[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
Wed Jan 14 19:34:57 PST 2026
https://github.com/smallp-o-p updated https://github.com/llvm/llvm-project/pull/154239
>From 8cec4dbbede31678f40344b23885156345aebe4e 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/19] 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 568c86556d156..efd5bbfe517de 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>
@@ -711,13 +711,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
@@ -726,12 +730,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
}
@@ -740,12 +744,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 a4d20157903b365900b942d2713a1ba5d1eaaead 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/19] 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 1be86305b449c..996811d078b86 100644
--- a/libcxx/test/std/utilities/optional/optional.iterator/iterator.pass.cpp
+++ b/libcxx/test/std/utilities/optional/optional.iterator/iterator.pass.cpp
@@ -98,6 +98,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 e02bec6d3278a79204fc31ce96f6ed9ddd0b02a1 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/19] 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 032cac20260c82917777cb4bd891f42a9119b510 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/19] 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 074e062ea79841ab2d4220c6e2b4a757024a619f 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/19] 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 efd5bbfe517de..2032869f9d466 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>
@@ -713,7 +713,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 63c5f489e941dc08e755ae680c1ac05da3132794 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/19] 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 2032869f9d466..e586c4a4bca16 100644
--- a/libcxx/include/optional
+++ b/libcxx/include/optional
@@ -717,8 +717,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>>;
@@ -730,10 +730,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
@@ -744,10 +744,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 09c0a2128e305a7aa9426baea4c0592a7c6ab3ab 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/19] 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 f79a016e948ef557007ad654253832f6965a2e6c 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/19] 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 01ec05d3717c5959abbf608f8f0c31ff59b3ebda 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/19] 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 b3c9b84eeb1990fcf4ec0723c39f08c8278af693 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/19] 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 3bb2d8b17a602294834fe35841455a692a295a5a 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/19] 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 651795918662140488d892d5b3f03e5c80fe32fc 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/19] 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 965e9219bd10ab3d70bac9bb31f12610565fef47 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/19] 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 cc878ec37b4536613e76ca6e2ecd806d44f71707 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/19] 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 da5678185999cc942ba95bba16d1928c680c56b4 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/19] 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 123ee684a930ce1ff87589743e1da2a21b257875 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/19] 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 ba73e83c82691384f27eb017f4a93994fb35fddc 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/19] 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 ee1c575bb866b21630aba2a430103f771a489d55 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/19] 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 e586c4a4bca16..d42c6455b9452 100644
--- a/libcxx/include/optional
+++ b/libcxx/include/optional
@@ -711,7 +711,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>;
@@ -764,13 +763,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
@@ -785,7 +787,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 8186639811f50b99230d353b2267a31bf9b1f1d4 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/19] 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 d42c6455b9452..1d4d51becd158 100644
--- a/libcxx/include/optional
+++ b/libcxx/include/optional
@@ -711,16 +711,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
@@ -734,7 +731,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
}
@@ -748,7 +746,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
}
@@ -763,16 +762,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
@@ -787,7 +783,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;
}
More information about the libcxx-commits
mailing list