[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