[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:48 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_;
+}
----------------
frederick-vs-ja wrote:

I think it's simpler to spell the return type as `std::ptrdiff_t`.

Also, can we have a single overload taking `fancy_pointer<T>` and `fancy_pointer<U>`, constrained by that `remove_const<T>::type` and `remove_const<U>::type` are the same type?

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


More information about the libcxx-commits mailing list