[libcxx-commits] [libcxx] [libc++] Implement a type-safe iterator for optional (PR #154239)
William Tran-Viet via libcxx-commits
libcxx-commits at lists.llvm.org
Fri Jan 30 19:47:25 PST 2026
https://github.com/smallp-o-p updated https://github.com/llvm/llvm-project/pull/154239
>From 2e10700d902974a15a0ead90404b948cf803aefb Mon Sep 17 00:00:00 2001
From: William Tran-Viet <wtranviet at proton.me>
Date: Mon, 18 Aug 2025 20:09:40 -0400
Subject: [PATCH 01/28] Implement a type-safe iterator for optional
---
libcxx/include/CMakeLists.txt | 1 +
.../__iterator/upper_bounded_iterator.h | 174 ++++++++++++++++++
libcxx/include/module.modulemap.in | 1 +
libcxx/include/optional | 26 +--
.../iterator.compile.pass.cpp | 55 ++++++
5 files changed, 246 insertions(+), 11 deletions(-)
create mode 100644 libcxx/include/__iterator/upper_bounded_iterator.h
create mode 100644 libcxx/test/libcxx/utilities/optional/optional.iterator/iterator.compile.pass.cpp
diff --git a/libcxx/include/CMakeLists.txt b/libcxx/include/CMakeLists.txt
index f9ae22accd687..5d804cca49677 100644
--- a/libcxx/include/CMakeLists.txt
+++ b/libcxx/include/CMakeLists.txt
@@ -516,6 +516,7 @@ set(files
__iterator/sortable.h
__iterator/static_bounded_iter.h
__iterator/unreachable_sentinel.h
+ __iterator/upper_bounded_iterator.h
__iterator/wrap_iter.h
__locale
__locale_dir/check_grouping.h
diff --git a/libcxx/include/__iterator/upper_bounded_iterator.h b/libcxx/include/__iterator/upper_bounded_iterator.h
new file mode 100644
index 0000000000000..1ae0d11ce379f
--- /dev/null
+++ b/libcxx/include/__iterator/upper_bounded_iterator.h
@@ -0,0 +1,174 @@
+// -*- C++ -*-
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+/*
+ * __upper_bounded_iterator is an iterator that wraps an underlying iterator.
+ * It stores the underlying container type to prevent mixing iterators, and allow algorithms
+ * to optimize based on the underlying container type.
+ * It also stores the absolute maximum amount of elements the container can have, known at compile-time.
+ * As of writing, the only standard library containers which have this property are inplace_vector and optional.
+ */
+
+#ifndef _LIBCPP___ITERATOR_UPPER_BOUNDED_ITERATOR_H
+#define _LIBCPP___ITERATOR_UPPER_BOUNDED_ITERATOR_H
+
+#include <__compare/ordering.h>
+#include <__compare/three_way_comparable.h>
+#include <__config>
+#include <__cstddef/size_t.h>
+#include <__iterator/incrementable_traits.h>
+#include <__iterator/iterator_traits.h>
+#include <__memory/pointer_traits.h>
+#include <__type_traits/is_constructible.h>
+#include <__utility/move.h>
+
+#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
+# pragma GCC system_header
+#endif
+
+_LIBCPP_PUSH_MACROS
+#include <__undef_macros>
+
+#if _LIBCPP_STD_VER >= 26
+
+_LIBCPP_BEGIN_NAMESPACE_STD
+
+template <class _Iter, class _Container, std::size_t _Max_Elements>
+class __upper_bounded_iterator {
+private:
+ _Iter __iter_;
+
+ friend _Container;
+
+public:
+ using iterator_category = iterator_traits<_Iter>::iterator_category;
+ using iterator_concept = _Iter::iterator_concept;
+ using value_type = iter_value_t<_Iter>;
+ using difference_type = iter_difference_t<_Iter>;
+ using reference = iter_reference_t<_Iter>;
+
+ _LIBCPP_HIDE_FROM_ABI constexpr __upper_bounded_iterator()
+ requires is_default_constructible_v<_Iter>
+ = default;
+
+ _LIBCPP_HIDE_FROM_ABI constexpr explicit __upper_bounded_iterator(_Iter __iter) : __iter_(std::move(__iter)) {}
+
+ _LIBCPP_HIDE_FROM_ABI constexpr _Iter __base() const noexcept(noexcept(_Iter(__iter_))) { return __iter_; }
+ _LIBCPP_HIDE_FROM_ABI constexpr auto __max_elements() const noexcept { return _Max_Elements; }
+
+ _LIBCPP_HIDE_FROM_ABI constexpr decltype(auto) operator*() const { return *__iter_; }
+ _LIBCPP_HIDE_FROM_ABI constexpr decltype(auto) operator->() const
+ requires requires { __iter_.operator->(); }
+ {
+ return __iter_.operator->();
+ }
+
+ _LIBCPP_HIDE_FROM_ABI constexpr __upper_bounded_iterator& operator++() {
+ ++__iter_;
+ return *this;
+ }
+
+ _LIBCPP_HIDE_FROM_ABI constexpr __upper_bounded_iterator operator++(int) {
+ __upper_bounded_iterator __tmp(*this);
+ ++*this;
+ return __tmp;
+ }
+
+ _LIBCPP_HIDE_FROM_ABI constexpr __upper_bounded_iterator& operator--() {
+ --__iter_;
+ return *this;
+ }
+
+ _LIBCPP_HIDE_FROM_ABI constexpr __upper_bounded_iterator operator--(int) {
+ __upper_bounded_iterator __tmp(*this);
+ --*this;
+ return __tmp;
+ }
+
+ _LIBCPP_HIDE_FROM_ABI constexpr __upper_bounded_iterator& operator+=(difference_type __x) {
+ __iter_ += __x;
+ return *this;
+ }
+
+ _LIBCPP_HIDE_FROM_ABI constexpr __upper_bounded_iterator& operator-=(difference_type __x) {
+ __iter_ -= __x;
+ return *this;
+ }
+
+ _LIBCPP_HIDE_FROM_ABI constexpr decltype(auto) operator[](difference_type __n) const { return *(*this + __n); }
+
+ _LIBCPP_HIDE_FROM_ABI friend constexpr bool
+ operator==(const __upper_bounded_iterator& __x, const __upper_bounded_iterator& __y) {
+ return __x.__iter_ == __y.__iter_;
+ }
+
+ _LIBCPP_HIDE_FROM_ABI friend constexpr auto
+ operator<=>(const __upper_bounded_iterator& __x, const __upper_bounded_iterator& __y) {
+ if constexpr (three_way_comparable_with<_Iter, _Iter, strong_ordering>) {
+ return __x.__iter_ <=> __y.__iter_;
+ } else {
+ if (__x.__iter_ < __x.__iter_) {
+ return strong_ordering::less;
+ } else if (__x.__iter_ == __y.__iter_) {
+ return strong_ordering::equal;
+ }
+ return strong_ordering::greater;
+ }
+ }
+
+ template <class _Iter2>
+ _LIBCPP_HIDE_FROM_ABI friend constexpr auto
+ operator<=>(const __upper_bounded_iterator& __x,
+ const __upper_bounded_iterator<_Iter2, _Container, _Max_Elements> __y) {
+ if constexpr (three_way_comparable_with<_Iter, _Iter2, strong_ordering>) {
+ return __x.__iter_ <=> __y.__iter_;
+ } else {
+ if (__x.__iter_ < __x.__iter_) {
+ return strong_ordering::less;
+ } else if (__x.__iter_ == __y.__iter_) {
+ return strong_ordering::equal;
+ }
+ return strong_ordering::greater;
+ }
+ }
+
+ _LIBCPP_HIDE_FROM_ABI friend constexpr __upper_bounded_iterator
+ operator+(const __upper_bounded_iterator& __i, difference_type __n) {
+ auto __tmp = __i;
+ __tmp += __n;
+ return __tmp;
+ }
+
+ _LIBCPP_HIDE_FROM_ABI friend constexpr __upper_bounded_iterator
+ operator+(difference_type __n, const __upper_bounded_iterator& __i) {
+ auto __tmp = __i;
+ __tmp += __n;
+ return __tmp;
+ }
+
+ _LIBCPP_HIDE_FROM_ABI friend constexpr __upper_bounded_iterator
+ operator-(const __upper_bounded_iterator& __i, difference_type __n) {
+ return __i.__iter_ + __n;
+ }
+
+ template <class _Iter2>
+ _LIBCPP_HIDE_FROM_ABI friend constexpr difference_type
+ operator-(const __upper_bounded_iterator& __x,
+ const __upper_bounded_iterator<_Iter2, _Container, _Max_Elements>& __y) {
+ return difference_type(__x.__base() - __y.__base());
+ }
+};
+
+_LIBCPP_END_NAMESPACE_STD
+
+#endif // _LIBCPP_STD_VER >= 26
+
+_LIBCPP_POP_MACROS
+
+#endif // _LIBCPP___ITERATOR_UPPER_BOUNDED_ITERATOR_H
diff --git a/libcxx/include/module.modulemap.in b/libcxx/include/module.modulemap.in
index 27178aa1f4378..54d16ea9fef3f 100644
--- a/libcxx/include/module.modulemap.in
+++ b/libcxx/include/module.modulemap.in
@@ -1544,6 +1544,7 @@ module std [system] {
module sortable { header "__iterator/sortable.h" }
module static_bounded_iter { header "__iterator/static_bounded_iter.h" }
module unreachable_sentinel { header "__iterator/unreachable_sentinel.h" }
+ module upper_bounded_iterator { header "__iterator/upper_bounded_iterator.h" }
module wrap_iter { header "__iterator/wrap_iter.h" }
header "iterator"
diff --git a/libcxx/include/optional b/libcxx/include/optional
index cc6a30151c53a..8b170a8fe143a 100644
--- a/libcxx/include/optional
+++ b/libcxx/include/optional
@@ -264,7 +264,6 @@ namespace std {
# include <__compare/three_way_comparable.h>
# include <__concepts/invocable.h>
# include <__config>
-# include <__cstddef/ptrdiff_t.h>
# include <__exception/exception.h>
# include <__format/range_format.h>
# include <__functional/hash.h>
@@ -272,6 +271,7 @@ namespace std {
# include <__functional/unary_function.h>
# include <__fwd/functional.h>
# include <__iterator/bounded_iter.h>
+# include <__iterator/upper_bounded_iterator.h>
# include <__iterator/wrap_iter.h>
# include <__memory/addressof.h>
# include <__memory/construct_at.h>
@@ -717,13 +717,17 @@ private:
using __pointer _LIBCPP_NODEBUG = add_pointer_t<_Tp>;
using __const_pointer _LIBCPP_NODEBUG = add_pointer_t<const _Tp>;
+# if _LIBCPP_STD_VER >= 26
+ template <typename _Underlying>
+ using __iter _LIBCPP_NODEBUG = __upper_bounded_iterator<_Underlying, __optional_iterator, 1>;
+
public:
# ifdef _LIBCPP_ABI_BOUNDED_ITERATORS_IN_OPTIONAL
- using iterator = __bounded_iter<__wrap_iter<__pointer>>;
- using const_iterator = __bounded_iter<__wrap_iter<__const_pointer>>;
+ using iterator = __iter<__bounded_iter<__wrap_iter<__pointer>>>;
+ using const_iterator = __iter<__bounded_iter<__wrap_iter<__const_pointer>>>;
# else
- using iterator = __wrap_iter<__pointer>;
- using const_iterator = __wrap_iter<__const_pointer>;
+ using iterator = __iter<__wrap_iter<__pointer>>;
+ using const_iterator = __iter<__wrap_iter<__const_pointer>>;
# endif
// [optional.iterators], iterator support
@@ -732,12 +736,12 @@ public:
auto* __ptr = std::addressof(__derived_self.__get());
# ifdef _LIBCPP_ABI_BOUNDED_ITERATORS_IN_OPTIONAL
- return std::__make_bounded_iter(
+ return iterator(std::__make_bounded_iter(
__wrap_iter<__pointer>(__ptr),
__wrap_iter<__pointer>(__ptr),
- __wrap_iter<__pointer>(__ptr) + (__derived_self.has_value() ? 1 : 0));
+ __wrap_iter<__pointer>(__ptr) + (__derived_self.has_value() ? 1 : 0)));
# else
- return iterator(__ptr);
+ return iterator(__wrap_iter<__pointer>(__ptr));
# endif
}
@@ -746,12 +750,12 @@ public:
auto* __ptr = std::addressof(__derived_self.__get());
# ifdef _LIBCPP_ABI_BOUNDED_ITERATORS_IN_OPTIONAL
- return std::__make_bounded_iter(
+ return const_iterator(std::__make_bounded_iter(
__wrap_iter<__const_pointer>(__ptr),
__wrap_iter<__const_pointer>(__ptr),
- __wrap_iter<__const_pointer>(__ptr) + (__derived_self.has_value() ? 1 : 0));
+ __wrap_iter<__const_pointer>(__ptr) + (__derived_self.has_value() ? 1 : 0)));
# else
- return const_iterator(__ptr);
+ return const_iterator(__wrap_iter<__const_pointer>(__ptr));
# endif
}
diff --git a/libcxx/test/libcxx/utilities/optional/optional.iterator/iterator.compile.pass.cpp b/libcxx/test/libcxx/utilities/optional/optional.iterator/iterator.compile.pass.cpp
new file mode 100644
index 0000000000000..424367b4f10b2
--- /dev/null
+++ b/libcxx/test/libcxx/utilities/optional/optional.iterator/iterator.compile.pass.cpp
@@ -0,0 +1,55 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+// REQUIRES: std-at-least-c++26
+// UNSUPPORTED: generic-hardening
+// <optional>
+
+// template <class T> class optional::iterator;
+// template <class T> class optional::const_iterator;
+
+#include <optional>
+#include <type_traits>
+
+template <typename T>
+concept has_iterator_aliases = requires {
+ typename T::iterator;
+ typename T::const_iterator;
+};
+
+static_assert(has_iterator_aliases<std::optional<int>>);
+static_assert(has_iterator_aliases<std::optional<const int>>);
+static_assert(has_iterator_aliases<std::optional<int&>>);
+static_assert(has_iterator_aliases<std::optional<const int&>>);
+static_assert(!has_iterator_aliases<std::optional<int (&)[1]>>);
+static_assert(!has_iterator_aliases<std::optional<int (&)()>>);
+
+using Iter1 = std::optional<int>::iterator;
+using Iter2 = std::optional<double>::iterator;
+using Iter3 = std::optional<int>::const_iterator;
+using Iter4 = std::optional<double>::const_iterator;
+
+static_assert(std::is_convertible_v<Iter1, Iter1>);
+static_assert(!std::is_convertible_v<Iter1, Iter2>);
+static_assert(!std::is_convertible_v<Iter1, Iter3>);
+static_assert(!std::is_convertible_v<Iter1, Iter4>);
+
+static_assert(std::is_convertible_v<Iter2, Iter2>);
+static_assert(!std::is_convertible_v<Iter2, Iter1>);
+static_assert(!std::is_convertible_v<Iter2, Iter3>);
+static_assert(!std::is_convertible_v<Iter2, Iter4>);
+
+static_assert(std::is_convertible_v<Iter3, Iter3>);
+static_assert(!std::is_convertible_v<Iter3, Iter1>);
+static_assert(!std::is_convertible_v<Iter3, Iter2>);
+static_assert(!std::is_convertible_v<Iter3, Iter4>);
+
+static_assert(std::is_convertible_v<Iter4, Iter4>);
+static_assert(!std::is_convertible_v<Iter4, Iter1>);
+static_assert(!std::is_convertible_v<Iter4, Iter2>);
+static_assert(!std::is_convertible_v<Iter4, Iter3>);
>From a7aec364365de3309105a0dcac5756be4947f71a Mon Sep 17 00:00:00 2001
From: William Tran-Viet <wtranviet at proton.me>
Date: Mon, 18 Aug 2025 20:39:34 -0400
Subject: [PATCH 02/28] Update iterator tests
---
.../iterator.compile.pass.cpp | 2 +-
.../optional.iterator/iterator.pass.cpp | 24 +++++
.../iterator_compare.pass.cpp | 99 +++++++++++++++++++
3 files changed, 124 insertions(+), 1 deletion(-)
create mode 100644 libcxx/test/std/utilities/optional/optional.iterator/iterator_compare.pass.cpp
diff --git a/libcxx/test/libcxx/utilities/optional/optional.iterator/iterator.compile.pass.cpp b/libcxx/test/libcxx/utilities/optional/optional.iterator/iterator.compile.pass.cpp
index 424367b4f10b2..442195bdcb948 100644
--- a/libcxx/test/libcxx/utilities/optional/optional.iterator/iterator.compile.pass.cpp
+++ b/libcxx/test/libcxx/utilities/optional/optional.iterator/iterator.compile.pass.cpp
@@ -7,7 +7,7 @@
//===----------------------------------------------------------------------===//
// REQUIRES: std-at-least-c++26
-// UNSUPPORTED: generic-hardening
+
// <optional>
// template <class T> class optional::iterator;
diff --git a/libcxx/test/std/utilities/optional/optional.iterator/iterator.pass.cpp b/libcxx/test/std/utilities/optional/optional.iterator/iterator.pass.cpp
index 1581c640136c6..05b8b3572ef53 100644
--- a/libcxx/test/std/utilities/optional/optional.iterator/iterator.pass.cpp
+++ b/libcxx/test/std/utilities/optional/optional.iterator/iterator.pass.cpp
@@ -100,6 +100,30 @@ constexpr void test(std::decay_t<T> v) {
assert(val.begin() != val.end());
assert(*(val.begin()) == v);
}
+
+ // [container.reqmts] operator-
+ {
+ std::optional<T> val(v);
+ auto it1 = val.begin();
+ auto it2 = val.begin();
+ auto it3 = val.end();
+
+ auto cit1 = std::as_const(val).begin();
+ auto cit2 = std::as_const(val).begin();
+ auto cit3 = std::as_const(val).end();
+
+ assert(it1 - it2 == 0);
+ assert(cit1 - cit2 == 0);
+ assert(it1 - cit1 == 0);
+ assert(it3 - it1 == 1);
+ assert(it1 - it3 == -1);
+
+ assert(cit3 - cit1 == 1);
+ assert(cit1 - cit3 == -1);
+ assert(cit3 - cit3 == 0);
+ assert(cit3 - it1 == 1);
+ assert(it1 - cit3 == -1);
+ }
}
constexpr bool test() {
diff --git a/libcxx/test/std/utilities/optional/optional.iterator/iterator_compare.pass.cpp b/libcxx/test/std/utilities/optional/optional.iterator/iterator_compare.pass.cpp
new file mode 100644
index 0000000000000..16b74ade9d82e
--- /dev/null
+++ b/libcxx/test/std/utilities/optional/optional.iterator/iterator_compare.pass.cpp
@@ -0,0 +1,99 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+// REQUIRES: std-at-least-c++26
+
+// <optional>
+
+// template <class T> class optional::iterator;
+// template <class T> class optional::const_iterator;
+
+#include <cassert>
+#include <compare>
+#include <concepts>
+#include <optional>
+#include <type_traits>
+#include <utility>
+
+template<typename T>
+constexpr bool test() {
+ using Opt = std::optional<T>;
+ using I = Opt::iterator;
+ using CI = Opt::const_iterator;
+
+ static_assert(std::three_way_comparable<I>);
+ static_assert(std::three_way_comparable<CI>);
+
+ std::remove_reference_t<T> t{};
+ Opt opt{t};
+
+ // [container.reqmts] tests for comparison operators of optional::iterator and optional::const_iterator
+ auto it1 = opt.begin();
+
+ {
+ auto it2 = opt.begin();
+ assert(it1 == it2);
+ assert(!(it1 != it2));
+
+ static_assert(std::same_as<decltype(it1 <=> it2), std::strong_ordering>);
+ assert(it1 <=> it2 == std::strong_ordering::equal);
+ }
+
+ {
+ auto it3 = opt.end();
+ assert(it1 != it3);
+ assert(it1 <= it3);
+ assert(it1 < it3);
+ assert(it3 >= it1);
+ assert(it3 > it1);
+
+ assert(it1 <=> it3 == std::strong_ordering::less);
+ assert(it3 <=> it1 == std::strong_ordering::greater);
+ }
+
+ auto cit1 = std::as_const(opt).begin();
+
+ {
+ auto cit2 = std::as_const(opt).begin();
+ assert(cit1 == cit2);
+ assert(!(cit1 != cit2));
+
+ static_assert(std::same_as<decltype(cit1 <=> cit2), std::strong_ordering>);
+ assert(cit1 <=> cit2 == std::strong_ordering::equal);
+ }
+
+ {
+ auto cit3 = std::as_const(opt).end();
+
+ assert(cit1 <= cit3);
+ assert(cit1 < cit3);
+ assert(cit3 >= cit1);
+ assert(cit3 > cit1);
+
+ assert(cit1 <=> cit3 == std::strong_ordering::less);
+ assert(cit3 <=> cit1 == std::strong_ordering::greater);
+ }
+
+ return true;
+}
+
+
+constexpr bool test() {
+ test<int>();
+ test<char>();
+ test<int&>();
+
+ return true;
+}
+
+int main(int, char**) {
+ assert(test());
+ static_assert(test());
+
+ return 0;
+}
>From ec78b410332b5176a2419b5c3a6010e5246e5a35 Mon Sep 17 00:00:00 2001
From: William Tran-Viet <wtranviet at proton.me>
Date: Tue, 2 Dec 2025 21:30:14 -0500
Subject: [PATCH 03/28] Formatting
---
.../optional/optional.iterator/iterator_compare.pass.cpp | 7 +++----
1 file changed, 3 insertions(+), 4 deletions(-)
diff --git a/libcxx/test/std/utilities/optional/optional.iterator/iterator_compare.pass.cpp b/libcxx/test/std/utilities/optional/optional.iterator/iterator_compare.pass.cpp
index 16b74ade9d82e..958519d4c805c 100644
--- a/libcxx/test/std/utilities/optional/optional.iterator/iterator_compare.pass.cpp
+++ b/libcxx/test/std/utilities/optional/optional.iterator/iterator_compare.pass.cpp
@@ -20,11 +20,11 @@
#include <type_traits>
#include <utility>
-template<typename T>
+template <typename T>
constexpr bool test() {
using Opt = std::optional<T>;
- using I = Opt::iterator;
- using CI = Opt::const_iterator;
+ using I = Opt::iterator;
+ using CI = Opt::const_iterator;
static_assert(std::three_way_comparable<I>);
static_assert(std::three_way_comparable<CI>);
@@ -82,7 +82,6 @@ constexpr bool test() {
return true;
}
-
constexpr bool test() {
test<int>();
test<char>();
>From f5140f56c444d7ccb6348e19206ddcaf02afb808 Mon Sep 17 00:00:00 2001
From: William Tran-Viet <wtranviet at proton.me>
Date: Thu, 4 Dec 2025 14:30:42 -0500
Subject: [PATCH 04/28] Allow conversions from iterator -> const_iterator
---
libcxx/include/__iterator/upper_bounded_iterator.h | 9 ++++++++-
.../optional/optional.iterator/iterator.compile.pass.cpp | 4 ++--
2 files changed, 10 insertions(+), 3 deletions(-)
diff --git a/libcxx/include/__iterator/upper_bounded_iterator.h b/libcxx/include/__iterator/upper_bounded_iterator.h
index 1ae0d11ce379f..8aa2a0340f7bc 100644
--- a/libcxx/include/__iterator/upper_bounded_iterator.h
+++ b/libcxx/include/__iterator/upper_bounded_iterator.h
@@ -11,7 +11,7 @@
* __upper_bounded_iterator is an iterator that wraps an underlying iterator.
* It stores the underlying container type to prevent mixing iterators, and allow algorithms
* to optimize based on the underlying container type.
- * It also stores the absolute maximum amount of elements the container can have, known at compile-time.
+ * It also encodes the container's (known at compile-time) maximum amount of elements as part of the type.
* As of writing, the only standard library containers which have this property are inplace_vector and optional.
*/
@@ -26,6 +26,7 @@
#include <__iterator/iterator_traits.h>
#include <__memory/pointer_traits.h>
#include <__type_traits/is_constructible.h>
+#include <__type_traits/is_convertible.h>
#include <__utility/move.h>
#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
@@ -59,6 +60,12 @@ class __upper_bounded_iterator {
_LIBCPP_HIDE_FROM_ABI constexpr explicit __upper_bounded_iterator(_Iter __iter) : __iter_(std::move(__iter)) {}
+ template <typename _Iter2>
+ requires is_convertible_v<_Iter2, _Iter>
+ _LIBCPP_HIDE_FROM_ABI constexpr __upper_bounded_iterator(
+ const __upper_bounded_iterator<_Iter2, _Container, _Max_Elements>& __y)
+ : __iter_(__y.__iter_) {}
+
_LIBCPP_HIDE_FROM_ABI constexpr _Iter __base() const noexcept(noexcept(_Iter(__iter_))) { return __iter_; }
_LIBCPP_HIDE_FROM_ABI constexpr auto __max_elements() const noexcept { return _Max_Elements; }
diff --git a/libcxx/test/libcxx/utilities/optional/optional.iterator/iterator.compile.pass.cpp b/libcxx/test/libcxx/utilities/optional/optional.iterator/iterator.compile.pass.cpp
index 442195bdcb948..1d0009d3ed2d9 100644
--- a/libcxx/test/libcxx/utilities/optional/optional.iterator/iterator.compile.pass.cpp
+++ b/libcxx/test/libcxx/utilities/optional/optional.iterator/iterator.compile.pass.cpp
@@ -36,13 +36,13 @@ using Iter4 = std::optional<double>::const_iterator;
static_assert(std::is_convertible_v<Iter1, Iter1>);
static_assert(!std::is_convertible_v<Iter1, Iter2>);
-static_assert(!std::is_convertible_v<Iter1, Iter3>);
+static_assert(std::is_convertible_v<Iter1, Iter3>);
static_assert(!std::is_convertible_v<Iter1, Iter4>);
static_assert(std::is_convertible_v<Iter2, Iter2>);
static_assert(!std::is_convertible_v<Iter2, Iter1>);
static_assert(!std::is_convertible_v<Iter2, Iter3>);
-static_assert(!std::is_convertible_v<Iter2, Iter4>);
+static_assert(std::is_convertible_v<Iter2, Iter4>);
static_assert(std::is_convertible_v<Iter3, Iter3>);
static_assert(!std::is_convertible_v<Iter3, Iter1>);
>From 5c22231691b5e2a9f43ab0c2d2710993f9ca397e Mon Sep 17 00:00:00 2001
From: William Tran-Viet <wtranviet at proton.me>
Date: Fri, 5 Dec 2025 18:38:09 -0500
Subject: [PATCH 05/28] Address most comments, try new name
---
libcxx/include/CMakeLists.txt | 2 +-
.../__iterator/capacity_aware_iterator.h | 180 +++++++++++++++++
.../__iterator/upper_bounded_iterator.h | 181 ------------------
libcxx/include/module.modulemap.in | 2 +-
libcxx/include/optional | 4 +-
.../iterator.compile.pass.cpp | 19 +-
6 files changed, 199 insertions(+), 189 deletions(-)
create mode 100644 libcxx/include/__iterator/capacity_aware_iterator.h
delete mode 100644 libcxx/include/__iterator/upper_bounded_iterator.h
diff --git a/libcxx/include/CMakeLists.txt b/libcxx/include/CMakeLists.txt
index 5d804cca49677..04ca182007dc0 100644
--- a/libcxx/include/CMakeLists.txt
+++ b/libcxx/include/CMakeLists.txt
@@ -477,6 +477,7 @@ set(files
__iterator/aliasing_iterator.h
__iterator/back_insert_iterator.h
__iterator/bounded_iter.h
+ __iterator/capacity_aware_iterator.h
__iterator/common_iterator.h
__iterator/concepts.h
__iterator/counted_iterator.h
@@ -516,7 +517,6 @@ set(files
__iterator/sortable.h
__iterator/static_bounded_iter.h
__iterator/unreachable_sentinel.h
- __iterator/upper_bounded_iterator.h
__iterator/wrap_iter.h
__locale
__locale_dir/check_grouping.h
diff --git a/libcxx/include/__iterator/capacity_aware_iterator.h b/libcxx/include/__iterator/capacity_aware_iterator.h
new file mode 100644
index 0000000000000..f006e773a39d0
--- /dev/null
+++ b/libcxx/include/__iterator/capacity_aware_iterator.h
@@ -0,0 +1,180 @@
+// -*- C++ -*-
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef _LIBCPP___ITERATOR_UPPER_BOUNDED_ITERATOR_H
+#define _LIBCPP___ITERATOR_UPPER_BOUNDED_ITERATOR_H
+
+#include <__assert>
+#include <__compare/ordering.h>
+#include <__compare/three_way_comparable.h>
+#include <__config>
+#include <__cstddef/size_t.h>
+#include <__iterator/incrementable_traits.h>
+#include <__iterator/iterator_traits.h>
+#include <__memory/pointer_traits.h>
+#include <__type_traits/is_constructible.h>
+#include <__type_traits/is_convertible.h>
+#include <__utility/move.h>
+
+#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
+# pragma GCC system_header
+#endif
+
+_LIBCPP_PUSH_MACROS
+#include <__undef_macros>
+
+#if _LIBCPP_STD_VER >= 26
+
+_LIBCPP_BEGIN_NAMESPACE_STD
+
+// __capacity_aware_iterator is an iterator that wraps an underlying iterator.
+// It stores the underlying container type to prevent mixing iterators, and allow algorithms
+// to optimize based on the underlying container type.
+// It also encodes the container's (known at compile-time) maximum amount of elements as part of the type.
+// As of writing, the only standard library containers which have this property are inplace_vector and optional.
+
+template <class _Iter, class _Container, std::size_t _ContainerMaxElements>
+class __capacity_aware_iterator {
+private:
+ _Iter __iter_;
+
+ friend _Container;
+
+public:
+ using iterator_category = iterator_traits<_Iter>::iterator_category;
+ using iterator_concept = _Iter::iterator_concept;
+ using difference_type = iter_difference_t<_Iter>;
+ using pointer = iterator_traits<_Iter>::pointer;
+ using reference = iter_reference_t<_Iter>;
+ using value_type = iter_value_t<_Iter>;
+
+ _LIBCPP_HIDE_FROM_ABI constexpr __capacity_aware_iterator()
+ requires is_default_constructible_v<_Iter>
+ = default;
+
+ template <typename _Iter2>
+ requires is_convertible_v<_Iter2, _Iter>
+ _LIBCPP_HIDE_FROM_ABI constexpr __capacity_aware_iterator(
+ const __capacity_aware_iterator<_Iter2, _Container, _ContainerMaxElements>& __y)
+ : __iter_(__y.base()) {}
+
+private:
+ _LIBCPP_HIDE_FROM_ABI constexpr explicit __capacity_aware_iterator(_Iter __iter) : __iter_(std::move(__iter)) {}
+
+ template <typename _Tp, class>
+ friend struct __optional_iterator;
+
+public:
+ _LIBCPP_HIDE_FROM_ABI constexpr _Iter base() const noexcept { return __iter_; }
+ _LIBCPP_HIDE_FROM_ABI constexpr decltype(auto) operator*() const { return *__iter_; }
+ _LIBCPP_HIDE_FROM_ABI constexpr decltype(auto) operator->() const
+ requires requires { __iter_.operator->(); }
+ {
+ return __iter_.operator->();
+ }
+
+ _LIBCPP_HIDE_FROM_ABI constexpr __capacity_aware_iterator& operator++() {
+ ++__iter_;
+ return *this;
+ }
+
+ _LIBCPP_HIDE_FROM_ABI constexpr __capacity_aware_iterator operator++(int) {
+ __capacity_aware_iterator __tmp(*this);
+ ++*this;
+ return __tmp;
+ }
+
+ _LIBCPP_HIDE_FROM_ABI constexpr __capacity_aware_iterator& operator--() {
+ --__iter_;
+ return *this;
+ }
+
+ _LIBCPP_HIDE_FROM_ABI constexpr __capacity_aware_iterator operator--(int) {
+ __capacity_aware_iterator __tmp(*this);
+ --*this;
+ return __tmp;
+ }
+
+ _LIBCPP_HIDE_FROM_ABI constexpr __capacity_aware_iterator& operator+=(difference_type __n) {
+ _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(
+ (__n >= 0 ? __n : -__n) <= _ContainerMaxElements,
+ "__capacity_aware_iterator::operator+=: Attempting to move iterator past its "
+ "container's possible range");
+
+ __iter_ += __n;
+ return *this;
+ }
+
+ _LIBCPP_HIDE_FROM_ABI constexpr __capacity_aware_iterator& operator-=(difference_type __n) {
+ _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(
+ (__n >= 0 ? __n : -__n) <= _ContainerMaxElements,
+ "__capacity_aware_iterator::operator-=: Attempting to move iterator past its container's possible range");
+
+ __iter_ -= __n;
+ return *this;
+ }
+
+ _LIBCPP_HIDE_FROM_ABI constexpr decltype(auto) operator[](difference_type __n) const {
+ _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(
+ (__n >= 0 ? __n : -__n) < _ContainerMaxElements,
+ "__capacity_aware_iterator::operator[]: Attempting to index iterator past its container's possible range");
+ return *(*this + __n);
+ }
+
+ _LIBCPP_HIDE_FROM_ABI friend constexpr bool
+ operator==(const __capacity_aware_iterator& __x, const __capacity_aware_iterator& __y) {
+ return __x.__iter_ == __y.__iter_;
+ }
+
+ _LIBCPP_HIDE_FROM_ABI friend constexpr auto
+ operator<=>(const __capacity_aware_iterator& __x, const __capacity_aware_iterator& __y) {
+ if constexpr (three_way_comparable_with<_Iter, _Iter, strong_ordering>) {
+ return __x.__iter_ <=> __y.__iter_;
+ } else {
+ if (__x.__iter_ < __x.__iter_) {
+ return strong_ordering::less;
+ } else if (__x.__iter_ == __y.__iter_) {
+ return strong_ordering::equal;
+ }
+ return strong_ordering::greater;
+ }
+ }
+
+ _LIBCPP_HIDE_FROM_ABI friend constexpr __capacity_aware_iterator
+ operator+(const __capacity_aware_iterator& __i, difference_type __n) {
+ auto __tmp = __i;
+ __tmp += __n;
+ return __tmp;
+ }
+
+ _LIBCPP_HIDE_FROM_ABI friend constexpr __capacity_aware_iterator
+ operator+(difference_type __n, const __capacity_aware_iterator& __i) {
+ auto __tmp = __i;
+ __tmp += __n;
+ return __tmp;
+ }
+
+ _LIBCPP_HIDE_FROM_ABI friend constexpr __capacity_aware_iterator
+ operator-(const __capacity_aware_iterator& __i, difference_type __n) {
+ return __i.__iter_ + __n;
+ }
+
+ _LIBCPP_HIDE_FROM_ABI friend constexpr difference_type
+ operator-(const __capacity_aware_iterator& __x, const __capacity_aware_iterator& __y) {
+ return difference_type(__x.base() - __y.base());
+ }
+};
+
+_LIBCPP_END_NAMESPACE_STD
+
+#endif // _LIBCPP_STD_VER >= 26
+
+_LIBCPP_POP_MACROS
+
+#endif // _LIBCPP___ITERATOR_UPPER_BOUNDED_ITERATOR_H
diff --git a/libcxx/include/__iterator/upper_bounded_iterator.h b/libcxx/include/__iterator/upper_bounded_iterator.h
deleted file mode 100644
index 8aa2a0340f7bc..0000000000000
--- a/libcxx/include/__iterator/upper_bounded_iterator.h
+++ /dev/null
@@ -1,181 +0,0 @@
-// -*- C++ -*-
-//===----------------------------------------------------------------------===//
-//
-// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
-// See https://llvm.org/LICENSE.txt for license information.
-// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
-//
-//===----------------------------------------------------------------------===//
-
-/*
- * __upper_bounded_iterator is an iterator that wraps an underlying iterator.
- * It stores the underlying container type to prevent mixing iterators, and allow algorithms
- * to optimize based on the underlying container type.
- * It also encodes the container's (known at compile-time) maximum amount of elements as part of the type.
- * As of writing, the only standard library containers which have this property are inplace_vector and optional.
- */
-
-#ifndef _LIBCPP___ITERATOR_UPPER_BOUNDED_ITERATOR_H
-#define _LIBCPP___ITERATOR_UPPER_BOUNDED_ITERATOR_H
-
-#include <__compare/ordering.h>
-#include <__compare/three_way_comparable.h>
-#include <__config>
-#include <__cstddef/size_t.h>
-#include <__iterator/incrementable_traits.h>
-#include <__iterator/iterator_traits.h>
-#include <__memory/pointer_traits.h>
-#include <__type_traits/is_constructible.h>
-#include <__type_traits/is_convertible.h>
-#include <__utility/move.h>
-
-#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
-# pragma GCC system_header
-#endif
-
-_LIBCPP_PUSH_MACROS
-#include <__undef_macros>
-
-#if _LIBCPP_STD_VER >= 26
-
-_LIBCPP_BEGIN_NAMESPACE_STD
-
-template <class _Iter, class _Container, std::size_t _Max_Elements>
-class __upper_bounded_iterator {
-private:
- _Iter __iter_;
-
- friend _Container;
-
-public:
- using iterator_category = iterator_traits<_Iter>::iterator_category;
- using iterator_concept = _Iter::iterator_concept;
- using value_type = iter_value_t<_Iter>;
- using difference_type = iter_difference_t<_Iter>;
- using reference = iter_reference_t<_Iter>;
-
- _LIBCPP_HIDE_FROM_ABI constexpr __upper_bounded_iterator()
- requires is_default_constructible_v<_Iter>
- = default;
-
- _LIBCPP_HIDE_FROM_ABI constexpr explicit __upper_bounded_iterator(_Iter __iter) : __iter_(std::move(__iter)) {}
-
- template <typename _Iter2>
- requires is_convertible_v<_Iter2, _Iter>
- _LIBCPP_HIDE_FROM_ABI constexpr __upper_bounded_iterator(
- const __upper_bounded_iterator<_Iter2, _Container, _Max_Elements>& __y)
- : __iter_(__y.__iter_) {}
-
- _LIBCPP_HIDE_FROM_ABI constexpr _Iter __base() const noexcept(noexcept(_Iter(__iter_))) { return __iter_; }
- _LIBCPP_HIDE_FROM_ABI constexpr auto __max_elements() const noexcept { return _Max_Elements; }
-
- _LIBCPP_HIDE_FROM_ABI constexpr decltype(auto) operator*() const { return *__iter_; }
- _LIBCPP_HIDE_FROM_ABI constexpr decltype(auto) operator->() const
- requires requires { __iter_.operator->(); }
- {
- return __iter_.operator->();
- }
-
- _LIBCPP_HIDE_FROM_ABI constexpr __upper_bounded_iterator& operator++() {
- ++__iter_;
- return *this;
- }
-
- _LIBCPP_HIDE_FROM_ABI constexpr __upper_bounded_iterator operator++(int) {
- __upper_bounded_iterator __tmp(*this);
- ++*this;
- return __tmp;
- }
-
- _LIBCPP_HIDE_FROM_ABI constexpr __upper_bounded_iterator& operator--() {
- --__iter_;
- return *this;
- }
-
- _LIBCPP_HIDE_FROM_ABI constexpr __upper_bounded_iterator operator--(int) {
- __upper_bounded_iterator __tmp(*this);
- --*this;
- return __tmp;
- }
-
- _LIBCPP_HIDE_FROM_ABI constexpr __upper_bounded_iterator& operator+=(difference_type __x) {
- __iter_ += __x;
- return *this;
- }
-
- _LIBCPP_HIDE_FROM_ABI constexpr __upper_bounded_iterator& operator-=(difference_type __x) {
- __iter_ -= __x;
- return *this;
- }
-
- _LIBCPP_HIDE_FROM_ABI constexpr decltype(auto) operator[](difference_type __n) const { return *(*this + __n); }
-
- _LIBCPP_HIDE_FROM_ABI friend constexpr bool
- operator==(const __upper_bounded_iterator& __x, const __upper_bounded_iterator& __y) {
- return __x.__iter_ == __y.__iter_;
- }
-
- _LIBCPP_HIDE_FROM_ABI friend constexpr auto
- operator<=>(const __upper_bounded_iterator& __x, const __upper_bounded_iterator& __y) {
- if constexpr (three_way_comparable_with<_Iter, _Iter, strong_ordering>) {
- return __x.__iter_ <=> __y.__iter_;
- } else {
- if (__x.__iter_ < __x.__iter_) {
- return strong_ordering::less;
- } else if (__x.__iter_ == __y.__iter_) {
- return strong_ordering::equal;
- }
- return strong_ordering::greater;
- }
- }
-
- template <class _Iter2>
- _LIBCPP_HIDE_FROM_ABI friend constexpr auto
- operator<=>(const __upper_bounded_iterator& __x,
- const __upper_bounded_iterator<_Iter2, _Container, _Max_Elements> __y) {
- if constexpr (three_way_comparable_with<_Iter, _Iter2, strong_ordering>) {
- return __x.__iter_ <=> __y.__iter_;
- } else {
- if (__x.__iter_ < __x.__iter_) {
- return strong_ordering::less;
- } else if (__x.__iter_ == __y.__iter_) {
- return strong_ordering::equal;
- }
- return strong_ordering::greater;
- }
- }
-
- _LIBCPP_HIDE_FROM_ABI friend constexpr __upper_bounded_iterator
- operator+(const __upper_bounded_iterator& __i, difference_type __n) {
- auto __tmp = __i;
- __tmp += __n;
- return __tmp;
- }
-
- _LIBCPP_HIDE_FROM_ABI friend constexpr __upper_bounded_iterator
- operator+(difference_type __n, const __upper_bounded_iterator& __i) {
- auto __tmp = __i;
- __tmp += __n;
- return __tmp;
- }
-
- _LIBCPP_HIDE_FROM_ABI friend constexpr __upper_bounded_iterator
- operator-(const __upper_bounded_iterator& __i, difference_type __n) {
- return __i.__iter_ + __n;
- }
-
- template <class _Iter2>
- _LIBCPP_HIDE_FROM_ABI friend constexpr difference_type
- operator-(const __upper_bounded_iterator& __x,
- const __upper_bounded_iterator<_Iter2, _Container, _Max_Elements>& __y) {
- return difference_type(__x.__base() - __y.__base());
- }
-};
-
-_LIBCPP_END_NAMESPACE_STD
-
-#endif // _LIBCPP_STD_VER >= 26
-
-_LIBCPP_POP_MACROS
-
-#endif // _LIBCPP___ITERATOR_UPPER_BOUNDED_ITERATOR_H
diff --git a/libcxx/include/module.modulemap.in b/libcxx/include/module.modulemap.in
index 54d16ea9fef3f..92df7c6a85e6c 100644
--- a/libcxx/include/module.modulemap.in
+++ b/libcxx/include/module.modulemap.in
@@ -1544,7 +1544,7 @@ module std [system] {
module sortable { header "__iterator/sortable.h" }
module static_bounded_iter { header "__iterator/static_bounded_iter.h" }
module unreachable_sentinel { header "__iterator/unreachable_sentinel.h" }
- module upper_bounded_iterator { header "__iterator/upper_bounded_iterator.h" }
+ module capacity_aware_iterator { header "__iterator/capacity_aware_iterator.h" }
module wrap_iter { header "__iterator/wrap_iter.h" }
header "iterator"
diff --git a/libcxx/include/optional b/libcxx/include/optional
index 8b170a8fe143a..325b4f5a30bfd 100644
--- a/libcxx/include/optional
+++ b/libcxx/include/optional
@@ -271,7 +271,7 @@ namespace std {
# include <__functional/unary_function.h>
# include <__fwd/functional.h>
# include <__iterator/bounded_iter.h>
-# include <__iterator/upper_bounded_iterator.h>
+# include <__iterator/capacity_aware_iterator.h>
# include <__iterator/wrap_iter.h>
# include <__memory/addressof.h>
# include <__memory/construct_at.h>
@@ -719,7 +719,7 @@ private:
# if _LIBCPP_STD_VER >= 26
template <typename _Underlying>
- using __iter _LIBCPP_NODEBUG = __upper_bounded_iterator<_Underlying, __optional_iterator, 1>;
+ using __iter _LIBCPP_NODEBUG = __capacity_aware_iterator<_Underlying, optional<_Tp>, 1>;
public:
# ifdef _LIBCPP_ABI_BOUNDED_ITERATORS_IN_OPTIONAL
diff --git a/libcxx/test/libcxx/utilities/optional/optional.iterator/iterator.compile.pass.cpp b/libcxx/test/libcxx/utilities/optional/optional.iterator/iterator.compile.pass.cpp
index 1d0009d3ed2d9..7db0c9ec32e87 100644
--- a/libcxx/test/libcxx/utilities/optional/optional.iterator/iterator.compile.pass.cpp
+++ b/libcxx/test/libcxx/utilities/optional/optional.iterator/iterator.compile.pass.cpp
@@ -15,6 +15,7 @@
#include <optional>
#include <type_traits>
+#include <vector>
template <typename T>
concept has_iterator_aliases = requires {
@@ -29,27 +30,37 @@ static_assert(has_iterator_aliases<std::optional<const int&>>);
static_assert(!has_iterator_aliases<std::optional<int (&)[1]>>);
static_assert(!has_iterator_aliases<std::optional<int (&)()>>);
-using Iter1 = std::optional<int>::iterator;
-using Iter2 = std::optional<double>::iterator;
-using Iter3 = std::optional<int>::const_iterator;
-using Iter4 = std::optional<double>::const_iterator;
+using Iter1 = std::optional<int>::iterator;
+using Iter2 = std::optional<double>::iterator;
+using Iter3 = std::optional<int>::const_iterator;
+using Iter4 = std::optional<double>::const_iterator;
+using VIter1 = std::vector<int>::iterator;
+using VIter2 = std::vector<int>::const_iterator;
static_assert(std::is_convertible_v<Iter1, Iter1>);
static_assert(!std::is_convertible_v<Iter1, Iter2>);
static_assert(std::is_convertible_v<Iter1, Iter3>);
static_assert(!std::is_convertible_v<Iter1, Iter4>);
+static_assert(!std::is_convertible_v<Iter1, VIter1>);
+static_assert(!std::is_convertible_v<Iter1, VIter2>);
static_assert(std::is_convertible_v<Iter2, Iter2>);
static_assert(!std::is_convertible_v<Iter2, Iter1>);
static_assert(!std::is_convertible_v<Iter2, Iter3>);
static_assert(std::is_convertible_v<Iter2, Iter4>);
+static_assert(!std::is_convertible_v<Iter2, VIter1>);
+static_assert(!std::is_convertible_v<Iter2, VIter2>);
static_assert(std::is_convertible_v<Iter3, Iter3>);
static_assert(!std::is_convertible_v<Iter3, Iter1>);
static_assert(!std::is_convertible_v<Iter3, Iter2>);
static_assert(!std::is_convertible_v<Iter3, Iter4>);
+static_assert(!std::is_convertible_v<Iter3, VIter1>);
+static_assert(!std::is_convertible_v<Iter3, VIter2>);
static_assert(std::is_convertible_v<Iter4, Iter4>);
static_assert(!std::is_convertible_v<Iter4, Iter1>);
static_assert(!std::is_convertible_v<Iter4, Iter2>);
static_assert(!std::is_convertible_v<Iter4, Iter3>);
+static_assert(!std::is_convertible_v<Iter4, VIter1>);
+static_assert(!std::is_convertible_v<Iter4, VIter2>);
>From 31bb36a9ee1c1b1afa211e551c7f497099c2793c Mon Sep 17 00:00:00 2001
From: William Tran-Viet <wtranviet at proton.me>
Date: Fri, 5 Dec 2025 20:20:22 -0500
Subject: [PATCH 06/28] Don't wrap bounded_iter because there would a second
redundant bounds check
---
libcxx/include/optional | 12 ++++++------
1 file changed, 6 insertions(+), 6 deletions(-)
diff --git a/libcxx/include/optional b/libcxx/include/optional
index 325b4f5a30bfd..b928b1ac1c5a4 100644
--- a/libcxx/include/optional
+++ b/libcxx/include/optional
@@ -723,8 +723,8 @@ private:
public:
# ifdef _LIBCPP_ABI_BOUNDED_ITERATORS_IN_OPTIONAL
- using iterator = __iter<__bounded_iter<__wrap_iter<__pointer>>>;
- using const_iterator = __iter<__bounded_iter<__wrap_iter<__const_pointer>>>;
+ using iterator = __bounded_iter<__wrap_iter<__pointer>>;
+ using const_iterator = __bounded_iter<__wrap_iter<__const_pointer>>;
# else
using iterator = __iter<__wrap_iter<__pointer>>;
using const_iterator = __iter<__wrap_iter<__const_pointer>>;
@@ -736,10 +736,10 @@ public:
auto* __ptr = std::addressof(__derived_self.__get());
# ifdef _LIBCPP_ABI_BOUNDED_ITERATORS_IN_OPTIONAL
- return iterator(std::__make_bounded_iter(
+ return std::__make_bounded_iter(
__wrap_iter<__pointer>(__ptr),
__wrap_iter<__pointer>(__ptr),
- __wrap_iter<__pointer>(__ptr) + (__derived_self.has_value() ? 1 : 0)));
+ __wrap_iter<__pointer>(__ptr) + (__derived_self.has_value() ? 1 : 0));
# else
return iterator(__wrap_iter<__pointer>(__ptr));
# endif
@@ -750,10 +750,10 @@ public:
auto* __ptr = std::addressof(__derived_self.__get());
# ifdef _LIBCPP_ABI_BOUNDED_ITERATORS_IN_OPTIONAL
- return const_iterator(std::__make_bounded_iter(
+ return std::__make_bounded_iter(
__wrap_iter<__const_pointer>(__ptr),
__wrap_iter<__const_pointer>(__ptr),
- __wrap_iter<__const_pointer>(__ptr) + (__derived_self.has_value() ? 1 : 0)));
+ __wrap_iter<__const_pointer>(__ptr) + (__derived_self.has_value() ? 1 : 0));
# else
return const_iterator(__wrap_iter<__const_pointer>(__ptr));
# endif
>From 978b0634e2f2ad28279fb4f8e724c7f86c44a2eb Mon Sep 17 00:00:00 2001
From: William Tran-Viet <wtranviet at proton.me>
Date: Fri, 5 Dec 2025 20:18:38 -0500
Subject: [PATCH 07/28] Add iterator fail test
---
.../assert.arithmetic.pass.cpp | 46 +++++++++++++++++++
.../iterator.compile.pass.cpp | 2 +
.../iterator_compare.pass.cpp | 4 +-
.../libcxx/test/features/libcxx_macros.py | 1 +
4 files changed, 51 insertions(+), 2 deletions(-)
create mode 100644 libcxx/test/libcxx/utilities/optional/optional.iterator/assert.arithmetic.pass.cpp
diff --git a/libcxx/test/libcxx/utilities/optional/optional.iterator/assert.arithmetic.pass.cpp b/libcxx/test/libcxx/utilities/optional/optional.iterator/assert.arithmetic.pass.cpp
new file mode 100644
index 0000000000000..f66a3f5214343
--- /dev/null
+++ b/libcxx/test/libcxx/utilities/optional/optional.iterator/assert.arithmetic.pass.cpp
@@ -0,0 +1,46 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+// <optional>
+
+// Add to iterator out of bounds.
+
+// REQUIRES: std-at-least-c++26
+// UNSUPPORTED: libcpp-hardening-mode=none, libcpp-has-abi-bounded-iterators-in-optional
+
+#include <optional>
+
+#include "check_assertion.h"
+
+int main(int, char**) {
+ {
+ std::optional<int> opt(1);
+ auto i = opt.begin();
+
+ TEST_LIBCPP_ASSERT_FAILURE(
+ i += 2,
+ "__capacity_aware_iterator::operator+=: Attempting to advance iterator past its container's possible range");
+
+ TEST_LIBCPP_ASSERT_FAILURE(
+ i += -2, "__capacity_aware_iterator::operator+=: Attempting to rewind iterator past its container's start");
+
+ TEST_LIBCPP_ASSERT_FAILURE(
+ i -= 2, "__capacity_aware_iterator::operator-=: Attempting to rewind iterator before its container's start");
+
+ TEST_LIBCPP_ASSERT_FAILURE(
+ i -= -2,
+ "__capacity_aware_iterator::operator+=: Attempting to advance iterator past its container's possible range");
+
+ TEST_LIBCPP_ASSERT_FAILURE(
+ i[2],
+ "__capacity_aware_iterator::operator[]: Attempting to index iterator past its container's possible range");
+
+ TEST_LIBCPP_ASSERT_FAILURE(
+ i[-2], "__capacity_aware_iterator::operator[]: Attempting to index iterator before its container's start");
+ }
+}
diff --git a/libcxx/test/libcxx/utilities/optional/optional.iterator/iterator.compile.pass.cpp b/libcxx/test/libcxx/utilities/optional/optional.iterator/iterator.compile.pass.cpp
index 7db0c9ec32e87..ea99978f72e7c 100644
--- a/libcxx/test/libcxx/utilities/optional/optional.iterator/iterator.compile.pass.cpp
+++ b/libcxx/test/libcxx/utilities/optional/optional.iterator/iterator.compile.pass.cpp
@@ -10,6 +10,8 @@
// <optional>
+// UNSUPPORTED: libcpp-has-abi-bounded-iterators-in-optional
+
// template <class T> class optional::iterator;
// template <class T> class optional::const_iterator;
diff --git a/libcxx/test/std/utilities/optional/optional.iterator/iterator_compare.pass.cpp b/libcxx/test/std/utilities/optional/optional.iterator/iterator_compare.pass.cpp
index 958519d4c805c..d24300931d566 100644
--- a/libcxx/test/std/utilities/optional/optional.iterator/iterator_compare.pass.cpp
+++ b/libcxx/test/std/utilities/optional/optional.iterator/iterator_compare.pass.cpp
@@ -10,8 +10,8 @@
// <optional>
-// template <class T> class optional::iterator;
-// template <class T> class optional::const_iterator;
+// template <class T> class optional::iterator::operator<=>;
+// template <class T> class optional::const_iterator::operator<=>;
#include <cassert>
#include <compare>
diff --git a/libcxx/utils/libcxx/test/features/libcxx_macros.py b/libcxx/utils/libcxx/test/features/libcxx_macros.py
index 7a465f2e87866..71297e6a8880c 100644
--- a/libcxx/utils/libcxx/test/features/libcxx_macros.py
+++ b/libcxx/utils/libcxx/test/features/libcxx_macros.py
@@ -25,6 +25,7 @@
"_LIBCPP_ABI_VERSION": "libcpp-abi-version",
"_LIBCPP_ABI_BOUNDED_ITERATORS": "libcpp-has-abi-bounded-iterators",
"_LIBCPP_ABI_BOUNDED_ITERATORS_IN_STRING": "libcpp-has-abi-bounded-iterators-in-string",
+ "_LIBCPP_ABI_BOUNDED_ITERATORS_IN_OPTIONAL": "libcpp-has-abi-bounded-iterators-in-optional",
"_LIBCPP_ABI_BOUNDED_ITERATORS_IN_VECTOR": "libcpp-has-abi-bounded-iterators-in-vector",
"_LIBCPP_ABI_BOUNDED_ITERATORS_IN_STD_ARRAY": "libcpp-has-abi-bounded-iterators-in-std-array",
"_LIBCPP_ABI_BOUNDED_UNIQUE_PTR": "libcpp-has-abi-bounded-unique_ptr",
>From 087562d45aebf8381eca77bedf5e3461a402b501 Mon Sep 17 00:00:00 2001
From: William Tran-Viet <wtranviet at proton.me>
Date: Sat, 6 Dec 2025 00:44:58 -0500
Subject: [PATCH 08/28] Resolve signedness issue
---
libcxx/include/__iterator/capacity_aware_iterator.h | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/libcxx/include/__iterator/capacity_aware_iterator.h b/libcxx/include/__iterator/capacity_aware_iterator.h
index f006e773a39d0..797172337b26b 100644
--- a/libcxx/include/__iterator/capacity_aware_iterator.h
+++ b/libcxx/include/__iterator/capacity_aware_iterator.h
@@ -103,7 +103,7 @@ class __capacity_aware_iterator {
_LIBCPP_HIDE_FROM_ABI constexpr __capacity_aware_iterator& operator+=(difference_type __n) {
_LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(
- (__n >= 0 ? __n : -__n) <= _ContainerMaxElements,
+ static_cast<size_t>((__n >= 0 ? __n : -__n)) <= _ContainerMaxElements,
"__capacity_aware_iterator::operator+=: Attempting to move iterator past its "
"container's possible range");
@@ -113,7 +113,7 @@ class __capacity_aware_iterator {
_LIBCPP_HIDE_FROM_ABI constexpr __capacity_aware_iterator& operator-=(difference_type __n) {
_LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(
- (__n >= 0 ? __n : -__n) <= _ContainerMaxElements,
+ static_cast<size_t>((__n >= 0 ? __n : -__n)) <= _ContainerMaxElements,
"__capacity_aware_iterator::operator-=: Attempting to move iterator past its container's possible range");
__iter_ -= __n;
>From bd8e68b7c4f9efce4676662e261c580a215eba10 Mon Sep 17 00:00:00 2001
From: William Tran-Viet <wtranviet at proton.me>
Date: Sat, 6 Dec 2025 00:45:32 -0500
Subject: [PATCH 09/28] Rename iterator_compare.pass.cpp
---
.../{iterator_compare.pass.cpp => compare.pass.cpp} | 0
1 file changed, 0 insertions(+), 0 deletions(-)
rename libcxx/test/std/utilities/optional/optional.iterator/{iterator_compare.pass.cpp => compare.pass.cpp} (100%)
diff --git a/libcxx/test/std/utilities/optional/optional.iterator/iterator_compare.pass.cpp b/libcxx/test/std/utilities/optional/optional.iterator/compare.pass.cpp
similarity index 100%
rename from libcxx/test/std/utilities/optional/optional.iterator/iterator_compare.pass.cpp
rename to libcxx/test/std/utilities/optional/optional.iterator/compare.pass.cpp
>From 3eab1e946c1cef952cca662029841d9d98042fb9 Mon Sep 17 00:00:00 2001
From: William Tran-Viet <wtranviet at proton.me>
Date: Sat, 6 Dec 2025 14:36:15 -0500
Subject: [PATCH 10/28] Signed issue x2
---
libcxx/include/__iterator/capacity_aware_iterator.h | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/libcxx/include/__iterator/capacity_aware_iterator.h b/libcxx/include/__iterator/capacity_aware_iterator.h
index 797172337b26b..fb05892b8a1b7 100644
--- a/libcxx/include/__iterator/capacity_aware_iterator.h
+++ b/libcxx/include/__iterator/capacity_aware_iterator.h
@@ -122,7 +122,7 @@ class __capacity_aware_iterator {
_LIBCPP_HIDE_FROM_ABI constexpr decltype(auto) operator[](difference_type __n) const {
_LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(
- (__n >= 0 ? __n : -__n) < _ContainerMaxElements,
+ static_cast<size_t>(__n >= 0 ? __n : -__n) < _ContainerMaxElements,
"__capacity_aware_iterator::operator[]: Attempting to index iterator past its container's possible range");
return *(*this + __n);
}
>From 1f3bc1644164e7e8c1d91d2e36edce108afc1efe Mon Sep 17 00:00:00 2001
From: William Tran-Viet <wtranviet at proton.me>
Date: Mon, 8 Dec 2025 19:40:49 -0500
Subject: [PATCH 11/28] Deduce iterator concept, add create method
---
.../__iterator/capacity_aware_iterator.h | 28 +++++++++++++++++--
1 file changed, 25 insertions(+), 3 deletions(-)
diff --git a/libcxx/include/__iterator/capacity_aware_iterator.h b/libcxx/include/__iterator/capacity_aware_iterator.h
index fb05892b8a1b7..73f095e87d339 100644
--- a/libcxx/include/__iterator/capacity_aware_iterator.h
+++ b/libcxx/include/__iterator/capacity_aware_iterator.h
@@ -15,6 +15,7 @@
#include <__compare/three_way_comparable.h>
#include <__config>
#include <__cstddef/size_t.h>
+#include <__iterator/concepts.h>
#include <__iterator/incrementable_traits.h>
#include <__iterator/iterator_traits.h>
#include <__memory/pointer_traits.h>
@@ -46,9 +47,23 @@ class __capacity_aware_iterator {
friend _Container;
+ _LIBCPP_HIDE_FROM_ABI static constexpr auto __get_iter_concept() {
+ if constexpr (contiguous_iterator<_Iter>) {
+ return contiguous_iterator_tag{};
+ } else if constexpr (random_access_iterator<_Iter>) {
+ return random_access_iterator_tag{};
+ } else if constexpr (bidirectional_iterator<_Iter>) {
+ return bidirectional_iterator_tag{};
+ } else if constexpr (forward_iterator<_Iter>) {
+ return forward_iterator_tag{};
+ } else {
+ return input_iterator_tag{};
+ }
+ }
+
public:
using iterator_category = iterator_traits<_Iter>::iterator_category;
- using iterator_concept = _Iter::iterator_concept;
+ using iterator_concept = decltype(__get_iter_concept());
using difference_type = iter_difference_t<_Iter>;
using pointer = iterator_traits<_Iter>::pointer;
using reference = iter_reference_t<_Iter>;
@@ -70,6 +85,9 @@ class __capacity_aware_iterator {
template <typename _Tp, class>
friend struct __optional_iterator;
+ template <class _It, class _C, size_t _M>
+ friend auto __make_capacity_aware_iterator(_It __iter);
+
public:
_LIBCPP_HIDE_FROM_ABI constexpr _Iter base() const noexcept { return __iter_; }
_LIBCPP_HIDE_FROM_ABI constexpr decltype(auto) operator*() const { return *__iter_; }
@@ -104,8 +122,7 @@ class __capacity_aware_iterator {
_LIBCPP_HIDE_FROM_ABI constexpr __capacity_aware_iterator& operator+=(difference_type __n) {
_LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(
static_cast<size_t>((__n >= 0 ? __n : -__n)) <= _ContainerMaxElements,
- "__capacity_aware_iterator::operator+=: Attempting to move iterator past its "
- "container's possible range");
+ "__capacity_aware_iterator::operator+=: Attempting to move iterator past its container's possible range");
__iter_ += __n;
return *this;
@@ -171,6 +188,11 @@ class __capacity_aware_iterator {
}
};
+template <class _It, class _C, size_t _M>
+auto __make_capacity_aware_iterator(_It __iter) {
+ return __capacity_aware_iterator<_It, _C, _M>(__iter);
+}
+
_LIBCPP_END_NAMESPACE_STD
#endif // _LIBCPP_STD_VER >= 26
>From 8a683e36eaf1e7580162d3f71ed97948d0a581bf Mon Sep 17 00:00:00 2001
From: William Tran-Viet <wtranviet at proton.me>
Date: Mon, 8 Dec 2025 19:41:11 -0500
Subject: [PATCH 12/28] Add tests
---
.../capacity_aware_iter/arithmetic.pass.cpp | 132 ++++++++++++++++++
.../capacity_aware_iter/assert.pass.cpp | 63 +++++++++
.../capacity_aware_iter/comparison.pass.cpp | 91 ++++++++++++
.../capacity_aware_iter/dereference.pass.cpp | 62 ++++++++
.../types.compile.pass.cpp | 30 ++++
.../assert.arithmetic.pass.cpp | 13 +-
6 files changed, 386 insertions(+), 5 deletions(-)
create mode 100644 libcxx/test/libcxx/iterators/capacity_aware_iter/arithmetic.pass.cpp
create mode 100644 libcxx/test/libcxx/iterators/capacity_aware_iter/assert.pass.cpp
create mode 100644 libcxx/test/libcxx/iterators/capacity_aware_iter/comparison.pass.cpp
create mode 100644 libcxx/test/libcxx/iterators/capacity_aware_iter/dereference.pass.cpp
create mode 100644 libcxx/test/libcxx/iterators/capacity_aware_iter/types.compile.pass.cpp
diff --git a/libcxx/test/libcxx/iterators/capacity_aware_iter/arithmetic.pass.cpp b/libcxx/test/libcxx/iterators/capacity_aware_iter/arithmetic.pass.cpp
new file mode 100644
index 0000000000000..16e7ea7a6369c
--- /dev/null
+++ b/libcxx/test/libcxx/iterators/capacity_aware_iter/arithmetic.pass.cpp
@@ -0,0 +1,132 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+// REQUIRES: std-at-least-c++26
+
+// template <class _Iterator, class _Container, class _ContainerMaxElements>
+// struct __capacity_aware_iterator;
+
+// Arithmetic operators
+
+#include <__iterator/capacity_aware_iterator.h>
+#include <cstddef>
+#include <iterator>
+
+#include "test_iterators.h"
+
+template <typename Iter>
+constexpr bool test() {
+ int arr[] = {1, 2, 3, 4, 5, 6};
+ constexpr size_t sz = std::size(arr);
+
+ using CapIter = std::__capacity_aware_iterator<Iter, decltype(arr), sz>;
+
+ int* i = arr + 0;
+
+ // operator++()
+ {
+ CapIter iter = std::__make_capacity_aware_iterator<Iter, decltype(arr), sz>(Iter(i));
+ CapIter& res = ++iter;
+
+ assert(&res == &iter);
+ assert(*iter == 2);
+ }
+
+ // operator++(int)
+ {
+ CapIter iter = std::__make_capacity_aware_iterator<Iter, decltype(arr), sz>(Iter(i));
+ CapIter res = iter++;
+
+ assert(*res == 1);
+ assert(*iter == 2);
+ }
+
+ // operator--()
+ {
+ CapIter iter = std::__make_capacity_aware_iterator<Iter, decltype(arr), sz>(Iter(i + 1));
+ CapIter& res = --iter;
+
+ assert(&iter == &res);
+ assert(*iter == 1);
+ }
+
+ // operator--(int)
+ {
+ CapIter iter = std::__make_capacity_aware_iterator<Iter, decltype(arr), sz>(Iter(i + 1));
+ CapIter res = iter--;
+
+ assert(*res == 2);
+ assert(*iter == 1);
+ }
+
+ // operator+=(difference_type)
+ {
+ CapIter iter = std::__make_capacity_aware_iterator<Iter, decltype(arr), sz>(Iter(i));
+ CapIter& res = iter += 2;
+
+ assert(&iter == &res);
+ assert(*iter == 3);
+ }
+
+ // operator+(__capacity_aware_iterator, difference_type)
+ {
+ CapIter iter = std::__make_capacity_aware_iterator<Iter, decltype(arr), sz>(Iter(i));
+ CapIter res = iter + 2;
+
+ assert(*iter == 1);
+ assert(*res == 3);
+ }
+
+ // operator+(difference_type, __capacity_aware_iterator)
+ {
+ CapIter iter = std::__make_capacity_aware_iterator<Iter, decltype(arr), sz>(Iter(i));
+ CapIter res = 2 + iter;
+
+ assert(*iter == 1);
+ assert(*res == 3);
+ }
+
+ // operator-=(difference_type)
+ {
+ CapIter iter = std::__make_capacity_aware_iterator<Iter, decltype(arr), sz>(Iter(i + 2));
+ CapIter& res = iter -= 2;
+
+ assert(&iter == &res);
+ assert(*iter == 1);
+ }
+
+ // operator-(__capacity_aware_iterator, difference_type)
+ {
+ CapIter iter = std::__make_capacity_aware_iterator<Iter, decltype(arr), sz>(Iter(i + 2));
+ CapIter res = iter - 2;
+
+ assert(*iter == 3);
+ assert(*res == 1);
+ }
+
+ // operator-(__capacity_aware_iterator, __capacity_aware_iterator)
+ {
+ CapIter iter = std::__make_capacity_aware_iterator<Iter, decltype(arr), sz>(Iter(i));
+ CapIter iter2 = std::__make_capacity_aware_iterator<Iter, decltype(arr), sz>(Iter(i + 2));
+ CapIter iter3 = std::__make_capacity_aware_iterator<Iter, decltype(arr), sz>(Iter(i + 6));
+ std::ptrdiff_t res = iter2 - iter;
+ std::ptrdiff_t res2 = iter3 - iter;
+
+ assert(res == 2);
+ assert(res2 == 6);
+ }
+
+ return true;
+}
+
+int main(int, char**){
+ assert(test<cpp20_random_access_iterator<int*>>());
+ static_assert(test<cpp20_random_access_iterator<int*>>());
+
+ return 0;
+}
diff --git a/libcxx/test/libcxx/iterators/capacity_aware_iter/assert.pass.cpp b/libcxx/test/libcxx/iterators/capacity_aware_iter/assert.pass.cpp
new file mode 100644
index 0000000000000..e014bc7d640db
--- /dev/null
+++ b/libcxx/test/libcxx/iterators/capacity_aware_iter/assert.pass.cpp
@@ -0,0 +1,63 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+// REQUIRES: std-at-least-c++26
+// UNSUPPORTED: libcpp-hardening-mode=none
+
+// template <class _Iterator, class _Container, class _ContainerMaxElements>
+// struct __capacity_aware_iterator;
+
+// Check assert failure if advancing, rewinding or indexing iterator past _ContainerMaxElements
+
+#include <__iterator/capacity_aware_iterator.h>
+#include <iterator>
+
+#include "check_assertion.h"
+#include "test_iterators.h"
+#include "test_macros.h"
+
+template <typename Iter>
+void test() {
+ int arr[] = {1, 2, 3, 4};
+
+ constexpr long sz = std::size(arr);
+
+ using CapIter = std::__capacity_aware_iterator<Iter, decltype(arr), sz>;
+
+ CapIter it = std::__make_capacity_aware_iterator<Iter, decltype(arr), sz>(Iter(arr));
+
+ TEST_LIBCPP_ASSERT_FAILURE(
+ it += (sz + 1),
+ "__capacity_aware_iterator::operator+=: Attempting to move iterator past its container's possible range");
+
+ TEST_LIBCPP_ASSERT_FAILURE(
+ it += -(sz + 1),
+ "__capacity_aware_iterator::operator+=: Attempting to move iterator past its container's possible range");
+
+ TEST_LIBCPP_ASSERT_FAILURE(
+ it -= (sz + 1),
+ "__capacity_aware_iterator::operator-=: Attempting to move iterator past its container's possible range");
+
+ TEST_LIBCPP_ASSERT_FAILURE(
+ it -= -(sz + 1),
+ "__capacity_aware_iterator::operator-=: Attempting to move iterator past its container's possible range");
+
+ TEST_LIBCPP_ASSERT_FAILURE(
+ it[sz],
+ "__capacity_aware_iterator::operator[]: Attempting to index iterator past its container's possible range");
+
+ TEST_LIBCPP_ASSERT_FAILURE(
+ it[-sz],
+ "__capacity_aware_iterator::operator[]: Attempting to index iterator past its container's possible range");
+}
+
+int main(int, char**) {
+ test<cpp20_random_access_iterator<int*>>();
+
+ return 0;
+}
diff --git a/libcxx/test/libcxx/iterators/capacity_aware_iter/comparison.pass.cpp b/libcxx/test/libcxx/iterators/capacity_aware_iter/comparison.pass.cpp
new file mode 100644
index 0000000000000..0cf0facc262f3
--- /dev/null
+++ b/libcxx/test/libcxx/iterators/capacity_aware_iter/comparison.pass.cpp
@@ -0,0 +1,91 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+// REQUIRES: std-at-least-c++26
+
+// template <class _Iterator, class _Container, class _ContainerMaxElements>
+// struct __capacity_aware_iterator;
+
+// Comparison operators
+
+#include <__iterator/capacity_aware_iterator.h>
+#include <compare>
+#include <iterator>
+
+#include "test_iterators.h"
+
+template<typename Iter>
+constexpr bool test(){
+ int arr[] = {1,2,3,4};
+ constexpr long sz = std::size(arr);
+
+ using CapIter = std::__capacity_aware_iterator<Iter, decltype(arr), sz>;
+
+ CapIter iter1 = std::__make_capacity_aware_iterator<Iter, decltype(arr), sz>(Iter(arr));
+ CapIter iter2 = std::__make_capacity_aware_iterator<Iter, decltype(arr), sz>(Iter(arr + 4));
+
+ // operator==
+ {
+ assert(iter1 == iter1);
+ assert(!(iter1 == iter2));
+ }
+
+ // operator!=
+ {
+ assert(iter1 != iter2);
+ assert(!(iter1 != iter1));
+ }
+
+ // operator<
+ {
+ assert(iter1 < iter2);
+ assert(!(iter1 < iter1));
+ assert(!(iter2 < iter1));
+ }
+
+ // operator<=
+ {
+ assert(iter1 <= iter2);
+ assert(iter1 <= iter1);
+ assert(!(iter2 <= iter1));
+ }
+
+ // operator>
+ {
+ assert(iter2 > iter1);
+ assert(!(iter1 > iter2));
+ assert(!(iter1 > iter1));
+ }
+
+ // operator>=
+ {
+ assert(iter2 >= iter1);
+ assert(iter1 >= iter1);
+ assert(!(iter1 >= iter2));
+ }
+
+ // operator <=>
+ {
+ std::same_as<std::strong_ordering> decltype(auto) r1 = iter1 <=> iter2;
+ assert(r1 == std::strong_ordering::less);
+
+ std::same_as<std::strong_ordering> decltype(auto) r2 = iter2 <=> iter1;
+ assert(r2 == std::strong_ordering::greater);
+
+ std::same_as<std::strong_ordering> decltype(auto) r3 = iter1 <=> iter1;
+ assert(r3 == std::strong_ordering::equal);
+ assert(r3 == std::strong_ordering::equivalent);
+ }
+
+ return true;
+}
+
+int main(int, char**){
+ assert(test<cpp20_random_access_iterator<int*>>());
+ // static_assert(test<cpp20_random_access_iterator<int*>>());
+}
diff --git a/libcxx/test/libcxx/iterators/capacity_aware_iter/dereference.pass.cpp b/libcxx/test/libcxx/iterators/capacity_aware_iter/dereference.pass.cpp
new file mode 100644
index 0000000000000..1f3b273e7b5b2
--- /dev/null
+++ b/libcxx/test/libcxx/iterators/capacity_aware_iter/dereference.pass.cpp
@@ -0,0 +1,62 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+// REQUIRES: std-at-least-c++26
+
+// template <class _Iterator, class _Container, class _ContainerMaxElements>
+// struct __capacity_aware_iterator;
+
+// Dereference operators
+
+#include <__iterator/capacity_aware_iterator.h>
+
+#include "test_iterators.h"
+
+struct Foo {
+ int x;
+ constexpr bool operator==(Foo const& other) const { return x == other.x; }
+};
+
+template <typename Iter>
+constexpr bool test() {
+ Foo arr[] = {Foo{1}, Foo{2}, Foo{3}, Foo{4}};
+ constexpr long sz = std::size(arr);
+
+ using CapIter = std::__capacity_aware_iterator<Iter, decltype(arr), sz>;
+
+ CapIter it = std::__make_capacity_aware_iterator<Iter, decltype(arr), sz>(Iter(arr));
+
+ // operator[]
+ {
+ assert(it[0] == Foo{1});
+ assert(it[1] == Foo{2});
+ assert(it[2] == Foo{3});
+
+ CapIter it2 = it + 2;
+
+ assert(it2[-1] == Foo{2});
+ assert(it2[-2] == Foo{1});
+ }
+
+ // operator*
+ {
+ assert(*it == Foo{1});
+ }
+
+ // operator->
+ {
+ assert(it->x == 1);
+ }
+
+ return true;
+}
+
+int main(int, char**) {
+ assert(test<three_way_contiguous_iterator<Foo*>>());
+ static_assert(test<three_way_contiguous_iterator<Foo*>>());
+}
diff --git a/libcxx/test/libcxx/iterators/capacity_aware_iter/types.compile.pass.cpp b/libcxx/test/libcxx/iterators/capacity_aware_iter/types.compile.pass.cpp
new file mode 100644
index 0000000000000..ca7026000eb95
--- /dev/null
+++ b/libcxx/test/libcxx/iterators/capacity_aware_iter/types.compile.pass.cpp
@@ -0,0 +1,30 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+// REQUIRES: std-at-least-c++26
+
+// template <class _Iterator, class _Container, class _ContainerMaxElements>
+// struct __capacity_aware_iterator;
+
+// Nested types
+
+#include "test_iterators.h"
+#include <__iterator/capacity_aware_iterator.h>
+#include <iterator>
+#include <type_traits>
+
+using It = contiguous_iterator<int*>;
+
+using CapIter = std::__capacity_aware_iterator<It, int[], 1>;
+
+static_assert(std::is_same_v<CapIter::iterator_category, It::iterator_category>);
+static_assert(std::is_same_v<CapIter::iterator_concept, std::contiguous_iterator_tag>);
+static_assert(std::is_same_v<CapIter::difference_type, std::iter_difference_t<It>>);
+static_assert(std::is_same_v<CapIter::reference, std::iter_reference_t<It>>);
+static_assert(std::is_same_v<CapIter::reference, std::iter_reference_t<It>>);
+static_assert(std::is_same_v<CapIter::value_type, std::iter_value_t<It>>);
diff --git a/libcxx/test/libcxx/utilities/optional/optional.iterator/assert.arithmetic.pass.cpp b/libcxx/test/libcxx/utilities/optional/optional.iterator/assert.arithmetic.pass.cpp
index f66a3f5214343..e40b269ee8255 100644
--- a/libcxx/test/libcxx/utilities/optional/optional.iterator/assert.arithmetic.pass.cpp
+++ b/libcxx/test/libcxx/utilities/optional/optional.iterator/assert.arithmetic.pass.cpp
@@ -24,23 +24,26 @@ int main(int, char**) {
TEST_LIBCPP_ASSERT_FAILURE(
i += 2,
- "__capacity_aware_iterator::operator+=: Attempting to advance iterator past its container's possible range");
+ "__capacity_aware_iterator::operator+=: Attempting to move iterator past its container's possible range");
TEST_LIBCPP_ASSERT_FAILURE(
- i += -2, "__capacity_aware_iterator::operator+=: Attempting to rewind iterator past its container's start");
+ i += -2,
+ "__capacity_aware_iterator::operator+=: Attempting to move iterator past its container's possible range");
TEST_LIBCPP_ASSERT_FAILURE(
- i -= 2, "__capacity_aware_iterator::operator-=: Attempting to rewind iterator before its container's start");
+ i -= 2,
+ "__capacity_aware_iterator::operator-=: Attempting to move iterator past its container's possible range");
TEST_LIBCPP_ASSERT_FAILURE(
i -= -2,
- "__capacity_aware_iterator::operator+=: Attempting to advance iterator past its container's possible range");
+ "__capacity_aware_iterator::operator-=: Attempting to move iterator past its container's possible range");
TEST_LIBCPP_ASSERT_FAILURE(
i[2],
"__capacity_aware_iterator::operator[]: Attempting to index iterator past its container's possible range");
TEST_LIBCPP_ASSERT_FAILURE(
- i[-2], "__capacity_aware_iterator::operator[]: Attempting to index iterator before its container's start");
+ i[-2],
+ "__capacity_aware_iterator::operator[]: Attempting to index iterator past its container's possible range");
}
}
>From a4feae97c3f23d4298de9987c8fcde1d61406721 Mon Sep 17 00:00:00 2001
From: William Tran-Viet <wtranviet at proton.me>
Date: Mon, 8 Dec 2025 20:46:45 -0500
Subject: [PATCH 13/28] Fix some typos
---
.../include/__iterator/capacity_aware_iterator.h | 16 +++++++++-------
1 file changed, 9 insertions(+), 7 deletions(-)
diff --git a/libcxx/include/__iterator/capacity_aware_iterator.h b/libcxx/include/__iterator/capacity_aware_iterator.h
index 73f095e87d339..e5a8a9f788296 100644
--- a/libcxx/include/__iterator/capacity_aware_iterator.h
+++ b/libcxx/include/__iterator/capacity_aware_iterator.h
@@ -85,8 +85,8 @@ class __capacity_aware_iterator {
template <typename _Tp, class>
friend struct __optional_iterator;
- template <class _It, class _C, size_t _M>
- friend auto __make_capacity_aware_iterator(_It __iter);
+ template <class _It, class _Container2, size_t _ContainerMaxElems2>
+ _LIBCPP_HIDE_FROM_ABI friend constexpr auto __make_capacity_aware_iterator(_It __iter);
public:
_LIBCPP_HIDE_FROM_ABI constexpr _Iter base() const noexcept { return __iter_; }
@@ -154,7 +154,7 @@ class __capacity_aware_iterator {
if constexpr (three_way_comparable_with<_Iter, _Iter, strong_ordering>) {
return __x.__iter_ <=> __y.__iter_;
} else {
- if (__x.__iter_ < __x.__iter_) {
+ if (__x.__iter_ < __y.__iter_) {
return strong_ordering::less;
} else if (__x.__iter_ == __y.__iter_) {
return strong_ordering::equal;
@@ -179,7 +179,9 @@ class __capacity_aware_iterator {
_LIBCPP_HIDE_FROM_ABI friend constexpr __capacity_aware_iterator
operator-(const __capacity_aware_iterator& __i, difference_type __n) {
- return __i.__iter_ + __n;
+ auto __tmp = __i;
+ __tmp -= __n;
+ return __tmp;
}
_LIBCPP_HIDE_FROM_ABI friend constexpr difference_type
@@ -188,9 +190,9 @@ class __capacity_aware_iterator {
}
};
-template <class _It, class _C, size_t _M>
-auto __make_capacity_aware_iterator(_It __iter) {
- return __capacity_aware_iterator<_It, _C, _M>(__iter);
+template <class _It, class _Container2, size_t _ContainerMaxElems2>
+_LIBCPP_HIDE_FROM_ABI constexpr auto __make_capacity_aware_iterator(_It __iter) {
+ return __capacity_aware_iterator<_It, _Container2, _ContainerMaxElems2>(__iter);
}
_LIBCPP_END_NAMESPACE_STD
>From dd3b01d99524680a21db3d4c4bf3171fee8dbfa5 Mon Sep 17 00:00:00 2001
From: William Tran-Viet <wtranviet at proton.me>
Date: Mon, 8 Dec 2025 21:22:45 -0500
Subject: [PATCH 14/28] Formatting
---
.../capacity_aware_iter/arithmetic.pass.cpp | 22 +++++++++----------
.../capacity_aware_iter/comparison.pass.cpp | 8 +++----
2 files changed, 15 insertions(+), 15 deletions(-)
diff --git a/libcxx/test/libcxx/iterators/capacity_aware_iter/arithmetic.pass.cpp b/libcxx/test/libcxx/iterators/capacity_aware_iter/arithmetic.pass.cpp
index 16e7ea7a6369c..26dbfa0d7be93 100644
--- a/libcxx/test/libcxx/iterators/capacity_aware_iter/arithmetic.pass.cpp
+++ b/libcxx/test/libcxx/iterators/capacity_aware_iter/arithmetic.pass.cpp
@@ -21,7 +21,7 @@
template <typename Iter>
constexpr bool test() {
- int arr[] = {1, 2, 3, 4, 5, 6};
+ int arr[] = {1, 2, 3, 4, 5, 6};
constexpr size_t sz = std::size(arr);
using CapIter = std::__capacity_aware_iterator<Iter, decltype(arr), sz>;
@@ -40,7 +40,7 @@ constexpr bool test() {
// operator++(int)
{
CapIter iter = std::__make_capacity_aware_iterator<Iter, decltype(arr), sz>(Iter(i));
- CapIter res = iter++;
+ CapIter res = iter++;
assert(*res == 1);
assert(*iter == 2);
@@ -58,7 +58,7 @@ constexpr bool test() {
// operator--(int)
{
CapIter iter = std::__make_capacity_aware_iterator<Iter, decltype(arr), sz>(Iter(i + 1));
- CapIter res = iter--;
+ CapIter res = iter--;
assert(*res == 2);
assert(*iter == 1);
@@ -76,7 +76,7 @@ constexpr bool test() {
// operator+(__capacity_aware_iterator, difference_type)
{
CapIter iter = std::__make_capacity_aware_iterator<Iter, decltype(arr), sz>(Iter(i));
- CapIter res = iter + 2;
+ CapIter res = iter + 2;
assert(*iter == 1);
assert(*res == 3);
@@ -85,7 +85,7 @@ constexpr bool test() {
// operator+(difference_type, __capacity_aware_iterator)
{
CapIter iter = std::__make_capacity_aware_iterator<Iter, decltype(arr), sz>(Iter(i));
- CapIter res = 2 + iter;
+ CapIter res = 2 + iter;
assert(*iter == 1);
assert(*res == 3);
@@ -103,7 +103,7 @@ constexpr bool test() {
// operator-(__capacity_aware_iterator, difference_type)
{
CapIter iter = std::__make_capacity_aware_iterator<Iter, decltype(arr), sz>(Iter(i + 2));
- CapIter res = iter - 2;
+ CapIter res = iter - 2;
assert(*iter == 3);
assert(*res == 1);
@@ -111,10 +111,10 @@ constexpr bool test() {
// operator-(__capacity_aware_iterator, __capacity_aware_iterator)
{
- CapIter iter = std::__make_capacity_aware_iterator<Iter, decltype(arr), sz>(Iter(i));
- CapIter iter2 = std::__make_capacity_aware_iterator<Iter, decltype(arr), sz>(Iter(i + 2));
- CapIter iter3 = std::__make_capacity_aware_iterator<Iter, decltype(arr), sz>(Iter(i + 6));
- std::ptrdiff_t res = iter2 - iter;
+ CapIter iter = std::__make_capacity_aware_iterator<Iter, decltype(arr), sz>(Iter(i));
+ CapIter iter2 = std::__make_capacity_aware_iterator<Iter, decltype(arr), sz>(Iter(i + 2));
+ CapIter iter3 = std::__make_capacity_aware_iterator<Iter, decltype(arr), sz>(Iter(i + 6));
+ std::ptrdiff_t res = iter2 - iter;
std::ptrdiff_t res2 = iter3 - iter;
assert(res == 2);
@@ -124,7 +124,7 @@ constexpr bool test() {
return true;
}
-int main(int, char**){
+int main(int, char**) {
assert(test<cpp20_random_access_iterator<int*>>());
static_assert(test<cpp20_random_access_iterator<int*>>());
diff --git a/libcxx/test/libcxx/iterators/capacity_aware_iter/comparison.pass.cpp b/libcxx/test/libcxx/iterators/capacity_aware_iter/comparison.pass.cpp
index 0cf0facc262f3..15ed12fe1b57a 100644
--- a/libcxx/test/libcxx/iterators/capacity_aware_iter/comparison.pass.cpp
+++ b/libcxx/test/libcxx/iterators/capacity_aware_iter/comparison.pass.cpp
@@ -19,9 +19,9 @@
#include "test_iterators.h"
-template<typename Iter>
-constexpr bool test(){
- int arr[] = {1,2,3,4};
+template <typename Iter>
+constexpr bool test() {
+ int arr[] = {1, 2, 3, 4};
constexpr long sz = std::size(arr);
using CapIter = std::__capacity_aware_iterator<Iter, decltype(arr), sz>;
@@ -85,7 +85,7 @@ constexpr bool test(){
return true;
}
-int main(int, char**){
+int main(int, char**) {
assert(test<cpp20_random_access_iterator<int*>>());
// static_assert(test<cpp20_random_access_iterator<int*>>());
}
>From bf41d58beca1f009e66021da1cd34616950a10f1 Mon Sep 17 00:00:00 2001
From: William Tran-Viet <wtranviet at proton.me>
Date: Mon, 8 Dec 2025 22:35:25 -0500
Subject: [PATCH 15/28] Move include
---
.../iterators/capacity_aware_iter/types.compile.pass.cpp | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/libcxx/test/libcxx/iterators/capacity_aware_iter/types.compile.pass.cpp b/libcxx/test/libcxx/iterators/capacity_aware_iter/types.compile.pass.cpp
index ca7026000eb95..b3b72a0728ed7 100644
--- a/libcxx/test/libcxx/iterators/capacity_aware_iter/types.compile.pass.cpp
+++ b/libcxx/test/libcxx/iterators/capacity_aware_iter/types.compile.pass.cpp
@@ -13,11 +13,12 @@
// Nested types
-#include "test_iterators.h"
#include <__iterator/capacity_aware_iterator.h>
#include <iterator>
#include <type_traits>
+#include "test_iterators.h"
+
using It = contiguous_iterator<int*>;
using CapIter = std::__capacity_aware_iterator<It, int[], 1>;
>From 96f83883ab6b2dac68c5dd7ebb4f88611b0f8229 Mon Sep 17 00:00:00 2001
From: William Tran-Viet <wtranviet at proton.me>
Date: Tue, 9 Dec 2025 17:13:49 -0500
Subject: [PATCH 16/28] Other overlooked things
---
libcxx/include/__iterator/capacity_aware_iterator.h | 6 +++---
.../iterators/capacity_aware_iter/comparison.pass.cpp | 4 +++-
.../iterators/capacity_aware_iter/dereference.pass.cpp | 2 ++
3 files changed, 8 insertions(+), 4 deletions(-)
diff --git a/libcxx/include/__iterator/capacity_aware_iterator.h b/libcxx/include/__iterator/capacity_aware_iterator.h
index e5a8a9f788296..3a5d0fb199c08 100644
--- a/libcxx/include/__iterator/capacity_aware_iterator.h
+++ b/libcxx/include/__iterator/capacity_aware_iterator.h
@@ -7,8 +7,8 @@
//
//===----------------------------------------------------------------------===//
-#ifndef _LIBCPP___ITERATOR_UPPER_BOUNDED_ITERATOR_H
-#define _LIBCPP___ITERATOR_UPPER_BOUNDED_ITERATOR_H
+#ifndef _LIBCPP_CAPACITY_AWARE_ITERATOR_H
+#define _LIBCPP_CAPACITY_AWARE_ITERATOR_H
#include <__assert>
#include <__compare/ordering.h>
@@ -201,4 +201,4 @@ _LIBCPP_END_NAMESPACE_STD
_LIBCPP_POP_MACROS
-#endif // _LIBCPP___ITERATOR_UPPER_BOUNDED_ITERATOR_H
+#endif // _LIBCPP_CAPACITY_AWARE_ITERATOR_H
diff --git a/libcxx/test/libcxx/iterators/capacity_aware_iter/comparison.pass.cpp b/libcxx/test/libcxx/iterators/capacity_aware_iter/comparison.pass.cpp
index 15ed12fe1b57a..67d236fc0d9ab 100644
--- a/libcxx/test/libcxx/iterators/capacity_aware_iter/comparison.pass.cpp
+++ b/libcxx/test/libcxx/iterators/capacity_aware_iter/comparison.pass.cpp
@@ -87,5 +87,7 @@ constexpr bool test() {
int main(int, char**) {
assert(test<cpp20_random_access_iterator<int*>>());
- // static_assert(test<cpp20_random_access_iterator<int*>>());
+ static_assert(test<cpp20_random_access_iterator<int*>>());
+
+ return 0;
}
diff --git a/libcxx/test/libcxx/iterators/capacity_aware_iter/dereference.pass.cpp b/libcxx/test/libcxx/iterators/capacity_aware_iter/dereference.pass.cpp
index 1f3b273e7b5b2..34d7aa4983a27 100644
--- a/libcxx/test/libcxx/iterators/capacity_aware_iter/dereference.pass.cpp
+++ b/libcxx/test/libcxx/iterators/capacity_aware_iter/dereference.pass.cpp
@@ -59,4 +59,6 @@ constexpr bool test() {
int main(int, char**) {
assert(test<three_way_contiguous_iterator<Foo*>>());
static_assert(test<three_way_contiguous_iterator<Foo*>>());
+
+ return 0;
}
>From e82c7ef0f8c584909d5254a11c5b78b46d3e63d3 Mon Sep 17 00:00:00 2001
From: William Tran-Viet <wtranviet at proton.me>
Date: Tue, 9 Dec 2025 17:14:44 -0500
Subject: [PATCH 17/28] Macro formatting
---
libcxx/include/__iterator/capacity_aware_iterator.h | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/libcxx/include/__iterator/capacity_aware_iterator.h b/libcxx/include/__iterator/capacity_aware_iterator.h
index 3a5d0fb199c08..53f72fac23876 100644
--- a/libcxx/include/__iterator/capacity_aware_iterator.h
+++ b/libcxx/include/__iterator/capacity_aware_iterator.h
@@ -7,8 +7,8 @@
//
//===----------------------------------------------------------------------===//
-#ifndef _LIBCPP_CAPACITY_AWARE_ITERATOR_H
-#define _LIBCPP_CAPACITY_AWARE_ITERATOR_H
+#ifndef _LIBCPP___CAPACITY_AWARE_ITERATOR_H
+#define _LIBCPP___CAPACITY_AWARE_ITERATOR_H
#include <__assert>
#include <__compare/ordering.h>
@@ -201,4 +201,4 @@ _LIBCPP_END_NAMESPACE_STD
_LIBCPP_POP_MACROS
-#endif // _LIBCPP_CAPACITY_AWARE_ITERATOR_H
+#endif // _LIBCPP___CAPACITY_AWARE_ITERATOR_H
>From 52a0b21895e147ff0388fd76769fc546d4c23e11 Mon Sep 17 00:00:00 2001
From: William Tran-Viet <wtranviet at proton.me>
Date: Wed, 7 Jan 2026 22:03:06 -0500
Subject: [PATCH 18/28] Fix merge issues
---
libcxx/include/optional | 8 +++++---
.../optional.iterator/iterator.compile.pass.cpp | 13 -------------
.../optional/optional.iterator/compare.pass.cpp | 9 +++++----
3 files changed, 10 insertions(+), 20 deletions(-)
diff --git a/libcxx/include/optional b/libcxx/include/optional
index b928b1ac1c5a4..596b808f5f4a9 100644
--- a/libcxx/include/optional
+++ b/libcxx/include/optional
@@ -717,7 +717,6 @@ private:
using __pointer _LIBCPP_NODEBUG = add_pointer_t<_Tp>;
using __const_pointer _LIBCPP_NODEBUG = add_pointer_t<const _Tp>;
-# if _LIBCPP_STD_VER >= 26
template <typename _Underlying>
using __iter _LIBCPP_NODEBUG = __capacity_aware_iterator<_Underlying, optional<_Tp>, 1>;
@@ -770,13 +769,16 @@ public:
template <class _Tp>
struct __optional_iterator<_Tp&, enable_if_t<is_object_v<_Tp> && !__is_unbounded_array_v<_Tp> >> {
private:
+ template <typename _Underlying>
+ using __iter _LIBCPP_NODEBUG = __capacity_aware_iterator<_Underlying, optional<_Tp&>, 1>;
+
using __pointer _LIBCPP_NODEBUG = add_pointer_t<_Tp>;
public:
# ifdef _LIBCPP_ABI_BOUNDED_ITERATORS_IN_OPTIONAL
using iterator = __bounded_iter<__wrap_iter<__pointer>>;
# else
- using iterator = __wrap_iter<__pointer>;
+ using iterator = __iter<__wrap_iter<__pointer>>;
# endif
// [optional.ref.iterators], iterator support
@@ -791,7 +793,7 @@ public:
__wrap_iter<__pointer>(__ptr),
__wrap_iter<__pointer>(__ptr) + (__derived_self.has_value() ? 1 : 0));
# else
- return iterator(__ptr);
+ return iterator(__wrap_iter<__pointer>(__ptr));
# endif
}
diff --git a/libcxx/test/libcxx/utilities/optional/optional.iterator/iterator.compile.pass.cpp b/libcxx/test/libcxx/utilities/optional/optional.iterator/iterator.compile.pass.cpp
index ea99978f72e7c..b6e407dacca42 100644
--- a/libcxx/test/libcxx/utilities/optional/optional.iterator/iterator.compile.pass.cpp
+++ b/libcxx/test/libcxx/utilities/optional/optional.iterator/iterator.compile.pass.cpp
@@ -19,19 +19,6 @@
#include <type_traits>
#include <vector>
-template <typename T>
-concept has_iterator_aliases = requires {
- typename T::iterator;
- typename T::const_iterator;
-};
-
-static_assert(has_iterator_aliases<std::optional<int>>);
-static_assert(has_iterator_aliases<std::optional<const int>>);
-static_assert(has_iterator_aliases<std::optional<int&>>);
-static_assert(has_iterator_aliases<std::optional<const int&>>);
-static_assert(!has_iterator_aliases<std::optional<int (&)[1]>>);
-static_assert(!has_iterator_aliases<std::optional<int (&)()>>);
-
using Iter1 = std::optional<int>::iterator;
using Iter2 = std::optional<double>::iterator;
using Iter3 = std::optional<int>::const_iterator;
diff --git a/libcxx/test/std/utilities/optional/optional.iterator/compare.pass.cpp b/libcxx/test/std/utilities/optional/optional.iterator/compare.pass.cpp
index d24300931d566..2c27ecb4c9f7c 100644
--- a/libcxx/test/std/utilities/optional/optional.iterator/compare.pass.cpp
+++ b/libcxx/test/std/utilities/optional/optional.iterator/compare.pass.cpp
@@ -23,11 +23,12 @@
template <typename T>
constexpr bool test() {
using Opt = std::optional<T>;
- using I = Opt::iterator;
- using CI = Opt::const_iterator;
- static_assert(std::three_way_comparable<I>);
- static_assert(std::three_way_comparable<CI>);
+ static_assert(std::three_way_comparable<typename Opt::iterator>);
+
+ if constexpr (std::is_object_v<T>) {
+ static_assert(std::three_way_comparable<typename Opt::const_iterator>);
+ }
std::remove_reference_t<T> t{};
Opt opt{t};
>From 0cbb843d0a3335d11499c6b6dd4bee527822b319 Mon Sep 17 00:00:00 2001
From: William Tran-Viet <wtranviet at proton.me>
Date: Wed, 14 Jan 2026 21:57:13 -0500
Subject: [PATCH 19/28] Address most comments
---
.../__iterator/capacity_aware_iterator.h | 61 ++++++++-----------
libcxx/include/optional | 21 +++----
.../capacity_aware_iter/arithmetic.pass.cpp | 15 ++++-
.../capacity_aware_iter/assert.pass.cpp | 4 +-
.../capacity_aware_iter/comparison.pass.cpp | 12 +++-
.../capacity_aware_iter/contiguous.verify.cpp | 30 +++++++++
.../capacity_aware_iter/dereference.pass.cpp | 4 ++
.../assert.arithmetic.pass.cpp | 2 +
8 files changed, 94 insertions(+), 55 deletions(-)
create mode 100644 libcxx/test/libcxx/iterators/capacity_aware_iter/contiguous.verify.cpp
diff --git a/libcxx/include/__iterator/capacity_aware_iterator.h b/libcxx/include/__iterator/capacity_aware_iterator.h
index 53f72fac23876..e6b64875fb814 100644
--- a/libcxx/include/__iterator/capacity_aware_iterator.h
+++ b/libcxx/include/__iterator/capacity_aware_iterator.h
@@ -34,36 +34,27 @@ _LIBCPP_PUSH_MACROS
_LIBCPP_BEGIN_NAMESPACE_STD
-// __capacity_aware_iterator is an iterator that wraps an underlying iterator.
-// It stores the underlying container type to prevent mixing iterators, and allow algorithms
-// to optimize based on the underlying container type.
-// It also encodes the container's (known at compile-time) maximum amount of elements as part of the type.
-// As of writing, the only standard library containers which have this property are inplace_vector and optional.
+// __capacity_aware_iterator is an iterator that wraps a contiguous iterator and encodes the maximum number of
+// elements that can appear in a range of such iterators. That maximum number of elements must be known at compile-time.
+//
+// It also embeds a tag type to prevent mixing iterators from e.g. different containers. This also allows for some algorithms
+// to detect this iterator and perform optimizations based on the added semantic information.
+//
+// As of writing, the only standard library containers which fulfill the requirements are inplace_vector and optional.
-template <class _Iter, class _Container, std::size_t _ContainerMaxElements>
+template <class _Iter, class _Tag, std::size_t _RangeMaxElements>
class __capacity_aware_iterator {
private:
_Iter __iter_;
- friend _Container;
-
- _LIBCPP_HIDE_FROM_ABI static constexpr auto __get_iter_concept() {
- if constexpr (contiguous_iterator<_Iter>) {
- return contiguous_iterator_tag{};
- } else if constexpr (random_access_iterator<_Iter>) {
- return random_access_iterator_tag{};
- } else if constexpr (bidirectional_iterator<_Iter>) {
- return bidirectional_iterator_tag{};
- } else if constexpr (forward_iterator<_Iter>) {
- return forward_iterator_tag{};
- } else {
- return input_iterator_tag{};
- }
- }
+ template <class, class, std::size_t>
+ friend class __capacity_aware_iterator;
public:
+ static_assert(contiguous_iterator<_Iter>, "__capacity_aware_iterator can only be used with contiguous iterators");
+
using iterator_category = iterator_traits<_Iter>::iterator_category;
- using iterator_concept = decltype(__get_iter_concept());
+ using iterator_concept = contiguous_iterator_tag;
using difference_type = iter_difference_t<_Iter>;
using pointer = iterator_traits<_Iter>::pointer;
using reference = iter_reference_t<_Iter>;
@@ -76,20 +67,16 @@ class __capacity_aware_iterator {
template <typename _Iter2>
requires is_convertible_v<_Iter2, _Iter>
_LIBCPP_HIDE_FROM_ABI constexpr __capacity_aware_iterator(
- const __capacity_aware_iterator<_Iter2, _Container, _ContainerMaxElements>& __y)
- : __iter_(__y.base()) {}
+ const __capacity_aware_iterator<_Iter2, _Tag, _RangeMaxElements>& __y)
+ : __iter_(__y.__iter_) {}
+
+ template <class _It, class _Tag2, size_t _RangeMaxElems2>
+ _LIBCPP_HIDE_FROM_ABI friend constexpr auto __make_capacity_aware_iterator(_It __iter);
private:
_LIBCPP_HIDE_FROM_ABI constexpr explicit __capacity_aware_iterator(_Iter __iter) : __iter_(std::move(__iter)) {}
- template <typename _Tp, class>
- friend struct __optional_iterator;
-
- template <class _It, class _Container2, size_t _ContainerMaxElems2>
- _LIBCPP_HIDE_FROM_ABI friend constexpr auto __make_capacity_aware_iterator(_It __iter);
-
public:
- _LIBCPP_HIDE_FROM_ABI constexpr _Iter base() const noexcept { return __iter_; }
_LIBCPP_HIDE_FROM_ABI constexpr decltype(auto) operator*() const { return *__iter_; }
_LIBCPP_HIDE_FROM_ABI constexpr decltype(auto) operator->() const
requires requires { __iter_.operator->(); }
@@ -121,7 +108,7 @@ class __capacity_aware_iterator {
_LIBCPP_HIDE_FROM_ABI constexpr __capacity_aware_iterator& operator+=(difference_type __n) {
_LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(
- static_cast<size_t>((__n >= 0 ? __n : -__n)) <= _ContainerMaxElements,
+ static_cast<size_t>((__n >= 0 ? __n : -__n)) <= _RangeMaxElements,
"__capacity_aware_iterator::operator+=: Attempting to move iterator past its container's possible range");
__iter_ += __n;
@@ -130,7 +117,7 @@ class __capacity_aware_iterator {
_LIBCPP_HIDE_FROM_ABI constexpr __capacity_aware_iterator& operator-=(difference_type __n) {
_LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(
- static_cast<size_t>((__n >= 0 ? __n : -__n)) <= _ContainerMaxElements,
+ static_cast<size_t>((__n >= 0 ? __n : -__n)) <= _RangeMaxElements,
"__capacity_aware_iterator::operator-=: Attempting to move iterator past its container's possible range");
__iter_ -= __n;
@@ -139,7 +126,7 @@ class __capacity_aware_iterator {
_LIBCPP_HIDE_FROM_ABI constexpr decltype(auto) operator[](difference_type __n) const {
_LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(
- static_cast<size_t>(__n >= 0 ? __n : -__n) < _ContainerMaxElements,
+ static_cast<size_t>(__n >= 0 ? __n : -__n) < _RangeMaxElements,
"__capacity_aware_iterator::operator[]: Attempting to index iterator past its container's possible range");
return *(*this + __n);
}
@@ -186,13 +173,13 @@ class __capacity_aware_iterator {
_LIBCPP_HIDE_FROM_ABI friend constexpr difference_type
operator-(const __capacity_aware_iterator& __x, const __capacity_aware_iterator& __y) {
- return difference_type(__x.base() - __y.base());
+ return difference_type(__x.__iter_ - __y.__iter_);
}
};
-template <class _It, class _Container2, size_t _ContainerMaxElems2>
+template <class _It, class _Tag2, size_t _RangeMaxElems2>
_LIBCPP_HIDE_FROM_ABI constexpr auto __make_capacity_aware_iterator(_It __iter) {
- return __capacity_aware_iterator<_It, _Container2, _ContainerMaxElems2>(__iter);
+ return __capacity_aware_iterator<_It, _Tag2, _RangeMaxElems2>(__iter);
}
_LIBCPP_END_NAMESPACE_STD
diff --git a/libcxx/include/optional b/libcxx/include/optional
index 596b808f5f4a9..c3fe3e479e7b5 100644
--- a/libcxx/include/optional
+++ b/libcxx/include/optional
@@ -717,16 +717,13 @@ private:
using __pointer _LIBCPP_NODEBUG = add_pointer_t<_Tp>;
using __const_pointer _LIBCPP_NODEBUG = add_pointer_t<const _Tp>;
- template <typename _Underlying>
- using __iter _LIBCPP_NODEBUG = __capacity_aware_iterator<_Underlying, optional<_Tp>, 1>;
-
public:
# ifdef _LIBCPP_ABI_BOUNDED_ITERATORS_IN_OPTIONAL
using iterator = __bounded_iter<__wrap_iter<__pointer>>;
using const_iterator = __bounded_iter<__wrap_iter<__const_pointer>>;
# else
- using iterator = __iter<__wrap_iter<__pointer>>;
- using const_iterator = __iter<__wrap_iter<__const_pointer>>;
+ using iterator = __capacity_aware_iterator<__wrap_iter<__pointer>, optional<_Tp>, 1>;
+ using const_iterator = __capacity_aware_iterator<__wrap_iter<__const_pointer>, optional<_Tp>, 1>;
# endif
// [optional.iterators], iterator support
@@ -740,7 +737,8 @@ public:
__wrap_iter<__pointer>(__ptr),
__wrap_iter<__pointer>(__ptr) + (__derived_self.has_value() ? 1 : 0));
# else
- return iterator(__wrap_iter<__pointer>(__ptr));
+ return std::__make_capacity_aware_iterator<__wrap_iter<__pointer>, optional<_Tp>, 1>(
+ __wrap_iter<__pointer>(__ptr));
# endif
}
@@ -754,7 +752,8 @@ public:
__wrap_iter<__const_pointer>(__ptr),
__wrap_iter<__const_pointer>(__ptr) + (__derived_self.has_value() ? 1 : 0));
# else
- return const_iterator(__wrap_iter<__const_pointer>(__ptr));
+ return std::__make_capacity_aware_iterator<__wrap_iter<__const_pointer>, optional<_Tp>, 1>(
+ __wrap_iter<__const_pointer>(__ptr));
# endif
}
@@ -769,16 +768,13 @@ public:
template <class _Tp>
struct __optional_iterator<_Tp&, enable_if_t<is_object_v<_Tp> && !__is_unbounded_array_v<_Tp> >> {
private:
- template <typename _Underlying>
- using __iter _LIBCPP_NODEBUG = __capacity_aware_iterator<_Underlying, optional<_Tp&>, 1>;
-
using __pointer _LIBCPP_NODEBUG = add_pointer_t<_Tp>;
public:
# ifdef _LIBCPP_ABI_BOUNDED_ITERATORS_IN_OPTIONAL
using iterator = __bounded_iter<__wrap_iter<__pointer>>;
# else
- using iterator = __iter<__wrap_iter<__pointer>>;
+ using iterator = __capacity_aware_iterator<__wrap_iter<__pointer>, optional<_Tp&>, 1>;
# endif
// [optional.ref.iterators], iterator support
@@ -793,7 +789,8 @@ public:
__wrap_iter<__pointer>(__ptr),
__wrap_iter<__pointer>(__ptr) + (__derived_self.has_value() ? 1 : 0));
# else
- return iterator(__wrap_iter<__pointer>(__ptr));
+ return std::__make_capacity_aware_iterator<__wrap_iter<__pointer>, optional<_Tp&>, 1>(
+ __wrap_iter<__pointer>(__ptr));
# endif
}
diff --git a/libcxx/test/libcxx/iterators/capacity_aware_iter/arithmetic.pass.cpp b/libcxx/test/libcxx/iterators/capacity_aware_iter/arithmetic.pass.cpp
index 26dbfa0d7be93..ce577edb22967 100644
--- a/libcxx/test/libcxx/iterators/capacity_aware_iter/arithmetic.pass.cpp
+++ b/libcxx/test/libcxx/iterators/capacity_aware_iter/arithmetic.pass.cpp
@@ -13,6 +13,17 @@
// Arithmetic operators
+// operator++()
+// operator++(int)
+// operator--()
+// operator--(int)
+// operator+=(difference_type)
+// operator+(__capacity_aware_iterator, difference_type)
+// operator+(difference_type, __capacity_aware_iterator)
+// operator-=(difference_type)
+// operator-(__capacity_aware_iterator, difference_type)
+// operator-(__capacity_aware_iterator, __capacity_aware_iterator)
+
#include <__iterator/capacity_aware_iterator.h>
#include <cstddef>
#include <iterator>
@@ -125,8 +136,8 @@ constexpr bool test() {
}
int main(int, char**) {
- assert(test<cpp20_random_access_iterator<int*>>());
- static_assert(test<cpp20_random_access_iterator<int*>>());
+ assert(test<contiguous_iterator<int*>>());
+ static_assert(test<contiguous_iterator<int*>>());
return 0;
}
diff --git a/libcxx/test/libcxx/iterators/capacity_aware_iter/assert.pass.cpp b/libcxx/test/libcxx/iterators/capacity_aware_iter/assert.pass.cpp
index e014bc7d640db..ceac20d549c34 100644
--- a/libcxx/test/libcxx/iterators/capacity_aware_iter/assert.pass.cpp
+++ b/libcxx/test/libcxx/iterators/capacity_aware_iter/assert.pass.cpp
@@ -12,7 +12,7 @@
// template <class _Iterator, class _Container, class _ContainerMaxElements>
// struct __capacity_aware_iterator;
-// Check assert failure if advancing, rewinding or indexing iterator past _ContainerMaxElements
+// Check assert failure if advancing, rewinding or indexing iterator past its maximum range size
#include <__iterator/capacity_aware_iterator.h>
#include <iterator>
@@ -57,7 +57,7 @@ void test() {
}
int main(int, char**) {
- test<cpp20_random_access_iterator<int*>>();
+ test<contiguous_iterator<int*>>();
return 0;
}
diff --git a/libcxx/test/libcxx/iterators/capacity_aware_iter/comparison.pass.cpp b/libcxx/test/libcxx/iterators/capacity_aware_iter/comparison.pass.cpp
index 67d236fc0d9ab..cd9be482b1dcb 100644
--- a/libcxx/test/libcxx/iterators/capacity_aware_iter/comparison.pass.cpp
+++ b/libcxx/test/libcxx/iterators/capacity_aware_iter/comparison.pass.cpp
@@ -13,6 +13,14 @@
// Comparison operators
+// operator==
+// operator!=
+// operator<
+// operator<=
+// operator>
+// operator>=
+// operator<=>
+
#include <__iterator/capacity_aware_iterator.h>
#include <compare>
#include <iterator>
@@ -86,8 +94,8 @@ constexpr bool test() {
}
int main(int, char**) {
- assert(test<cpp20_random_access_iterator<int*>>());
- static_assert(test<cpp20_random_access_iterator<int*>>());
+ assert(test<contiguous_iterator<int*>>());
+ static_assert(test<contiguous_iterator<int*>>());
return 0;
}
diff --git a/libcxx/test/libcxx/iterators/capacity_aware_iter/contiguous.verify.cpp b/libcxx/test/libcxx/iterators/capacity_aware_iter/contiguous.verify.cpp
new file mode 100644
index 0000000000000..0c49d2f1ac000
--- /dev/null
+++ b/libcxx/test/libcxx/iterators/capacity_aware_iter/contiguous.verify.cpp
@@ -0,0 +1,30 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+// REQUIRES: std-at-least-c++26
+
+// __capacity_aware_iterator<class _Iter, class _Tag, std::size_t>
+
+// Verify that only contiguous_iterators are accepted
+
+#include <__iterator/capacity_aware_iterator.h>
+
+#include "test_iterators.h"
+
+void test() {
+ std::__capacity_aware_iterator<cpp20_random_access_iterator<int*>, int[], 0>
+ v1; // expected-error@*:* {{static assertion failed: __capacity_aware_iterator can only be used with contiguous iterators}}
+ std::__capacity_aware_iterator<cpp20_input_iterator<int*>, int[], 0>
+ v2; // expected-error@*:* {{static assertion failed: __capacity_aware_iterator can only be used with contiguous iterators}}
+ std::__capacity_aware_iterator<bidirectional_iterator<int*>, int[], 0>
+ v3; // expected-error@*:* {{static assertion failed: __capacity_aware_iterator can only be used with contiguous iterators}}
+ std::__capacity_aware_iterator<cpp20_output_iterator<int*>, int[], 0>
+ v4; // expected-error@*:* {{static assertion failed: __capacity_aware_iterator can only be used with contiguous iterators}}
+ std::__capacity_aware_iterator<forward_iterator<int*>, int[], 0>
+ v5; // expected-error@*:* {{static assertion failed: __capacity_aware_iterator can only be used with contiguous iterators}}
+}
diff --git a/libcxx/test/libcxx/iterators/capacity_aware_iter/dereference.pass.cpp b/libcxx/test/libcxx/iterators/capacity_aware_iter/dereference.pass.cpp
index 34d7aa4983a27..284f697b6523a 100644
--- a/libcxx/test/libcxx/iterators/capacity_aware_iter/dereference.pass.cpp
+++ b/libcxx/test/libcxx/iterators/capacity_aware_iter/dereference.pass.cpp
@@ -13,6 +13,10 @@
// Dereference operators
+// operator[](difference_type)
+// operator*();
+// operator->();
+
#include <__iterator/capacity_aware_iterator.h>
#include "test_iterators.h"
diff --git a/libcxx/test/libcxx/utilities/optional/optional.iterator/assert.arithmetic.pass.cpp b/libcxx/test/libcxx/utilities/optional/optional.iterator/assert.arithmetic.pass.cpp
index e40b269ee8255..cd73d67b39038 100644
--- a/libcxx/test/libcxx/utilities/optional/optional.iterator/assert.arithmetic.pass.cpp
+++ b/libcxx/test/libcxx/utilities/optional/optional.iterator/assert.arithmetic.pass.cpp
@@ -46,4 +46,6 @@ int main(int, char**) {
i[-2],
"__capacity_aware_iterator::operator[]: Attempting to index iterator past its container's possible range");
}
+
+ return 0;
}
>From 140a4b35198494735176b95bebeef9a1820966e7 Mon Sep 17 00:00:00 2001
From: William Tran-Viet <wtranviet at proton.me>
Date: Wed, 14 Jan 2026 22:39:57 -0500
Subject: [PATCH 20/28] Formatting
---
libcxx/include/__iterator/capacity_aware_iterator.h | 4 ++--
libcxx/include/optional | 3 +--
2 files changed, 3 insertions(+), 4 deletions(-)
diff --git a/libcxx/include/__iterator/capacity_aware_iterator.h b/libcxx/include/__iterator/capacity_aware_iterator.h
index e6b64875fb814..55e823925230a 100644
--- a/libcxx/include/__iterator/capacity_aware_iterator.h
+++ b/libcxx/include/__iterator/capacity_aware_iterator.h
@@ -37,8 +37,8 @@ _LIBCPP_BEGIN_NAMESPACE_STD
// __capacity_aware_iterator is an iterator that wraps a contiguous iterator and encodes the maximum number of
// elements that can appear in a range of such iterators. That maximum number of elements must be known at compile-time.
//
-// It also embeds a tag type to prevent mixing iterators from e.g. different containers. This also allows for some algorithms
-// to detect this iterator and perform optimizations based on the added semantic information.
+// It also embeds a tag type to prevent mixing iterators from e.g. different containers. This also allows for some
+// algorithms to detect this iterator and perform optimizations based on the added semantic information.
//
// As of writing, the only standard library containers which fulfill the requirements are inplace_vector and optional.
diff --git a/libcxx/include/optional b/libcxx/include/optional
index c3fe3e479e7b5..1bbaa5910dd68 100644
--- a/libcxx/include/optional
+++ b/libcxx/include/optional
@@ -737,8 +737,7 @@ public:
__wrap_iter<__pointer>(__ptr),
__wrap_iter<__pointer>(__ptr) + (__derived_self.has_value() ? 1 : 0));
# else
- return std::__make_capacity_aware_iterator<__wrap_iter<__pointer>, optional<_Tp>, 1>(
- __wrap_iter<__pointer>(__ptr));
+ return std::__make_capacity_aware_iterator<__wrap_iter<__pointer>, optional<_Tp>, 1>(__wrap_iter<__pointer>(__ptr));
# endif
}
>From 0edd32a60d7d24335d9089043c340289cee77246 Mon Sep 17 00:00:00 2001
From: William Tran-Viet <wtranviet at proton.me>
Date: Wed, 14 Jan 2026 22:54:33 -0500
Subject: [PATCH 21/28] Mark functions noexcept
---
.../__iterator/capacity_aware_iterator.h | 36 +++++++++----------
1 file changed, 18 insertions(+), 18 deletions(-)
diff --git a/libcxx/include/__iterator/capacity_aware_iterator.h b/libcxx/include/__iterator/capacity_aware_iterator.h
index 55e823925230a..a360b957d2718 100644
--- a/libcxx/include/__iterator/capacity_aware_iterator.h
+++ b/libcxx/include/__iterator/capacity_aware_iterator.h
@@ -67,46 +67,46 @@ class __capacity_aware_iterator {
template <typename _Iter2>
requires is_convertible_v<_Iter2, _Iter>
_LIBCPP_HIDE_FROM_ABI constexpr __capacity_aware_iterator(
- const __capacity_aware_iterator<_Iter2, _Tag, _RangeMaxElements>& __y)
+ const __capacity_aware_iterator<_Iter2, _Tag, _RangeMaxElements>& __y) noexcept
: __iter_(__y.__iter_) {}
template <class _It, class _Tag2, size_t _RangeMaxElems2>
- _LIBCPP_HIDE_FROM_ABI friend constexpr auto __make_capacity_aware_iterator(_It __iter);
+ _LIBCPP_HIDE_FROM_ABI friend constexpr auto __make_capacity_aware_iterator(_It __iter) noexcept;
private:
_LIBCPP_HIDE_FROM_ABI constexpr explicit __capacity_aware_iterator(_Iter __iter) : __iter_(std::move(__iter)) {}
public:
- _LIBCPP_HIDE_FROM_ABI constexpr decltype(auto) operator*() const { return *__iter_; }
- _LIBCPP_HIDE_FROM_ABI constexpr decltype(auto) operator->() const
+ _LIBCPP_HIDE_FROM_ABI constexpr decltype(auto) operator*() const noexcept { return *__iter_; }
+ _LIBCPP_HIDE_FROM_ABI constexpr decltype(auto) operator->() const noexcept
requires requires { __iter_.operator->(); }
{
return __iter_.operator->();
}
- _LIBCPP_HIDE_FROM_ABI constexpr __capacity_aware_iterator& operator++() {
+ _LIBCPP_HIDE_FROM_ABI constexpr __capacity_aware_iterator& operator++() noexcept {
++__iter_;
return *this;
}
- _LIBCPP_HIDE_FROM_ABI constexpr __capacity_aware_iterator operator++(int) {
+ _LIBCPP_HIDE_FROM_ABI constexpr __capacity_aware_iterator operator++(int) noexcept {
__capacity_aware_iterator __tmp(*this);
++*this;
return __tmp;
}
- _LIBCPP_HIDE_FROM_ABI constexpr __capacity_aware_iterator& operator--() {
+ _LIBCPP_HIDE_FROM_ABI constexpr __capacity_aware_iterator& operator--() noexcept {
--__iter_;
return *this;
}
- _LIBCPP_HIDE_FROM_ABI constexpr __capacity_aware_iterator operator--(int) {
+ _LIBCPP_HIDE_FROM_ABI constexpr __capacity_aware_iterator operator--(int) noexcept {
__capacity_aware_iterator __tmp(*this);
--*this;
return __tmp;
}
- _LIBCPP_HIDE_FROM_ABI constexpr __capacity_aware_iterator& operator+=(difference_type __n) {
+ _LIBCPP_HIDE_FROM_ABI constexpr __capacity_aware_iterator& operator+=(difference_type __n) noexcept {
_LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(
static_cast<size_t>((__n >= 0 ? __n : -__n)) <= _RangeMaxElements,
"__capacity_aware_iterator::operator+=: Attempting to move iterator past its container's possible range");
@@ -115,7 +115,7 @@ class __capacity_aware_iterator {
return *this;
}
- _LIBCPP_HIDE_FROM_ABI constexpr __capacity_aware_iterator& operator-=(difference_type __n) {
+ _LIBCPP_HIDE_FROM_ABI constexpr __capacity_aware_iterator& operator-=(difference_type __n) noexcept {
_LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(
static_cast<size_t>((__n >= 0 ? __n : -__n)) <= _RangeMaxElements,
"__capacity_aware_iterator::operator-=: Attempting to move iterator past its container's possible range");
@@ -124,7 +124,7 @@ class __capacity_aware_iterator {
return *this;
}
- _LIBCPP_HIDE_FROM_ABI constexpr decltype(auto) operator[](difference_type __n) const {
+ _LIBCPP_HIDE_FROM_ABI constexpr decltype(auto) operator[](difference_type __n) const noexcept {
_LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(
static_cast<size_t>(__n >= 0 ? __n : -__n) < _RangeMaxElements,
"__capacity_aware_iterator::operator[]: Attempting to index iterator past its container's possible range");
@@ -132,12 +132,12 @@ class __capacity_aware_iterator {
}
_LIBCPP_HIDE_FROM_ABI friend constexpr bool
- operator==(const __capacity_aware_iterator& __x, const __capacity_aware_iterator& __y) {
+ operator==(const __capacity_aware_iterator& __x, const __capacity_aware_iterator& __y) noexcept {
return __x.__iter_ == __y.__iter_;
}
_LIBCPP_HIDE_FROM_ABI friend constexpr auto
- operator<=>(const __capacity_aware_iterator& __x, const __capacity_aware_iterator& __y) {
+ operator<=>(const __capacity_aware_iterator& __x, const __capacity_aware_iterator& __y) noexcept {
if constexpr (three_way_comparable_with<_Iter, _Iter, strong_ordering>) {
return __x.__iter_ <=> __y.__iter_;
} else {
@@ -151,34 +151,34 @@ class __capacity_aware_iterator {
}
_LIBCPP_HIDE_FROM_ABI friend constexpr __capacity_aware_iterator
- operator+(const __capacity_aware_iterator& __i, difference_type __n) {
+ operator+(const __capacity_aware_iterator& __i, difference_type __n) noexcept {
auto __tmp = __i;
__tmp += __n;
return __tmp;
}
_LIBCPP_HIDE_FROM_ABI friend constexpr __capacity_aware_iterator
- operator+(difference_type __n, const __capacity_aware_iterator& __i) {
+ operator+(difference_type __n, const __capacity_aware_iterator& __i) noexcept {
auto __tmp = __i;
__tmp += __n;
return __tmp;
}
_LIBCPP_HIDE_FROM_ABI friend constexpr __capacity_aware_iterator
- operator-(const __capacity_aware_iterator& __i, difference_type __n) {
+ operator-(const __capacity_aware_iterator& __i, difference_type __n) noexcept {
auto __tmp = __i;
__tmp -= __n;
return __tmp;
}
_LIBCPP_HIDE_FROM_ABI friend constexpr difference_type
- operator-(const __capacity_aware_iterator& __x, const __capacity_aware_iterator& __y) {
+ operator-(const __capacity_aware_iterator& __x, const __capacity_aware_iterator& __y) noexcept {
return difference_type(__x.__iter_ - __y.__iter_);
}
};
template <class _It, class _Tag2, size_t _RangeMaxElems2>
-_LIBCPP_HIDE_FROM_ABI constexpr auto __make_capacity_aware_iterator(_It __iter) {
+_LIBCPP_HIDE_FROM_ABI constexpr auto __make_capacity_aware_iterator(_It __iter) noexcept {
return __capacity_aware_iterator<_It, _Tag2, _RangeMaxElems2>(__iter);
}
>From 055bf236ec0f50a3f0cbbb87d4e4f819dc1d8d2f Mon Sep 17 00:00:00 2001
From: William Tran-Viet <wtranviet at proton.me>
Date: Mon, 26 Jan 2026 21:10:31 -0500
Subject: [PATCH 22/28] Add pointer traits specialization
---
.../__iterator/capacity_aware_iterator.h | 19 +++++--
.../pointer_traits.pass.cpp | 56 +++++++++++++++++++
2 files changed, 70 insertions(+), 5 deletions(-)
create mode 100644 libcxx/test/libcxx/iterators/capacity_aware_iter/pointer_traits.pass.cpp
diff --git a/libcxx/include/__iterator/capacity_aware_iterator.h b/libcxx/include/__iterator/capacity_aware_iterator.h
index a360b957d2718..1ea1b312611b0 100644
--- a/libcxx/include/__iterator/capacity_aware_iterator.h
+++ b/libcxx/include/__iterator/capacity_aware_iterator.h
@@ -64,6 +64,8 @@ class __capacity_aware_iterator {
requires is_default_constructible_v<_Iter>
= default;
+ friend struct pointer_traits<__capacity_aware_iterator<_Iter, _Tag, _RangeMaxElements>>;
+
template <typename _Iter2>
requires is_convertible_v<_Iter2, _Iter>
_LIBCPP_HIDE_FROM_ABI constexpr __capacity_aware_iterator(
@@ -78,11 +80,7 @@ class __capacity_aware_iterator {
public:
_LIBCPP_HIDE_FROM_ABI constexpr decltype(auto) operator*() const noexcept { return *__iter_; }
- _LIBCPP_HIDE_FROM_ABI constexpr decltype(auto) operator->() const noexcept
- requires requires { __iter_.operator->(); }
- {
- return __iter_.operator->();
- }
+ _LIBCPP_HIDE_FROM_ABI constexpr decltype(auto) operator->() const noexcept { return std::__to_address(__iter_); }
_LIBCPP_HIDE_FROM_ABI constexpr __capacity_aware_iterator& operator++() noexcept {
++__iter_;
@@ -182,6 +180,17 @@ _LIBCPP_HIDE_FROM_ABI constexpr auto __make_capacity_aware_iterator(_It __iter)
return __capacity_aware_iterator<_It, _Tag2, _RangeMaxElems2>(__iter);
}
+template <class _Iter, class _Tag, std::size_t _RangeMaxElements>
+struct pointer_traits<__capacity_aware_iterator<_Iter, _Tag, _RangeMaxElements>> {
+ using pointer = __capacity_aware_iterator<_Iter, _Tag, _RangeMaxElements>;
+ using element_type = typename pointer_traits<_Iter>::element_type;
+ using difference_type = typename pointer_traits<_Iter>::difference_type;
+
+ _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR static element_type* to_address(pointer __it) _NOEXCEPT {
+ return std::__to_address(__it.__iter_);
+ }
+};
+
_LIBCPP_END_NAMESPACE_STD
#endif // _LIBCPP_STD_VER >= 26
diff --git a/libcxx/test/libcxx/iterators/capacity_aware_iter/pointer_traits.pass.cpp b/libcxx/test/libcxx/iterators/capacity_aware_iter/pointer_traits.pass.cpp
new file mode 100644
index 0000000000000..b67aba6bc2739
--- /dev/null
+++ b/libcxx/test/libcxx/iterators/capacity_aware_iter/pointer_traits.pass.cpp
@@ -0,0 +1,56 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+// REQUIRES: std-at-least-c++26
+
+// template <class _Iterator, class _Container, class _ContainerMaxElements>
+// struct __capacity_aware_iterator;
+//
+// std::pointer_traits specialization
+
+#include <__iterator/capacity_aware_iterator.h>
+#include <cassert>
+#include <cstddef>
+#include <iterator>
+#include <memory>
+#include <type_traits>
+
+#include "test_iterators.h"
+#include "test_macros.h"
+
+template <class Iter>
+TEST_CONSTEXPR_CXX14 bool tests() {
+ int array[] = {0, 1, 2, 3, 4};
+
+ using CapIter = std::__capacity_aware_iterator<Iter, decltype(array), std::size(array)>;
+ using PointerTraits = std::pointer_traits<CapIter>;
+ using BasePointerTraits = std::pointer_traits<Iter>;
+ static_assert(std::is_same_v<typename PointerTraits::pointer, CapIter>);
+ static_assert(std::is_same_v<typename PointerTraits::element_type, typename BasePointerTraits::element_type>);
+ static_assert(std::is_same_v<typename PointerTraits::difference_type, typename BasePointerTraits::difference_type>);
+
+ {
+ int* b = array + 0;
+ int* e = array + 5;
+ CapIter const iter1 = std::__make_capacity_aware_iterator<Iter, decltype(array), std::size(array)>(Iter(b));
+ CapIter const iter2 = std::__make_capacity_aware_iterator<Iter, decltype(array), std::size(array)>(Iter(e));
+ assert(std::to_address(iter1) == b); // in-bounds iterator
+ assert(std::to_address(iter2) == e); // out-of-bounds iterator
+ }
+
+ return true;
+}
+
+int main(int, char**) {
+ tests<int*>();
+ static_assert(tests<int*>(), "");
+ tests<contiguous_iterator<int*> >();
+ static_assert(tests<contiguous_iterator<int*> >(), "");
+
+ return 0;
+}
>From 4dc3ec97617706526480fe671cdf2d32f508ac66 Mon Sep 17 00:00:00 2001
From: William Tran-Viet <wtranviet at proton.me>
Date: Mon, 26 Jan 2026 21:16:51 -0500
Subject: [PATCH 23/28] Make optional just wrap a pointer
---
libcxx/include/optional | 14 ++++++--------
1 file changed, 6 insertions(+), 8 deletions(-)
diff --git a/libcxx/include/optional b/libcxx/include/optional
index 1bbaa5910dd68..f5a3d415e724a 100644
--- a/libcxx/include/optional
+++ b/libcxx/include/optional
@@ -722,8 +722,8 @@ public:
using iterator = __bounded_iter<__wrap_iter<__pointer>>;
using const_iterator = __bounded_iter<__wrap_iter<__const_pointer>>;
# else
- using iterator = __capacity_aware_iterator<__wrap_iter<__pointer>, optional<_Tp>, 1>;
- using const_iterator = __capacity_aware_iterator<__wrap_iter<__const_pointer>, optional<_Tp>, 1>;
+ using iterator = __capacity_aware_iterator<__pointer, optional<_Tp>, 1>;
+ using const_iterator = __capacity_aware_iterator<__const_pointer, optional<_Tp>, 1>;
# endif
// [optional.iterators], iterator support
@@ -737,7 +737,7 @@ public:
__wrap_iter<__pointer>(__ptr),
__wrap_iter<__pointer>(__ptr) + (__derived_self.has_value() ? 1 : 0));
# else
- return std::__make_capacity_aware_iterator<__wrap_iter<__pointer>, optional<_Tp>, 1>(__wrap_iter<__pointer>(__ptr));
+ return std::__make_capacity_aware_iterator<__pointer, optional<_Tp>, 1>(__ptr);
# endif
}
@@ -751,8 +751,7 @@ public:
__wrap_iter<__const_pointer>(__ptr),
__wrap_iter<__const_pointer>(__ptr) + (__derived_self.has_value() ? 1 : 0));
# else
- return std::__make_capacity_aware_iterator<__wrap_iter<__const_pointer>, optional<_Tp>, 1>(
- __wrap_iter<__const_pointer>(__ptr));
+ return std::__make_capacity_aware_iterator<__const_pointer, optional<_Tp>, 1>(__ptr);
# endif
}
@@ -773,7 +772,7 @@ public:
# ifdef _LIBCPP_ABI_BOUNDED_ITERATORS_IN_OPTIONAL
using iterator = __bounded_iter<__wrap_iter<__pointer>>;
# else
- using iterator = __capacity_aware_iterator<__wrap_iter<__pointer>, optional<_Tp&>, 1>;
+ using iterator = __capacity_aware_iterator<__pointer, optional<_Tp&>, 1>;
# endif
// [optional.ref.iterators], iterator support
@@ -788,8 +787,7 @@ public:
__wrap_iter<__pointer>(__ptr),
__wrap_iter<__pointer>(__ptr) + (__derived_self.has_value() ? 1 : 0));
# else
- return std::__make_capacity_aware_iterator<__wrap_iter<__pointer>, optional<_Tp&>, 1>(
- __wrap_iter<__pointer>(__ptr));
+ return std::__make_capacity_aware_iterator<__pointer, optional<_Tp&>, 1>(__pointer(__ptr));
# endif
}
>From 2ddfddaec9c2932f18cd26ef738b27b62a129e47 Mon Sep 17 00:00:00 2001
From: William Tran-Viet <wtranviet at proton.me>
Date: Mon, 26 Jan 2026 21:17:51 -0500
Subject: [PATCH 24/28] Add noexcept tests
---
.../iterators/capacity_aware_iter/arithmetic.pass.cpp | 11 +++++++++++
.../iterators/capacity_aware_iter/comparison.pass.cpp | 8 ++++++++
.../capacity_aware_iter/dereference.pass.cpp | 4 ++++
3 files changed, 23 insertions(+)
diff --git a/libcxx/test/libcxx/iterators/capacity_aware_iter/arithmetic.pass.cpp b/libcxx/test/libcxx/iterators/capacity_aware_iter/arithmetic.pass.cpp
index ce577edb22967..2c8e8ba98f7db 100644
--- a/libcxx/test/libcxx/iterators/capacity_aware_iter/arithmetic.pass.cpp
+++ b/libcxx/test/libcxx/iterators/capacity_aware_iter/arithmetic.pass.cpp
@@ -29,6 +29,7 @@
#include <iterator>
#include "test_iterators.h"
+#include "test_macros.h"
template <typename Iter>
constexpr bool test() {
@@ -44,6 +45,7 @@ constexpr bool test() {
CapIter iter = std::__make_capacity_aware_iterator<Iter, decltype(arr), sz>(Iter(i));
CapIter& res = ++iter;
+ ASSERT_NOEXCEPT(*iter);
assert(&res == &iter);
assert(*iter == 2);
}
@@ -53,6 +55,7 @@ constexpr bool test() {
CapIter iter = std::__make_capacity_aware_iterator<Iter, decltype(arr), sz>(Iter(i));
CapIter res = iter++;
+ ASSERT_NOEXCEPT(iter++);
assert(*res == 1);
assert(*iter == 2);
}
@@ -62,6 +65,7 @@ constexpr bool test() {
CapIter iter = std::__make_capacity_aware_iterator<Iter, decltype(arr), sz>(Iter(i + 1));
CapIter& res = --iter;
+ ASSERT_NOEXCEPT(--iter);
assert(&iter == &res);
assert(*iter == 1);
}
@@ -71,6 +75,7 @@ constexpr bool test() {
CapIter iter = std::__make_capacity_aware_iterator<Iter, decltype(arr), sz>(Iter(i + 1));
CapIter res = iter--;
+ ASSERT_NOEXCEPT(iter--);
assert(*res == 2);
assert(*iter == 1);
}
@@ -80,6 +85,7 @@ constexpr bool test() {
CapIter iter = std::__make_capacity_aware_iterator<Iter, decltype(arr), sz>(Iter(i));
CapIter& res = iter += 2;
+ ASSERT_NOEXCEPT(iter += 2);
assert(&iter == &res);
assert(*iter == 3);
}
@@ -89,6 +95,7 @@ constexpr bool test() {
CapIter iter = std::__make_capacity_aware_iterator<Iter, decltype(arr), sz>(Iter(i));
CapIter res = iter + 2;
+ ASSERT_NOEXCEPT(iter + 2);
assert(*iter == 1);
assert(*res == 3);
}
@@ -98,6 +105,7 @@ constexpr bool test() {
CapIter iter = std::__make_capacity_aware_iterator<Iter, decltype(arr), sz>(Iter(i));
CapIter res = 2 + iter;
+ ASSERT_NOEXCEPT(2 + iter);
assert(*iter == 1);
assert(*res == 3);
}
@@ -107,6 +115,7 @@ constexpr bool test() {
CapIter iter = std::__make_capacity_aware_iterator<Iter, decltype(arr), sz>(Iter(i + 2));
CapIter& res = iter -= 2;
+ ASSERT_NOEXCEPT(iter -= 2);
assert(&iter == &res);
assert(*iter == 1);
}
@@ -116,6 +125,7 @@ constexpr bool test() {
CapIter iter = std::__make_capacity_aware_iterator<Iter, decltype(arr), sz>(Iter(i + 2));
CapIter res = iter - 2;
+ ASSERT_NOEXCEPT(iter - 2);
assert(*iter == 3);
assert(*res == 1);
}
@@ -128,6 +138,7 @@ constexpr bool test() {
std::ptrdiff_t res = iter2 - iter;
std::ptrdiff_t res2 = iter3 - iter;
+ ASSERT_NOEXCEPT(iter2 - iter);
assert(res == 2);
assert(res2 == 6);
}
diff --git a/libcxx/test/libcxx/iterators/capacity_aware_iter/comparison.pass.cpp b/libcxx/test/libcxx/iterators/capacity_aware_iter/comparison.pass.cpp
index cd9be482b1dcb..06ea099401297 100644
--- a/libcxx/test/libcxx/iterators/capacity_aware_iter/comparison.pass.cpp
+++ b/libcxx/test/libcxx/iterators/capacity_aware_iter/comparison.pass.cpp
@@ -26,6 +26,7 @@
#include <iterator>
#include "test_iterators.h"
+#include "test_macros.h"
template <typename Iter>
constexpr bool test() {
@@ -39,18 +40,21 @@ constexpr bool test() {
// operator==
{
+ ASSERT_NOEXCEPT(iter1 == iter2);
assert(iter1 == iter1);
assert(!(iter1 == iter2));
}
// operator!=
{
+ ASSERT_NOEXCEPT(iter1 != iter2);
assert(iter1 != iter2);
assert(!(iter1 != iter1));
}
// operator<
{
+ ASSERT_NOEXCEPT(iter1 < iter2);
assert(iter1 < iter2);
assert(!(iter1 < iter1));
assert(!(iter2 < iter1));
@@ -58,6 +62,7 @@ constexpr bool test() {
// operator<=
{
+ ASSERT_NOEXCEPT(iter1 <= iter2);
assert(iter1 <= iter2);
assert(iter1 <= iter1);
assert(!(iter2 <= iter1));
@@ -65,6 +70,7 @@ constexpr bool test() {
// operator>
{
+ ASSERT_NOEXCEPT(iter1 > iter2);
assert(iter2 > iter1);
assert(!(iter1 > iter2));
assert(!(iter1 > iter1));
@@ -72,6 +78,7 @@ constexpr bool test() {
// operator>=
{
+ ASSERT_NOEXCEPT(iter1 >= iter2);
assert(iter2 >= iter1);
assert(iter1 >= iter1);
assert(!(iter1 >= iter2));
@@ -79,6 +86,7 @@ constexpr bool test() {
// operator <=>
{
+ ASSERT_NOEXCEPT(iter1 <=> iter2);
std::same_as<std::strong_ordering> decltype(auto) r1 = iter1 <=> iter2;
assert(r1 == std::strong_ordering::less);
diff --git a/libcxx/test/libcxx/iterators/capacity_aware_iter/dereference.pass.cpp b/libcxx/test/libcxx/iterators/capacity_aware_iter/dereference.pass.cpp
index 284f697b6523a..e38c607e46dd0 100644
--- a/libcxx/test/libcxx/iterators/capacity_aware_iter/dereference.pass.cpp
+++ b/libcxx/test/libcxx/iterators/capacity_aware_iter/dereference.pass.cpp
@@ -20,6 +20,7 @@
#include <__iterator/capacity_aware_iterator.h>
#include "test_iterators.h"
+#include "test_macros.h"
struct Foo {
int x;
@@ -37,6 +38,7 @@ constexpr bool test() {
// operator[]
{
+ ASSERT_NOEXCEPT(it[0]);
assert(it[0] == Foo{1});
assert(it[1] == Foo{2});
assert(it[2] == Foo{3});
@@ -49,11 +51,13 @@ constexpr bool test() {
// operator*
{
+ ASSERT_NOEXCEPT(*it);
assert(*it == Foo{1});
}
// operator->
{
+ ASSERT_NOEXCEPT(it->x);
assert(it->x == 1);
}
>From 344da987f8b4040dcb9d58014936c1e6e197a02c Mon Sep 17 00:00:00 2001
From: William Tran-Viet <wtranviet at proton.me>
Date: Mon, 26 Jan 2026 21:18:04 -0500
Subject: [PATCH 25/28] Fix tests missing experimental lit flag
---
.../optional/optional.iterator/iterator.compile.pass.cpp | 2 +-
.../std/utilities/optional/optional.iterator/compare.pass.cpp | 1 +
2 files changed, 2 insertions(+), 1 deletion(-)
diff --git a/libcxx/test/libcxx/utilities/optional/optional.iterator/iterator.compile.pass.cpp b/libcxx/test/libcxx/utilities/optional/optional.iterator/iterator.compile.pass.cpp
index b6e407dacca42..d4d9f9a5961be 100644
--- a/libcxx/test/libcxx/utilities/optional/optional.iterator/iterator.compile.pass.cpp
+++ b/libcxx/test/libcxx/utilities/optional/optional.iterator/iterator.compile.pass.cpp
@@ -10,7 +10,7 @@
// <optional>
-// UNSUPPORTED: libcpp-has-abi-bounded-iterators-in-optional
+// UNSUPPORTED: libcpp-has-abi-bounded-iterators-in-optional, libcpp-has-no-experimental-optional-iterator
// template <class T> class optional::iterator;
// template <class T> class optional::const_iterator;
diff --git a/libcxx/test/std/utilities/optional/optional.iterator/compare.pass.cpp b/libcxx/test/std/utilities/optional/optional.iterator/compare.pass.cpp
index 2c27ecb4c9f7c..db56a8e191a33 100644
--- a/libcxx/test/std/utilities/optional/optional.iterator/compare.pass.cpp
+++ b/libcxx/test/std/utilities/optional/optional.iterator/compare.pass.cpp
@@ -7,6 +7,7 @@
//===----------------------------------------------------------------------===//
// REQUIRES: std-at-least-c++26
+// UNSUPPORTED: libcpp-has-no-experimental-optional-iterator
// <optional>
>From e9085453c47325fff8eb4887ed1d074ba6511a9e Mon Sep 17 00:00:00 2001
From: William Tran-Viet <wtranviet at proton.me>
Date: Fri, 30 Jan 2026 21:55:17 -0500
Subject: [PATCH 26/28] Remove pointer traits, fix comment
---
.../__iterator/capacity_aware_iterator.h | 22 ++------
.../pointer_traits.pass.cpp | 56 -------------------
2 files changed, 4 insertions(+), 74 deletions(-)
delete mode 100644 libcxx/test/libcxx/iterators/capacity_aware_iter/pointer_traits.pass.cpp
diff --git a/libcxx/include/__iterator/capacity_aware_iterator.h b/libcxx/include/__iterator/capacity_aware_iterator.h
index 1ea1b312611b0..fa4229ddf6af1 100644
--- a/libcxx/include/__iterator/capacity_aware_iterator.h
+++ b/libcxx/include/__iterator/capacity_aware_iterator.h
@@ -36,13 +36,12 @@ _LIBCPP_BEGIN_NAMESPACE_STD
// __capacity_aware_iterator is an iterator that wraps a contiguous iterator and encodes the maximum number of
// elements that can appear in a range of such iterators. That maximum number of elements must be known at compile-time.
+// As of writing, the only standard library containers which fulfill these requirements are inplace_vector and optional.
//
// It also embeds a tag type to prevent mixing iterators from e.g. different containers. This also allows for some
// algorithms to detect this iterator and perform optimizations based on the added semantic information.
-//
-// As of writing, the only standard library containers which fulfill the requirements are inplace_vector and optional.
-template <class _Iter, class _Tag, std::size_t _RangeMaxElements>
+template <class _Iter, class _Tag, size_t _RangeMaxElements>
class __capacity_aware_iterator {
private:
_Iter __iter_;
@@ -64,8 +63,6 @@ class __capacity_aware_iterator {
requires is_default_constructible_v<_Iter>
= default;
- friend struct pointer_traits<__capacity_aware_iterator<_Iter, _Tag, _RangeMaxElements>>;
-
template <typename _Iter2>
requires is_convertible_v<_Iter2, _Iter>
_LIBCPP_HIDE_FROM_ABI constexpr __capacity_aware_iterator(
@@ -106,7 +103,7 @@ class __capacity_aware_iterator {
_LIBCPP_HIDE_FROM_ABI constexpr __capacity_aware_iterator& operator+=(difference_type __n) noexcept {
_LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(
- static_cast<size_t>((__n >= 0 ? __n : -__n)) <= _RangeMaxElements,
+ static_cast<size_t>(__n >= 0 ? __n : -__n) <= _RangeMaxElements,
"__capacity_aware_iterator::operator+=: Attempting to move iterator past its container's possible range");
__iter_ += __n;
@@ -115,7 +112,7 @@ class __capacity_aware_iterator {
_LIBCPP_HIDE_FROM_ABI constexpr __capacity_aware_iterator& operator-=(difference_type __n) noexcept {
_LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(
- static_cast<size_t>((__n >= 0 ? __n : -__n)) <= _RangeMaxElements,
+ static_cast<size_t>(__n >= 0 ? __n : -__n) <= _RangeMaxElements,
"__capacity_aware_iterator::operator-=: Attempting to move iterator past its container's possible range");
__iter_ -= __n;
@@ -180,17 +177,6 @@ _LIBCPP_HIDE_FROM_ABI constexpr auto __make_capacity_aware_iterator(_It __iter)
return __capacity_aware_iterator<_It, _Tag2, _RangeMaxElems2>(__iter);
}
-template <class _Iter, class _Tag, std::size_t _RangeMaxElements>
-struct pointer_traits<__capacity_aware_iterator<_Iter, _Tag, _RangeMaxElements>> {
- using pointer = __capacity_aware_iterator<_Iter, _Tag, _RangeMaxElements>;
- using element_type = typename pointer_traits<_Iter>::element_type;
- using difference_type = typename pointer_traits<_Iter>::difference_type;
-
- _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR static element_type* to_address(pointer __it) _NOEXCEPT {
- return std::__to_address(__it.__iter_);
- }
-};
-
_LIBCPP_END_NAMESPACE_STD
#endif // _LIBCPP_STD_VER >= 26
diff --git a/libcxx/test/libcxx/iterators/capacity_aware_iter/pointer_traits.pass.cpp b/libcxx/test/libcxx/iterators/capacity_aware_iter/pointer_traits.pass.cpp
deleted file mode 100644
index b67aba6bc2739..0000000000000
--- a/libcxx/test/libcxx/iterators/capacity_aware_iter/pointer_traits.pass.cpp
+++ /dev/null
@@ -1,56 +0,0 @@
-//===----------------------------------------------------------------------===//
-//
-// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
-// See https://llvm.org/LICENSE.txt for license information.
-// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
-//
-//===----------------------------------------------------------------------===//
-
-// REQUIRES: std-at-least-c++26
-
-// template <class _Iterator, class _Container, class _ContainerMaxElements>
-// struct __capacity_aware_iterator;
-//
-// std::pointer_traits specialization
-
-#include <__iterator/capacity_aware_iterator.h>
-#include <cassert>
-#include <cstddef>
-#include <iterator>
-#include <memory>
-#include <type_traits>
-
-#include "test_iterators.h"
-#include "test_macros.h"
-
-template <class Iter>
-TEST_CONSTEXPR_CXX14 bool tests() {
- int array[] = {0, 1, 2, 3, 4};
-
- using CapIter = std::__capacity_aware_iterator<Iter, decltype(array), std::size(array)>;
- using PointerTraits = std::pointer_traits<CapIter>;
- using BasePointerTraits = std::pointer_traits<Iter>;
- static_assert(std::is_same_v<typename PointerTraits::pointer, CapIter>);
- static_assert(std::is_same_v<typename PointerTraits::element_type, typename BasePointerTraits::element_type>);
- static_assert(std::is_same_v<typename PointerTraits::difference_type, typename BasePointerTraits::difference_type>);
-
- {
- int* b = array + 0;
- int* e = array + 5;
- CapIter const iter1 = std::__make_capacity_aware_iterator<Iter, decltype(array), std::size(array)>(Iter(b));
- CapIter const iter2 = std::__make_capacity_aware_iterator<Iter, decltype(array), std::size(array)>(Iter(e));
- assert(std::to_address(iter1) == b); // in-bounds iterator
- assert(std::to_address(iter2) == e); // out-of-bounds iterator
- }
-
- return true;
-}
-
-int main(int, char**) {
- tests<int*>();
- static_assert(tests<int*>(), "");
- tests<contiguous_iterator<int*> >();
- static_assert(tests<contiguous_iterator<int*> >(), "");
-
- return 0;
-}
>From ad5afea75c6892094685c620e787171d097ee1d4 Mon Sep 17 00:00:00 2001
From: William Tran-Viet <wtranviet at proton.me>
Date: Fri, 30 Jan 2026 22:03:38 -0500
Subject: [PATCH 27/28] Address test comments
---
.../capacity_aware_iter/arithmetic.pass.cpp | 27 ++++++++++---------
.../capacity_aware_iter/comparison.pass.cpp | 21 ++++++++++-----
.../capacity_aware_iter/dereference.pass.cpp | 24 +++++++++++------
.../iterator.compile.pass.cpp | 2 ++
.../optional.iterator/compare.pass.cpp | 10 +++----
5 files changed, 51 insertions(+), 33 deletions(-)
diff --git a/libcxx/test/libcxx/iterators/capacity_aware_iter/arithmetic.pass.cpp b/libcxx/test/libcxx/iterators/capacity_aware_iter/arithmetic.pass.cpp
index 2c8e8ba98f7db..1aeb423101491 100644
--- a/libcxx/test/libcxx/iterators/capacity_aware_iter/arithmetic.pass.cpp
+++ b/libcxx/test/libcxx/iterators/capacity_aware_iter/arithmetic.pass.cpp
@@ -25,6 +25,7 @@
// operator-(__capacity_aware_iterator, __capacity_aware_iterator)
#include <__iterator/capacity_aware_iterator.h>
+#include <concepts>
#include <cstddef>
#include <iterator>
@@ -43,9 +44,9 @@ constexpr bool test() {
// operator++()
{
CapIter iter = std::__make_capacity_aware_iterator<Iter, decltype(arr), sz>(Iter(i));
- CapIter& res = ++iter;
+ std::same_as<CapIter&> decltype(auto) res = ++iter;
- ASSERT_NOEXCEPT(*iter);
+ ASSERT_NOEXCEPT(++iter);
assert(&res == &iter);
assert(*iter == 2);
}
@@ -53,7 +54,7 @@ constexpr bool test() {
// operator++(int)
{
CapIter iter = std::__make_capacity_aware_iterator<Iter, decltype(arr), sz>(Iter(i));
- CapIter res = iter++;
+ std::same_as<CapIter> decltype(auto) res = iter++;
ASSERT_NOEXCEPT(iter++);
assert(*res == 1);
@@ -63,7 +64,7 @@ constexpr bool test() {
// operator--()
{
CapIter iter = std::__make_capacity_aware_iterator<Iter, decltype(arr), sz>(Iter(i + 1));
- CapIter& res = --iter;
+ std::same_as<CapIter&> decltype(auto) res = --iter;
ASSERT_NOEXCEPT(--iter);
assert(&iter == &res);
@@ -73,7 +74,7 @@ constexpr bool test() {
// operator--(int)
{
CapIter iter = std::__make_capacity_aware_iterator<Iter, decltype(arr), sz>(Iter(i + 1));
- CapIter res = iter--;
+ std::same_as<CapIter> decltype(auto) res = iter--;
ASSERT_NOEXCEPT(iter--);
assert(*res == 2);
@@ -83,7 +84,7 @@ constexpr bool test() {
// operator+=(difference_type)
{
CapIter iter = std::__make_capacity_aware_iterator<Iter, decltype(arr), sz>(Iter(i));
- CapIter& res = iter += 2;
+ std::same_as<CapIter&> decltype(auto) res = iter += 2;
ASSERT_NOEXCEPT(iter += 2);
assert(&iter == &res);
@@ -93,7 +94,7 @@ constexpr bool test() {
// operator+(__capacity_aware_iterator, difference_type)
{
CapIter iter = std::__make_capacity_aware_iterator<Iter, decltype(arr), sz>(Iter(i));
- CapIter res = iter + 2;
+ std::same_as<CapIter> decltype(auto) res = iter + 2;
ASSERT_NOEXCEPT(iter + 2);
assert(*iter == 1);
@@ -103,7 +104,7 @@ constexpr bool test() {
// operator+(difference_type, __capacity_aware_iterator)
{
CapIter iter = std::__make_capacity_aware_iterator<Iter, decltype(arr), sz>(Iter(i));
- CapIter res = 2 + iter;
+ std::same_as<CapIter> decltype(auto) res = 2 + iter;
ASSERT_NOEXCEPT(2 + iter);
assert(*iter == 1);
@@ -113,7 +114,7 @@ constexpr bool test() {
// operator-=(difference_type)
{
CapIter iter = std::__make_capacity_aware_iterator<Iter, decltype(arr), sz>(Iter(i + 2));
- CapIter& res = iter -= 2;
+ std::same_as<CapIter&> decltype(auto) res = iter -= 2;
ASSERT_NOEXCEPT(iter -= 2);
assert(&iter == &res);
@@ -123,7 +124,7 @@ constexpr bool test() {
// operator-(__capacity_aware_iterator, difference_type)
{
CapIter iter = std::__make_capacity_aware_iterator<Iter, decltype(arr), sz>(Iter(i + 2));
- CapIter res = iter - 2;
+ std::same_as<CapIter> decltype(auto) res = iter - 2;
ASSERT_NOEXCEPT(iter - 2);
assert(*iter == 3);
@@ -135,8 +136,8 @@ constexpr bool test() {
CapIter iter = std::__make_capacity_aware_iterator<Iter, decltype(arr), sz>(Iter(i));
CapIter iter2 = std::__make_capacity_aware_iterator<Iter, decltype(arr), sz>(Iter(i + 2));
CapIter iter3 = std::__make_capacity_aware_iterator<Iter, decltype(arr), sz>(Iter(i + 6));
- std::ptrdiff_t res = iter2 - iter;
- std::ptrdiff_t res2 = iter3 - iter;
+ std::same_as<typename CapIter::difference_type> decltype(auto) res = iter2 - iter;
+ std::same_as<typename CapIter::difference_type> decltype(auto) res2 = iter3 - iter;
ASSERT_NOEXCEPT(iter2 - iter);
assert(res == 2);
@@ -147,7 +148,7 @@ constexpr bool test() {
}
int main(int, char**) {
- assert(test<contiguous_iterator<int*>>());
+ test<contiguous_iterator<int*>>();
static_assert(test<contiguous_iterator<int*>>());
return 0;
diff --git a/libcxx/test/libcxx/iterators/capacity_aware_iter/comparison.pass.cpp b/libcxx/test/libcxx/iterators/capacity_aware_iter/comparison.pass.cpp
index 06ea099401297..d1f396fb93777 100644
--- a/libcxx/test/libcxx/iterators/capacity_aware_iter/comparison.pass.cpp
+++ b/libcxx/test/libcxx/iterators/capacity_aware_iter/comparison.pass.cpp
@@ -23,6 +23,7 @@
#include <__iterator/capacity_aware_iterator.h>
#include <compare>
+#include <concepts>
#include <iterator>
#include "test_iterators.h"
@@ -40,48 +41,54 @@ constexpr bool test() {
// operator==
{
+ std::same_as<bool> decltype(auto) res = iter1 == iter1;
ASSERT_NOEXCEPT(iter1 == iter2);
- assert(iter1 == iter1);
+ assert(res);
assert(!(iter1 == iter2));
}
// operator!=
{
+ std::same_as<bool> decltype(auto) res = iter1 != iter2;
ASSERT_NOEXCEPT(iter1 != iter2);
- assert(iter1 != iter2);
+ assert(res);
assert(!(iter1 != iter1));
}
// operator<
{
+ std::same_as<bool> decltype(auto) res = iter1 < iter2;
ASSERT_NOEXCEPT(iter1 < iter2);
- assert(iter1 < iter2);
+ assert(res);
assert(!(iter1 < iter1));
assert(!(iter2 < iter1));
}
// operator<=
{
+ std::same_as<bool> decltype(auto) res = iter1 <= iter2;
ASSERT_NOEXCEPT(iter1 <= iter2);
- assert(iter1 <= iter2);
+ assert(res);
assert(iter1 <= iter1);
assert(!(iter2 <= iter1));
}
// operator>
{
+ std::same_as<bool> decltype(auto) res = iter1 > iter2;
ASSERT_NOEXCEPT(iter1 > iter2);
assert(iter2 > iter1);
- assert(!(iter1 > iter2));
+ assert(!res);
assert(!(iter1 > iter1));
}
// operator>=
{
+ std::same_as<bool> decltype(auto) res = iter1 >= iter2;
ASSERT_NOEXCEPT(iter1 >= iter2);
assert(iter2 >= iter1);
assert(iter1 >= iter1);
- assert(!(iter1 >= iter2));
+ assert(!res);
}
// operator <=>
@@ -102,7 +109,7 @@ constexpr bool test() {
}
int main(int, char**) {
- assert(test<contiguous_iterator<int*>>());
+ test<contiguous_iterator<int*>>();
static_assert(test<contiguous_iterator<int*>>());
return 0;
diff --git a/libcxx/test/libcxx/iterators/capacity_aware_iter/dereference.pass.cpp b/libcxx/test/libcxx/iterators/capacity_aware_iter/dereference.pass.cpp
index e38c607e46dd0..ff7d4b53b071a 100644
--- a/libcxx/test/libcxx/iterators/capacity_aware_iter/dereference.pass.cpp
+++ b/libcxx/test/libcxx/iterators/capacity_aware_iter/dereference.pass.cpp
@@ -18,6 +18,7 @@
// operator->();
#include <__iterator/capacity_aware_iterator.h>
+#include <concepts>
#include "test_iterators.h"
#include "test_macros.h"
@@ -38,34 +39,41 @@ constexpr bool test() {
// operator[]
{
+ std::same_as<Foo&> decltype(auto) res = it[0];
ASSERT_NOEXCEPT(it[0]);
- assert(it[0] == Foo{1});
- assert(it[1] == Foo{2});
- assert(it[2] == Foo{3});
+ assert(res == arr[0]);
+ assert(&res == &arr[0]);
+ assert(it[1] == arr[1]);
+ assert(it[2] == arr[2]);
CapIter it2 = it + 2;
- assert(it2[-1] == Foo{2});
- assert(it2[-2] == Foo{1});
+ assert(it2[-1] == arr[1]);
+ assert(it2[-2] == arr[0]);
}
// operator*
{
+ std::same_as<Foo&> decltype(auto) res = *it;
ASSERT_NOEXCEPT(*it);
- assert(*it == Foo{1});
+ assert(*it == arr[0]);
+ assert(&res == &arr[0]);
+ assert(&res == &(*it));
}
// operator->
{
+ std::same_as<Foo*> decltype(auto) ptr = it.operator->();
ASSERT_NOEXCEPT(it->x);
- assert(it->x == 1);
+ assert(ptr->x == 1);
+ assert(ptr == &arr[0]);
}
return true;
}
int main(int, char**) {
- assert(test<three_way_contiguous_iterator<Foo*>>());
+ test<three_way_contiguous_iterator<Foo*>>();
static_assert(test<three_way_contiguous_iterator<Foo*>>());
return 0;
diff --git a/libcxx/test/libcxx/utilities/optional/optional.iterator/iterator.compile.pass.cpp b/libcxx/test/libcxx/utilities/optional/optional.iterator/iterator.compile.pass.cpp
index d4d9f9a5961be..265d39c97cb39 100644
--- a/libcxx/test/libcxx/utilities/optional/optional.iterator/iterator.compile.pass.cpp
+++ b/libcxx/test/libcxx/utilities/optional/optional.iterator/iterator.compile.pass.cpp
@@ -12,6 +12,8 @@
// UNSUPPORTED: libcpp-has-abi-bounded-iterators-in-optional, libcpp-has-no-experimental-optional-iterator
+// Ensure that a std::optional<T>::iterator can only be converted to a std::optional<T>::iterator.
+
// template <class T> class optional::iterator;
// template <class T> class optional::const_iterator;
diff --git a/libcxx/test/std/utilities/optional/optional.iterator/compare.pass.cpp b/libcxx/test/std/utilities/optional/optional.iterator/compare.pass.cpp
index db56a8e191a33..4c48c54df3257 100644
--- a/libcxx/test/std/utilities/optional/optional.iterator/compare.pass.cpp
+++ b/libcxx/test/std/utilities/optional/optional.iterator/compare.pass.cpp
@@ -42,8 +42,8 @@ constexpr bool test() {
assert(it1 == it2);
assert(!(it1 != it2));
- static_assert(std::same_as<decltype(it1 <=> it2), std::strong_ordering>);
- assert(it1 <=> it2 == std::strong_ordering::equal);
+ std::same_as<std::strong_ordering> decltype(auto) spaceship = it1 <=> it2;
+ assert(spaceship == std::strong_ordering::equal);
}
{
@@ -65,8 +65,8 @@ constexpr bool test() {
assert(cit1 == cit2);
assert(!(cit1 != cit2));
- static_assert(std::same_as<decltype(cit1 <=> cit2), std::strong_ordering>);
- assert(cit1 <=> cit2 == std::strong_ordering::equal);
+ std::same_as<std::strong_ordering> decltype(auto) spaceship = cit1 <=> cit2;
+ assert(spaceship == std::strong_ordering::equal);
}
{
@@ -93,7 +93,7 @@ constexpr bool test() {
}
int main(int, char**) {
- assert(test());
+ test();
static_assert(test());
return 0;
>From cd68608eb3729031d8c9c387422328e1e7f1c8d1 Mon Sep 17 00:00:00 2001
From: William Tran-Viet <wtranviet at proton.me>
Date: Fri, 30 Jan 2026 22:47:01 -0500
Subject: [PATCH 28/28] Remove another std::
---
libcxx/include/__iterator/capacity_aware_iterator.h | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/libcxx/include/__iterator/capacity_aware_iterator.h b/libcxx/include/__iterator/capacity_aware_iterator.h
index fa4229ddf6af1..4fbe2a6028175 100644
--- a/libcxx/include/__iterator/capacity_aware_iterator.h
+++ b/libcxx/include/__iterator/capacity_aware_iterator.h
@@ -46,7 +46,7 @@ class __capacity_aware_iterator {
private:
_Iter __iter_;
- template <class, class, std::size_t>
+ template <class, class, size_t>
friend class __capacity_aware_iterator;
public:
More information about the libcxx-commits
mailing list