[libcxx-commits] [libcxx] [libcxx][test-support] Implement fancy_pointer_allocator (PR #196187)

A. Jiang via libcxx-commits libcxx-commits at lists.llvm.org
Fri Oct 16 21:44:49 PDT 2026


================
@@ -574,4 +575,354 @@ struct SocccAllocator {
   using propagate_on_container_swap            = std::false_type;
 };
 
+template <class T>
+class fancy_pointer {
+public:
+  // For the std::pointer_traits interface.
+  using pointer         = T*;
+  using element_type    = T;
+  using difference_type = std::ptrdiff_t;
+
+  // For the std::iterator_traits interface.
+  using value_type        = typename std::remove_cv<T>::type;
+  using reference         = typename std::add_lvalue_reference<T>::type;
+  using iterator_category = std::random_access_iterator_tag;
+
+  TEST_CONSTEXPR_CXX20 fancy_pointer() TEST_NOEXCEPT : ptr_(nullptr), ctr_(nullptr) {}
+  TEST_CONSTEXPR_CXX20 fancy_pointer(nullptr_t) TEST_NOEXCEPT : ptr_(nullptr), ctr_(nullptr) {}
+  TEST_CONSTEXPR_CXX20 explicit fancy_pointer(T* p, int* c = nullptr) TEST_NOEXCEPT : ptr_(p), ctr_(c) {
+    if (ctr_)
+      ++*ctr_;
+  }
+  template <typename T2>
+  TEST_CONSTEXPR_CXX20 explicit fancy_pointer(const fancy_pointer<T2>& other) TEST_NOEXCEPT
+      : ptr_(static_cast<T*>(other.ptr_)),
+        ctr_(other.ctr_) {
+    if (ctr_)
+      ++*ctr_;
+  }
+  TEST_CONSTEXPR_CXX20 fancy_pointer(const fancy_pointer& other) TEST_NOEXCEPT : ptr_(other.ptr_), ctr_(other.ctr_) {
+    if (ctr_)
+      ++*ctr_;
+  }
+  TEST_CONSTEXPR_CXX20 fancy_pointer(fancy_pointer&& other) TEST_NOEXCEPT : ptr_(other.ptr_), ctr_(other.ctr_) {
+    if (ctr_)
+      ++*ctr_;
+  }
+  TEST_CONSTEXPR_CXX20 fancy_pointer& operator=(const fancy_pointer& other) TEST_NOEXCEPT {
+    if (ctr_)
+      --*ctr_;
+    ptr_ = other.ptr_;
+    ctr_ = other.ctr_;
+    if (ctr_)
+      ++*ctr_;
+    return *this;
+  }
+  TEST_CONSTEXPR_CXX20 fancy_pointer& operator=(fancy_pointer&& other) TEST_NOEXCEPT {
+    if (ctr_)
+      --*ctr_;
+    ptr_ = other.ptr_;
+    ctr_ = other.ctr_;
+    if (ctr_)
+      ++*ctr_;
+    return *this;
+  }
+  TEST_CONSTEXPR_CXX20 ~fancy_pointer() TEST_NOEXCEPT {
+    if (ctr_)
+      --*ctr_;
+  }
+
+  TEST_CONSTEXPR_CXX20 operator fancy_pointer<const T>() const TEST_NOEXCEPT {
+    return fancy_pointer<const T>(ptr_, ctr_);
+  }
+
+  TEST_CONSTEXPR_CXX20 operator T*() const TEST_NOEXCEPT { return ptr_; }
+
+  TEST_CONSTEXPR_CXX20 T& operator*() const TEST_NOEXCEPT { return *ptr_; }
+  TEST_CONSTEXPR_CXX20 T* operator->() const TEST_NOEXCEPT { return ptr_; }
+  TEST_CONSTEXPR_CXX20 explicit operator bool() const TEST_NOEXCEPT { return ptr_; }
+  TEST_CONSTEXPR_CXX20 T* get() const TEST_NOEXCEPT { return ptr_; }
+
+  TEST_CONSTEXPR_CXX20 fancy_pointer& operator++() TEST_NOEXCEPT {
+    ++ptr_;
+    return *this;
+  }
+  TEST_CONSTEXPR_CXX20 fancy_pointer operator++(int) TEST_NOEXCEPT {
+    fancy_pointer tmp(*this);
+    ++ptr_;
+    return tmp;
+  }
+
+  TEST_CONSTEXPR_CXX20 fancy_pointer& operator--() TEST_NOEXCEPT {
+    --ptr_;
+    return *this;
+  }
+  TEST_CONSTEXPR_CXX20 fancy_pointer operator--(int) TEST_NOEXCEPT {
+    fancy_pointer tmp(*this);
+    --ptr_;
+    return tmp;
+  }
+
+  TEST_CONSTEXPR_CXX20 fancy_pointer& operator+=(difference_type n) TEST_NOEXCEPT {
+    ptr_ += n;
+    return *this;
+  }
+
+  TEST_CONSTEXPR_CXX20 fancy_pointer& operator-=(difference_type n) TEST_NOEXCEPT {
+    ptr_ -= n;
+    return *this;
+  }
+
+  TEST_CONSTEXPR_CXX20 fancy_pointer operator+(difference_type n) const TEST_NOEXCEPT {
+    fancy_pointer tmp(*this);
+    tmp += n;
+    return tmp;
+  }
+
+  TEST_CONSTEXPR_CXX20 fancy_pointer operator-(difference_type n) const TEST_NOEXCEPT {
+    fancy_pointer tmp(*this);
+    tmp -= n;
+    return tmp;
+  }
+
+  TEST_CONSTEXPR_CXX20 reference operator[](difference_type n) const TEST_NOEXCEPT { return ptr_[n]; }
+
+  friend TEST_CONSTEXPR_CXX20 fancy_pointer operator+(difference_type x, fancy_pointer y) TEST_NOEXCEPT {
+    return y + x;
+  }
+
+  static TEST_CONSTEXPR_CXX20 fancy_pointer pointer_to(reference ref) TEST_NOEXCEPT { return fancy_pointer(&ref); }
+
+  T* ptr_;
+  int* ctr_;
+};
+
+template <>
+class fancy_pointer<void> {
+public:
+  using T = void;
+
+  // For the std::pointer_traits interface.
+  using pointer         = T*;
+  using element_type    = T;
+  using difference_type = std::ptrdiff_t;
+
+  // For the std::iterator_traits interface.
+  using value_type        = typename std::remove_cv<T>::type;
+  using reference         = typename std::add_lvalue_reference<T>::type;
+  using iterator_category = std::random_access_iterator_tag;
+
+  TEST_CONSTEXPR_CXX20 fancy_pointer() TEST_NOEXCEPT : ptr_(nullptr), ctr_(nullptr) {}
+  TEST_CONSTEXPR_CXX20 fancy_pointer(nullptr_t) TEST_NOEXCEPT : ptr_(nullptr), ctr_(nullptr) {}
+  TEST_CONSTEXPR_CXX20 explicit fancy_pointer(T* p, int* c = nullptr) TEST_NOEXCEPT : ptr_(p), ctr_(c) {
+    if (ctr_)
+      ++*ctr_;
+  }
+  template <typename T2>
+  TEST_CONSTEXPR_CXX20 explicit fancy_pointer(const fancy_pointer<T2>& other) TEST_NOEXCEPT
+      : ptr_(static_cast<T*>(other.ptr_), other.ctr_) {
+    if (ctr_)
+      ++*ctr_;
+  }
+  TEST_CONSTEXPR_CXX20 fancy_pointer(const fancy_pointer& other) TEST_NOEXCEPT : ptr_(other.ptr_), ctr_(other.ctr_) {
+    if (ctr_)
+      ++*ctr_;
+  }
+  TEST_CONSTEXPR_CXX20 fancy_pointer(fancy_pointer&& other) TEST_NOEXCEPT : ptr_(other.ptr_), ctr_(other.ctr_) {
+    if (ctr_)
+      ++*ctr_;
+  }
+  TEST_CONSTEXPR_CXX20 fancy_pointer& operator=(const fancy_pointer& other) TEST_NOEXCEPT {
+    if (ctr_)
+      --*ctr_;
+    ptr_ = other.ptr_;
+    ctr_ = other.ctr_;
+    if (ctr_)
+      ++*ctr_;
+    return *this;
+  }
+  TEST_CONSTEXPR_CXX20 fancy_pointer& operator=(fancy_pointer&& other) TEST_NOEXCEPT {
+    if (ctr_)
+      --*ctr_;
+    ptr_ = other.ptr_;
+    ctr_ = other.ctr_;
+    if (ctr_)
+      ++*ctr_;
+    return *this;
+  }
+  TEST_CONSTEXPR_CXX20 ~fancy_pointer() TEST_NOEXCEPT {
+    if (ctr_)
+      --*ctr_;
+  }
+
+  TEST_CONSTEXPR_CXX14 explicit operator bool() const TEST_NOEXCEPT { return ptr_; }
+  TEST_CONSTEXPR_CXX14 T* get() const TEST_NOEXCEPT { return ptr_; }
+
+  T* ptr_;
+  int* ctr_;
+};
+
+template <typename T>
+TEST_CONSTEXPR_CXX20 typename fancy_pointer<T>::difference_type
+operator-(fancy_pointer<T> x, fancy_pointer<T> y) TEST_NOEXCEPT {
+  return x.ptr_ - y.ptr_;
+}
+
+template <typename T>
+TEST_CONSTEXPR_CXX20 typename fancy_pointer<T>::difference_type
+operator-(fancy_pointer<const T> x, fancy_pointer<T> y) TEST_NOEXCEPT {
+  return x.ptr_ - y.ptr_;
+}
+
+template <typename T>
+TEST_CONSTEXPR_CXX20 typename fancy_pointer<T>::difference_type
+operator-(fancy_pointer<T> x, fancy_pointer<const T> y) TEST_NOEXCEPT {
+  return x.ptr_ - y.ptr_;
+}
+
+template <typename T>
+TEST_CONSTEXPR_CXX20 typename fancy_pointer<T>::difference_type
+operator-(fancy_pointer<const T> x, fancy_pointer<const T> y) TEST_NOEXCEPT {
+  return x.ptr_ - y.ptr_;
+}
+
+template <typename T>
+TEST_CONSTEXPR_CXX20 bool operator==(fancy_pointer<T> x, fancy_pointer<T> y) TEST_NOEXCEPT {
+  return x.get() == y.get();
+}
+
+template <typename T>
+TEST_CONSTEXPR_CXX20 bool operator==(fancy_pointer<const T> x, fancy_pointer<T> y) TEST_NOEXCEPT {
+  return x.get() == y.get();
+}
+
+template <typename T>
+TEST_CONSTEXPR_CXX20 bool operator==(fancy_pointer<T> x, fancy_pointer<const T> y) TEST_NOEXCEPT {
+  return x.get() == y.get();
+}
+
+template <typename T>
+TEST_CONSTEXPR_CXX20 bool operator==(fancy_pointer<const T> x, fancy_pointer<const T> y) TEST_NOEXCEPT {
+  return x.get() == y.get();
+}
+
+template <typename T>
+TEST_CONSTEXPR_CXX20 bool operator!=(fancy_pointer<T> x, fancy_pointer<T> y) TEST_NOEXCEPT {
+  return !(x == y);
+}
+
+template <typename T>
+TEST_CONSTEXPR_CXX20 bool operator!=(fancy_pointer<const T> x, fancy_pointer<T> y) TEST_NOEXCEPT {
+  return !(x == y);
+}
+
+template <typename T>
+TEST_CONSTEXPR_CXX20 bool operator!=(fancy_pointer<T> x, fancy_pointer<const T> y) TEST_NOEXCEPT {
+  return !(x == y);
+}
+
+template <typename T>
+TEST_CONSTEXPR_CXX20 bool operator!=(fancy_pointer<const T> x, fancy_pointer<const T> y) TEST_NOEXCEPT {
+  return !(x == y);
+}
+
+template <typename T>
+TEST_CONSTEXPR_CXX20 bool operator>(fancy_pointer<const T> x, fancy_pointer<const T> y) TEST_NOEXCEPT {
+  return x.get() == y.get();
+}
+
+template <typename T>
+TEST_CONSTEXPR_CXX20 bool operator<(fancy_pointer<const T> x, fancy_pointer<const T> y) TEST_NOEXCEPT {
+  return y < x;
+}
+
+template <typename T>
+TEST_CONSTEXPR_CXX20 bool operator<=(fancy_pointer<const T> x, fancy_pointer<const T> y) TEST_NOEXCEPT {
+  return !(y < x);
+}
+
+template <typename T>
+TEST_CONSTEXPR_CXX20 bool operator>=(fancy_pointer<const T> x, fancy_pointer<const T> y) TEST_NOEXCEPT {
+  return !(x < y);
+}
+
+struct fancy_pointer_statistics {
+  int alive_count = 0;
+
+  TEST_CONSTEXPR_CXX20 fancy_pointer_statistics() {};
+  fancy_pointer_statistics(const fancy_pointer_statistics&)            = delete;
+  fancy_pointer_statistics(fancy_pointer_statistics&&)                 = delete;
+  fancy_pointer_statistics& operator=(const fancy_pointer_statistics&) = delete;
+  fancy_pointer_statistics& operator=(fancy_pointer_statistics&&)      = delete;
+  TEST_CONSTEXPR_CXX20 ~fancy_pointer_statistics() {
+    assert(alive_count == 0 && "unmatched constructor/destructor/assignment?");
+  }
+};
+
+template <class T>
+class fancy_pointer_allocator : public std::allocator<T> {
+  using base = std::allocator<T>;
+
+public:
+  using value_type      = T;
+  using pointer         = fancy_pointer<T>;
+  using const_pointer   = fancy_pointer<const T>;
+  using reference       = value_type&;
+  using const_reference = const value_type&;
+  using size_type       = std::size_t;
+  using difference_type = std::ptrdiff_t;
+
+  template <class U>
+  struct rebind {
+    using other = fancy_pointer_allocator<U>;
+  };
+
+  using propagate_on_container_copy_assignment = std::true_type;
+  using propagate_on_container_move_assignment = std::true_type;
+  using propagate_on_container_swap            = std::true_type;
+
+  TEST_CONSTEXPR_CXX20 fancy_pointer_allocator() TEST_NOEXCEPT
+      : stats_(detail::make_thread_unsafe_shared<fancy_pointer_statistics>()) {}
----------------
frederick-vs-ja wrote:

```suggestion
  TEST_CONSTEXPR_CXX20 fancy_pointer_allocator()
      : stats_(detail::make_thread_unsafe_shared<fancy_pointer_statistics>()) {}
```

This function shouldn't be `noexcept`.

https://github.com/llvm/llvm-project/pull/196187


More information about the libcxx-commits mailing list