[libcxx-commits] [libcxx] [libc++] Add compact bounded specialization for capacity_aware_iterator (PR #208271)

William Tran-Viet via libcxx-commits libcxx-commits at lists.llvm.org
Fri Jul 10 11:50:26 PDT 2026


https://github.com/smallp-o-p updated https://github.com/llvm/llvm-project/pull/208271

>From 8496aed34b30e0c706852d0115b2f92dfbc97148 Mon Sep 17 00:00:00 2001
From: William Tran-Viet <wtranviet at proton.me>
Date: Mon, 29 Jun 2026 23:18:11 -0400
Subject: [PATCH 1/6] [libc++] Add bounded specialization for
 capacity_aware_iterator

- By taking advantage of unused alignment bits for a pointer of type T and the static capacity known at compile time,
  we can make a compact bounded iterator who's size == sizeof(T*) by stuffing a counter inside those bits.
- This overload only applies in the following situation:
  - Iter is a pointer
  - The capacity is <= (1 << (bit_width(alignof(T)) - 1)) - 1. The extra -1 is required, because we need to represent
    the end position past the last element.
---
 .../__iterator/capacity_aware_iterator.h      | 226 ++++++++++++++++++
 .../capacity_aware_iter/arithmetic.pass.cpp   |  10 +-
 .../capacity_aware_iter/assert.pass.cpp       |  58 ++++-
 .../capacity_aware_iter/comparison.pass.cpp   |   7 +-
 .../capacity_aware_iter/dereference.pass.cpp  |  19 +-
 .../types.compile.pass.cpp                    |  11 +
 6 files changed, 318 insertions(+), 13 deletions(-)

diff --git a/libcxx/include/__iterator/capacity_aware_iterator.h b/libcxx/include/__iterator/capacity_aware_iterator.h
index a516feef60f36..fa394e227e774 100644
--- a/libcxx/include/__iterator/capacity_aware_iterator.h
+++ b/libcxx/include/__iterator/capacity_aware_iterator.h
@@ -11,6 +11,8 @@
 #define _LIBCPP___CAPACITY_AWARE_ITERATOR_H
 
 #include <__assert>
+#include <__bit/bit_cast.h>
+#include <__bit/countr.h>
 #include <__compare/ordering.h>
 #include <__compare/three_way_comparable.h>
 #include <__config>
@@ -21,8 +23,12 @@
 #include <__memory/pointer_traits.h>
 #include <__type_traits/is_constructible.h>
 #include <__type_traits/is_convertible.h>
+#include <__type_traits/is_pointer.h>
+#include <__utility/declval.h>
 #include <__utility/move.h>
 
+#include <cstdint>
+
 #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
 #  pragma GCC system_header
 #endif
@@ -51,6 +57,7 @@ class __capacity_aware_iterator {
 
 public:
   static_assert(contiguous_iterator<_Iter>, "__capacity_aware_iterator can only be used with contiguous iterators");
+  constexpr static bool __can_track_count_ = false;
 
   using iterator_category = iterator_traits<_Iter>::iterator_category;
   using iterator_concept  = contiguous_iterator_tag;
@@ -172,6 +179,225 @@ class __capacity_aware_iterator {
   }
 };
 
+template <class _Tp>
+consteval bool __range_fits_in_alignment(std::size_t __num_elems) {
+  auto __bits = std::countr_zero(alignof(_Tp));
+
+  // Example: For alignof(T) == 4, we have two bits free, which has a range of 0-3. We need to
+  // reserve one for the end position, so __num_elems must be < 3.
+  auto __allowed_range = (1 << __bits) - 1;
+  return __allowed_range > __num_elems;
+}
+
+// A specialization of capacity_aware_iterator where we store a runtime count of the current position inside
+// the unused bottom bits of a pointer to T. Only applies if capacity can fit inside those bits.
+template <class _Iter, class _Tag, size_t _RangeMaxElements>
+  requires(std::is_pointer_v<_Iter> &&
+           std::__range_fits_in_alignment<decltype(* std::declval<_Iter>())>(_RangeMaxElements))
+class __capacity_aware_iterator<_Iter, _Tag, _RangeMaxElements> {
+  constexpr static std::size_t __bits_ = std::countr_zero(alignof(decltype(*std::declval<_Iter>())));
+
+  union {
+    _Iter __ptr_;
+    std::uintptr_t __current_ : __bits_;
+  };
+
+  template <class, class, size_t>
+  friend class __capacity_aware_iterator;
+
+public:
+  constexpr static bool __can_track_count_ = false;
+
+  using iterator_category = iterator_traits<_Iter>::iterator_category;
+  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>;
+  using value_type        = iter_value_t<_Iter>;
+
+  constexpr __capacity_aware_iterator()
+    requires is_default_constructible_v<_Iter>
+  = default;
+
+  template <typename _Iter2>
+    requires is_convertible_v<_Iter2, _Iter>
+  constexpr __capacity_aware_iterator(const __capacity_aware_iterator<_Iter2, _Tag, _RangeMaxElements>& __y) noexcept
+      : __ptr_(__y.__ptr_) {
+    if !consteval {
+      __current_ = __y.__current_;
+    }
+  }
+
+  template <class _It, class _Tag2, size_t _RangeMaxElems2>
+  friend constexpr auto __make_capacity_aware_iterator(_It __iter) noexcept;
+
+private:
+  constexpr explicit __capacity_aware_iterator(_Iter __iter) : __ptr_(std::move(__iter)) {
+    if !consteval {
+      __current_ = 0u;
+    }
+  }
+
+  constexpr _Iter __curr_iter() const {
+    if consteval {
+      return __ptr_;
+    }
+
+    return std::bit_cast<_Iter>((std::bit_cast<std::uintptr_t>(__ptr_) >> __bits_) << __bits_) + __current_;
+  }
+
+  constexpr void __update(difference_type __n) {
+    if consteval {
+      __ptr_ += __n;
+    } else {
+      __current_ += __n;
+    }
+  }
+
+public:
+  [[nodiscard]] constexpr decltype(auto) operator*() const noexcept {
+    if !consteval {
+      _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(
+          __current_ < _RangeMaxElements,
+          "__capacity_aware_iterator::operator*: Attempt to dereference an iterator at the end");
+    }
+
+    return *(__curr_iter());
+  }
+
+  constexpr decltype(auto) operator->() const noexcept {
+    if !consteval {
+      _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(
+          __current_ < _RangeMaxElements,
+          "__capacity_aware_iterator::operator->: Attempt to dereference an iterator at the end");
+    }
+
+    return __curr_iter();
+  }
+
+  constexpr __capacity_aware_iterator& operator++() noexcept {
+    if !consteval {
+      _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(
+          __current_ != _RangeMaxElements,
+          "__capacity_aware_iterator::operator++: Attempt to advance an iterator past the end");
+    }
+
+    __update(1);
+
+    return *this;
+  }
+
+  constexpr __capacity_aware_iterator operator++(int) noexcept {
+    __capacity_aware_iterator __tmp(*this);
+    ++*this;
+    return __tmp;
+  }
+
+  constexpr __capacity_aware_iterator& operator--() noexcept {
+    if !consteval {
+      _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(
+          __current_ != 0u, "__capacity_aware_iterator::operator--: Attempt to rewind an iterator past the start");
+    }
+
+    __update(-1);
+
+    return *this;
+  }
+
+  constexpr __capacity_aware_iterator operator--(int) noexcept {
+    __capacity_aware_iterator __tmp(*this);
+    --*this;
+    return __tmp;
+  }
+
+  constexpr __capacity_aware_iterator& operator+=(difference_type __n) noexcept {
+    if !consteval {
+      _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(
+          (static_cast<difference_type>(__current_) + __n) >= 0,
+          "__capacity_aware_iterator::operator+=: Attempt to rewind iterator past the start");
+      _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(
+          static_cast<std::size_t>(__current_ + __n) <= _RangeMaxElements,
+          "__capacity_aware_iterator::operator+=: Attempt to advance an iterator past the end");
+    }
+
+    __update(__n);
+
+    return *this;
+  }
+
+  constexpr __capacity_aware_iterator& operator-=(difference_type __n) noexcept {
+    if !consteval {
+      _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(
+          (static_cast<difference_type>(__current_) - __n) >= 0,
+          "__capacity_aware_iterator::operator-=: Attempt to rewind an iterator past the start");
+      _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(
+          static_cast<std::size_t>(__current_ - __n) <= _RangeMaxElements,
+          "__capacity_aware_iterator::operator-=: Attempt to advance an iterator past the end");
+    }
+
+    __update(-__n);
+
+    return *this;
+  }
+
+  [[nodiscard]] constexpr decltype(auto) operator[](difference_type __n) const noexcept {
+    if !consteval {
+      _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(
+          (static_cast<difference_type>(__current_) + __n) >= 0,
+          "__capacity_aware_iterator::operator[]: Attempt to index an iterator past the start");
+      _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(
+          static_cast<std::size_t>(__current_ + __n) <= _RangeMaxElements,
+          "__capacity_aware_iterator::operator[]: Attempt to index an iterator past the end");
+    }
+    return *(*this + __n);
+  }
+
+  friend constexpr bool
+  operator==(const __capacity_aware_iterator& __x, const __capacity_aware_iterator& __y) noexcept {
+    return __x.__curr_iter() == __y.__curr_iter();
+  }
+
+  friend constexpr auto
+  operator<=>(const __capacity_aware_iterator& __x, const __capacity_aware_iterator& __y) noexcept {
+    if constexpr (three_way_comparable_with<_Iter, _Iter, strong_ordering>) {
+      return __x.__curr_iter() <=> __y.__curr_iter();
+    } else {
+      if (__x.__curr_iter() < __y.__curr_iter()) {
+        return strong_ordering::less;
+      } else if (__x.__curr_iter() == __y.__curr_iter()) {
+        return strong_ordering::equal;
+      }
+      return strong_ordering::greater;
+    }
+  }
+
+  [[nodiscard]] friend constexpr __capacity_aware_iterator
+  operator+(const __capacity_aware_iterator& __i, difference_type __n) noexcept {
+    auto __tmp = __i;
+    __tmp += __n;
+    return __tmp;
+  }
+
+  [[nodiscard]] friend constexpr __capacity_aware_iterator
+  operator+(difference_type __n, const __capacity_aware_iterator& __i) noexcept {
+    auto __tmp = __i;
+    __tmp += __n;
+    return __tmp;
+  }
+
+  [[nodiscard]] friend constexpr __capacity_aware_iterator
+  operator-(const __capacity_aware_iterator& __i, difference_type __n) noexcept {
+    auto __tmp = __i;
+    __tmp -= __n;
+    return __tmp;
+  }
+
+  [[nodiscard]] friend constexpr difference_type
+  operator-(const __capacity_aware_iterator& __x, const __capacity_aware_iterator& __y) noexcept {
+    return difference_type(__x.__curr_iter() - __y.__curr_iter());
+  }
+};
+
 template <class _It, class _Tag2, size_t _RangeMaxElems2>
 _LIBCPP_HIDE_FROM_ABI constexpr auto __make_capacity_aware_iterator(_It __iter) noexcept {
   return __capacity_aware_iterator<_It, _Tag2, _RangeMaxElems2>(__iter);
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 f4aa5c29790ff..59a1e080d4d37 100644
--- a/libcxx/test/libcxx/iterators/capacity_aware_iter/arithmetic.pass.cpp
+++ b/libcxx/test/libcxx/iterators/capacity_aware_iter/arithmetic.pass.cpp
@@ -33,14 +33,14 @@
 #include "test_iterators.h"
 #include "test_macros.h"
 
-template <typename Iter>
+template <typename Iter, typename Ty = int>
 constexpr bool test() {
-  int arr[]           = {1, 2, 3, 4, 5, 6};
+  Ty 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;
+  Ty* i = arr + 0;
 
   // operator++()
   {
@@ -162,5 +162,9 @@ int main(int, char**) {
   test<contiguous_iterator<int*>>();
   static_assert(test<contiguous_iterator<int*>>());
 
+  // bounded overload
+  test<long*, long>();
+  static_assert(test<long*, long>());
+
   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 ceac20d549c34..ed0d29f0cbcef 100644
--- a/libcxx/test/libcxx/iterators/capacity_aware_iter/assert.pass.cpp
+++ b/libcxx/test/libcxx/iterators/capacity_aware_iter/assert.pass.cpp
@@ -13,13 +13,64 @@
 // struct __capacity_aware_iterator;
 
 // Check assert failure if advancing, rewinding or indexing iterator past its maximum range size
+// Or if we're keeping track of the current position, if we're advancing, rewinding, indexing out of bounds.
 
 #include <__iterator/capacity_aware_iterator.h>
 #include <iterator>
 
 #include "check_assertion.h"
-#include "test_iterators.h"
-#include "test_macros.h"
+
+// Specialization where we can fit a running count inside unused alignment bits.
+template <typename Iter>
+void test_bounded() {
+  int arr[] = {1, 2};
+  int* p    = arr;
+
+  constexpr long sz = std::size(arr);
+
+  using CapIter = std::__capacity_aware_iterator<Iter, decltype(p), sz>;
+
+  CapIter it = std::__make_capacity_aware_iterator<Iter, decltype(p), sz>(Iter(arr));
+
+  TEST_LIBCPP_ASSERT_FAILURE(it--, "__capacity_aware_iterator::operator--: Attempt to rewind iterator past the start");
+
+  TEST_LIBCPP_ASSERT_FAILURE(
+      it -= 1, "__capacity_aware_iterator::operator-=: Attempt to rewind iterator past the start");
+
+  TEST_LIBCPP_ASSERT_FAILURE(
+      it += -1, "__capacity_aware_iterator::operator+=: Attempt to rewind iterator past the start");
+
+  TEST_LIBCPP_ASSERT_FAILURE(
+      it += (sz + 1), "__capacity_aware_iterator::operator+=: Attempt to advance an iterator past the end");
+
+  TEST_LIBCPP_ASSERT_FAILURE(
+      it += -(sz + 1), "__capacity_aware_iterator::operator+=: Attempt to rewind iterator past the start");
+
+  TEST_LIBCPP_ASSERT_FAILURE(
+      it -= (sz + 1), "__capacity_aware_iterator::operator-=: Attempt to rewind an iterator past the start");
+
+  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[]: Attempt to index an iterator past the end");
+
+  TEST_LIBCPP_ASSERT_FAILURE(
+      it[-sz], "__capacity_aware_iterator::operator[]: Attempt to index an iterator past the start");
+
+  ++it;
+  ++it;
+
+  TEST_LIBCPP_ASSERT_FAILURE(
+      *it, "__capacity_aware_iterator::operator*: Attempt to dereference an iterator at the end");
+
+  TEST_LIBCPP_ASSERT_FAILURE(
+      it.operator->(), "__capacity_aware_iterator::operator->: Attempt to dereference an iterator at the end");
+
+  TEST_LIBCPP_ASSERT_FAILURE(
+      ++it, "__capacity_aware_iterator::operator++: Attempt to advance an iterator past the end");
+}
 
 template <typename Iter>
 void test() {
@@ -57,7 +108,8 @@ void test() {
 }
 
 int main(int, char**) {
-  test<contiguous_iterator<int*>>();
+  test_bounded<int*>();
+  test<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 34aa73bf4459c..a7f3ae44fa5ee 100644
--- a/libcxx/test/libcxx/iterators/capacity_aware_iter/comparison.pass.cpp
+++ b/libcxx/test/libcxx/iterators/capacity_aware_iter/comparison.pass.cpp
@@ -30,9 +30,9 @@
 #include "test_iterators.h"
 #include "test_macros.h"
 
-template <typename Iter>
+template <typename Iter, typename Ty = int>
 constexpr bool test() {
-  int arr[]         = {1, 2, 3, 4};
+  Ty arr[]          = {1, 2, 3, 4};
   constexpr long sz = std::size(arr);
 
   using CapIter = std::__capacity_aware_iterator<Iter, decltype(arr), sz>;
@@ -113,5 +113,8 @@ int main(int, char**) {
   test<contiguous_iterator<int*>>();
   static_assert(test<contiguous_iterator<int*>>());
 
+  test<long*, long>();
+  static_assert(test<long*, long>());
+
   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 42ab763896e2f..910078db4a7d4 100644
--- a/libcxx/test/libcxx/iterators/capacity_aware_iter/dereference.pass.cpp
+++ b/libcxx/test/libcxx/iterators/capacity_aware_iter/dereference.pass.cpp
@@ -30,9 +30,14 @@ struct Foo {
   constexpr bool operator==(Foo const& other) const { return x == other.x; }
 };
 
-template <typename Iter>
+struct Foo2 {
+  long x;
+  constexpr bool operator==(Foo2 const& other) const { return x == other.x; }
+};
+
+template <typename Iter, typename Ty = Foo>
 constexpr bool test() {
-  Foo arr[]         = {Foo{1}, Foo{2}, Foo{3}, Foo{4}};
+  Ty arr[]          = {Ty{1}, Ty{2}, Ty{3}, Ty{4}};
   constexpr long sz = std::size(arr);
 
   using CapIter = std::__capacity_aware_iterator<Iter, decltype(arr), sz>;
@@ -41,7 +46,7 @@ constexpr bool test() {
 
   // operator[]
   {
-    std::same_as<Foo&> decltype(auto) res = it[0];
+    std::same_as<Ty&> decltype(auto) res = it[0];
     ASSERT_NOEXCEPT(it[0]);
     assert(res == arr[0]);
     assert(&res == &arr[0]);
@@ -56,7 +61,7 @@ constexpr bool test() {
 
   // operator*
   {
-    std::same_as<Foo&> decltype(auto) res = *it;
+    std::same_as<Ty&> decltype(auto) res = *it;
     ASSERT_NOEXCEPT(*it);
     assert(*it == arr[0]);
     assert(&res == &arr[0]);
@@ -65,7 +70,7 @@ constexpr bool test() {
 
   // operator->
   {
-    std::same_as<Foo*> decltype(auto) ptr = it.operator->();
+    std::same_as<Ty*> decltype(auto) ptr = it.operator->();
     ASSERT_NOEXCEPT(it->x);
     assert(ptr->x == 1);
     assert(ptr == &arr[0]);
@@ -78,5 +83,9 @@ int main(int, char**) {
   test<three_way_contiguous_iterator<Foo*>>();
   static_assert(test<three_way_contiguous_iterator<Foo*>>());
 
+  // bounded overload
+  test<Foo2*, Foo2>();
+  static_assert(test<Foo2*, Foo2>());
+
   return 0;
 }
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 b3b72a0728ed7..37680d0e7c859 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
@@ -29,3 +29,14 @@ 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>>);
+
+// bounded overload
+using It2      = long*;
+using CapIter2 = std::__capacity_aware_iterator<It2, long[6], 126>;
+
+static_assert(std::is_same_v<CapIter2::iterator_category, std::iterator_traits<It2>::iterator_category>);
+static_assert(std::is_same_v<CapIter2::iterator_concept, std::contiguous_iterator_tag>);
+static_assert(std::is_same_v<CapIter2::difference_type, std::iter_difference_t<It2>>);
+static_assert(std::is_same_v<CapIter2::reference, std::iter_reference_t<It2>>);
+static_assert(std::is_same_v<CapIter2::reference, std::iter_reference_t<It2>>);
+static_assert(std::is_same_v<CapIter2::value_type, std::iter_value_t<It2>>);

>From 4b70812bcf012fabbd792444e575dd70eca2ce04 Mon Sep 17 00:00:00 2001
From: William Tran-Viet <wtranviet at proton.me>
Date: Wed, 8 Jul 2026 16:12:17 -0400
Subject: [PATCH 2/6] Fix

---
 .../include/__iterator/capacity_aware_iterator.h   |  6 +++---
 .../capacity_aware_iter/arithmetic.pass.cpp        | 12 ++++++++----
 .../iterators/capacity_aware_iter/assert.pass.cpp  | 14 +++++++-------
 3 files changed, 18 insertions(+), 14 deletions(-)

diff --git a/libcxx/include/__iterator/capacity_aware_iterator.h b/libcxx/include/__iterator/capacity_aware_iterator.h
index fa394e227e774..442d9c4d2a561 100644
--- a/libcxx/include/__iterator/capacity_aware_iterator.h
+++ b/libcxx/include/__iterator/capacity_aware_iterator.h
@@ -314,7 +314,7 @@ class __capacity_aware_iterator<_Iter, _Tag, _RangeMaxElements> {
     if !consteval {
       _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(
           (static_cast<difference_type>(__current_) + __n) >= 0,
-          "__capacity_aware_iterator::operator+=: Attempt to rewind iterator past the start");
+          "__capacity_aware_iterator::operator+=: Attempt to rewind an iterator past the start");
       _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(
           static_cast<std::size_t>(__current_ + __n) <= _RangeMaxElements,
           "__capacity_aware_iterator::operator+=: Attempt to advance an iterator past the end");
@@ -346,8 +346,8 @@ class __capacity_aware_iterator<_Iter, _Tag, _RangeMaxElements> {
           (static_cast<difference_type>(__current_) + __n) >= 0,
           "__capacity_aware_iterator::operator[]: Attempt to index an iterator past the start");
       _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(
-          static_cast<std::size_t>(__current_ + __n) <= _RangeMaxElements,
-          "__capacity_aware_iterator::operator[]: Attempt to index an iterator past the end");
+          static_cast<std::size_t>(__current_ + __n) < _RangeMaxElements,
+          "__capacity_aware_iterator::operator[]: Attempt to index an iterator at or past the end");
     }
     return *(*this + __n);
   }
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 59a1e080d4d37..d46bb4d3e8bec 100644
--- a/libcxx/test/libcxx/iterators/capacity_aware_iter/arithmetic.pass.cpp
+++ b/libcxx/test/libcxx/iterators/capacity_aware_iter/arithmetic.pass.cpp
@@ -66,7 +66,8 @@ constexpr bool test() {
 
   // operator--()
   {
-    CapIter iter = std::__make_capacity_aware_iterator<Iter, decltype(arr), sz>(Iter(i + 1));
+    CapIter iter = std::__make_capacity_aware_iterator<Iter, decltype(arr), sz>(Iter(i));
+    ++iter;
 
     std::same_as<CapIter&> decltype(auto) res = --iter;
 
@@ -77,7 +78,8 @@ constexpr bool test() {
 
   // operator--(int)
   {
-    CapIter iter = std::__make_capacity_aware_iterator<Iter, decltype(arr), sz>(Iter(i + 1));
+    CapIter iter = std::__make_capacity_aware_iterator<Iter, decltype(arr), sz>(Iter(i));
+    ++iter;
 
     std::same_as<CapIter> decltype(auto) res = iter--;
 
@@ -121,7 +123,8 @@ constexpr bool test() {
 
   // operator-=(difference_type)
   {
-    CapIter iter = std::__make_capacity_aware_iterator<Iter, decltype(arr), sz>(Iter(i + 2));
+    CapIter iter = std::__make_capacity_aware_iterator<Iter, decltype(arr), sz>(Iter(i));
+    iter += 2;
 
     std::same_as<CapIter&> decltype(auto) res = iter -= 2;
 
@@ -132,7 +135,8 @@ constexpr bool test() {
 
   // operator-(__capacity_aware_iterator, difference_type)
   {
-    CapIter iter = std::__make_capacity_aware_iterator<Iter, decltype(arr), sz>(Iter(i + 2));
+    CapIter iter = std::__make_capacity_aware_iterator<Iter, decltype(arr), sz>(Iter(i));
+    iter += 2;
 
     std::same_as<CapIter> decltype(auto) res = iter - 2;
 
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 ed0d29f0cbcef..889e67899d8a4 100644
--- a/libcxx/test/libcxx/iterators/capacity_aware_iter/assert.pass.cpp
+++ b/libcxx/test/libcxx/iterators/capacity_aware_iter/assert.pass.cpp
@@ -32,29 +32,29 @@ void test_bounded() {
 
   CapIter it = std::__make_capacity_aware_iterator<Iter, decltype(p), sz>(Iter(arr));
 
-  TEST_LIBCPP_ASSERT_FAILURE(it--, "__capacity_aware_iterator::operator--: Attempt to rewind iterator past the start");
+  TEST_LIBCPP_ASSERT_FAILURE(
+      it--, "__capacity_aware_iterator::operator--: Attempt to rewind an iterator past the start");
 
   TEST_LIBCPP_ASSERT_FAILURE(
-      it -= 1, "__capacity_aware_iterator::operator-=: Attempt to rewind iterator past the start");
+      it -= 1, "__capacity_aware_iterator::operator-=: Attempt to rewind an iterator past the start");
 
   TEST_LIBCPP_ASSERT_FAILURE(
-      it += -1, "__capacity_aware_iterator::operator+=: Attempt to rewind iterator past the start");
+      it += -1, "__capacity_aware_iterator::operator+=: Attempt to rewind an iterator past the start");
 
   TEST_LIBCPP_ASSERT_FAILURE(
       it += (sz + 1), "__capacity_aware_iterator::operator+=: Attempt to advance an iterator past the end");
 
   TEST_LIBCPP_ASSERT_FAILURE(
-      it += -(sz + 1), "__capacity_aware_iterator::operator+=: Attempt to rewind iterator past the start");
+      it += -(sz + 1), "__capacity_aware_iterator::operator+=: Attempt to rewind an iterator past the start");
 
   TEST_LIBCPP_ASSERT_FAILURE(
       it -= (sz + 1), "__capacity_aware_iterator::operator-=: Attempt to rewind an iterator past the start");
 
   TEST_LIBCPP_ASSERT_FAILURE(
-      it -= -(sz + 1),
-      "__capacity_aware_iterator::operator-=: Attempting to move iterator past its container's possible range");
+      it -= -(sz + 1), "__capacity_aware_iterator::operator-=: Attempt to advance an iterator past the end");
 
   TEST_LIBCPP_ASSERT_FAILURE(
-      it[sz], "__capacity_aware_iterator::operator[]: Attempt to index an iterator past the end");
+      it[sz], "__capacity_aware_iterator::operator[]: Attempt to index an iterator at or past the end");
 
   TEST_LIBCPP_ASSERT_FAILURE(
       it[-sz], "__capacity_aware_iterator::operator[]: Attempt to index an iterator past the start");

>From 29eebbf0d6af4c5da9002208a9996b66061b2173 Mon Sep 17 00:00:00 2001
From: William Tran-Viet <wtranviet at proton.me>
Date: Thu, 9 Jul 2026 00:42:21 -0400
Subject: [PATCH 3/6] Fix incorrect pointer arithmetic

---
 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 442d9c4d2a561..02db1d6b52d19 100644
--- a/libcxx/include/__iterator/capacity_aware_iterator.h
+++ b/libcxx/include/__iterator/capacity_aware_iterator.h
@@ -243,7 +243,7 @@ class __capacity_aware_iterator<_Iter, _Tag, _RangeMaxElements> {
       return __ptr_;
     }
 
-    return std::bit_cast<_Iter>((std::bit_cast<std::uintptr_t>(__ptr_) >> __bits_) << __bits_) + __current_;
+    return std::bit_cast<_Iter>(std::bit_cast<std::uintptr_t>(__ptr_) - __current_) + __current_;
   }
 
   constexpr void __update(difference_type __n) {

>From bc6bf987bdc44e70a5290e0d2cf94600d358a06c Mon Sep 17 00:00:00 2001
From: William Tran-Viet <wtranviet at proton.me>
Date: Thu, 9 Jul 2026 00:44:43 -0400
Subject: [PATCH 4/6] Simplify

---
 libcxx/include/__iterator/capacity_aware_iterator.h | 6 ++----
 1 file changed, 2 insertions(+), 4 deletions(-)

diff --git a/libcxx/include/__iterator/capacity_aware_iterator.h b/libcxx/include/__iterator/capacity_aware_iterator.h
index 02db1d6b52d19..2572e1c0bd83c 100644
--- a/libcxx/include/__iterator/capacity_aware_iterator.h
+++ b/libcxx/include/__iterator/capacity_aware_iterator.h
@@ -24,7 +24,6 @@
 #include <__type_traits/is_constructible.h>
 #include <__type_traits/is_convertible.h>
 #include <__type_traits/is_pointer.h>
-#include <__utility/declval.h>
 #include <__utility/move.h>
 
 #include <cstdint>
@@ -192,10 +191,9 @@ consteval bool __range_fits_in_alignment(std::size_t __num_elems) {
 // A specialization of capacity_aware_iterator where we store a runtime count of the current position inside
 // the unused bottom bits of a pointer to T. Only applies if capacity can fit inside those bits.
 template <class _Iter, class _Tag, size_t _RangeMaxElements>
-  requires(std::is_pointer_v<_Iter> &&
-           std::__range_fits_in_alignment<decltype(* std::declval<_Iter>())>(_RangeMaxElements))
+  requires(std::is_pointer_v<_Iter> && std::__range_fits_in_alignment<std::iter_value_t<_Iter>>(_RangeMaxElements))
 class __capacity_aware_iterator<_Iter, _Tag, _RangeMaxElements> {
-  constexpr static std::size_t __bits_ = std::countr_zero(alignof(decltype(*std::declval<_Iter>())));
+  constexpr static std::size_t __bits_ = std::countr_zero(alignof(std::iter_value_t<_Iter>));
 
   union {
     _Iter __ptr_;

>From bc8d8ec7a90a804dcb492815f231de43c57e7501 Mon Sep 17 00:00:00 2001
From: William Tran-Viet <wtranviet at proton.me>
Date: Thu, 9 Jul 2026 01:31:20 -0400
Subject: [PATCH 5/6] Try force alignment

---
 .../iterators/capacity_aware_iter/arithmetic.pass.cpp       | 4 ++--
 .../iterators/capacity_aware_iter/comparison.pass.cpp       | 4 ++--
 .../iterators/capacity_aware_iter/dereference.pass.cpp      | 6 +++---
 .../iterators/capacity_aware_iter/types.compile.pass.cpp    | 5 +++--
 4 files changed, 10 insertions(+), 9 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 d46bb4d3e8bec..d84648a75e8f7 100644
--- a/libcxx/test/libcxx/iterators/capacity_aware_iter/arithmetic.pass.cpp
+++ b/libcxx/test/libcxx/iterators/capacity_aware_iter/arithmetic.pass.cpp
@@ -167,8 +167,8 @@ int main(int, char**) {
   static_assert(test<contiguous_iterator<int*>>());
 
   // bounded overload
-  test<long*, long>();
-  static_assert(test<long*, long>());
+  test<long long*, long long>();
+  static_assert(test<long long*, long long>());
 
   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 a7f3ae44fa5ee..149f37691eae0 100644
--- a/libcxx/test/libcxx/iterators/capacity_aware_iter/comparison.pass.cpp
+++ b/libcxx/test/libcxx/iterators/capacity_aware_iter/comparison.pass.cpp
@@ -113,8 +113,8 @@ int main(int, char**) {
   test<contiguous_iterator<int*>>();
   static_assert(test<contiguous_iterator<int*>>());
 
-  test<long*, long>();
-  static_assert(test<long*, long>());
+  test<long long*, long long>();
+  static_assert(test<long long*, long long>());
 
   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 910078db4a7d4..9048207d92ad2 100644
--- a/libcxx/test/libcxx/iterators/capacity_aware_iter/dereference.pass.cpp
+++ b/libcxx/test/libcxx/iterators/capacity_aware_iter/dereference.pass.cpp
@@ -25,13 +25,13 @@
 #include "test_iterators.h"
 #include "test_macros.h"
 
-struct Foo {
+struct alignas(4) Foo {
   int x;
   constexpr bool operator==(Foo const& other) const { return x == other.x; }
 };
 
-struct Foo2 {
-  long x;
+struct alignas(8) Foo2 {
+  int x;
   constexpr bool operator==(Foo2 const& other) const { return x == other.x; }
 };
 
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 37680d0e7c859..e633dc67803f4 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
@@ -30,9 +30,10 @@ 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>>);
 
+struct alignas(8) A {};
 // bounded overload
-using It2      = long*;
-using CapIter2 = std::__capacity_aware_iterator<It2, long[6], 126>;
+using It2      = A*;
+using CapIter2 = std::__capacity_aware_iterator<It2, A[], 126>;
 
 static_assert(std::is_same_v<CapIter2::iterator_category, std::iterator_traits<It2>::iterator_category>);
 static_assert(std::is_same_v<CapIter2::iterator_concept, std::contiguous_iterator_tag>);

>From 9cd041fd668fb40e045d9ef6375ceb971db04e64 Mon Sep 17 00:00:00 2001
From: William Tran-Viet <wtranviet at proton.me>
Date: Fri, 10 Jul 2026 14:50:12 -0400
Subject: [PATCH 6/6] Fix GCC warning

---
 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 2572e1c0bd83c..36281bccdf2ec 100644
--- a/libcxx/include/__iterator/capacity_aware_iterator.h
+++ b/libcxx/include/__iterator/capacity_aware_iterator.h
@@ -180,11 +180,11 @@ class __capacity_aware_iterator {
 
 template <class _Tp>
 consteval bool __range_fits_in_alignment(std::size_t __num_elems) {
-  auto __bits = std::countr_zero(alignof(_Tp));
+  std::size_t __bits = std::countr_zero(alignof(_Tp));
 
   // Example: For alignof(T) == 4, we have two bits free, which has a range of 0-3. We need to
   // reserve one for the end position, so __num_elems must be < 3.
-  auto __allowed_range = (1 << __bits) - 1;
+  std::size_t __allowed_range = (1 << __bits) - 1;
   return __allowed_range > __num_elems;
 }
 



More information about the libcxx-commits mailing list