================
@@ -65,6 +203,170 @@ public:
   using iterator                       = pointer;
   using const_iterator                 = const_pointer;
 
+public:
+  _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI 
__split_buffer_size_layout() = default;
+
+  _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI explicit 
__split_buffer_size_layout(const allocator_type& __alloc)
+      : __alloc_(__alloc) {}
+
+  _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI pointer __data() 
_NOEXCEPT { return __data_; }
+
+  _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI const_pointer __data() 
const _NOEXCEPT { return __data_; }
+
+  _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI pointer begin() 
_NOEXCEPT { return __begin_; }
+
+  _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI const_pointer begin() 
const _NOEXCEPT { return __begin_; }
+
+  _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI pointer end() _NOEXCEPT 
{ return __begin_ + __size_; }
+
+  _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI pointer end() const 
_NOEXCEPT { return __begin_ + __size_; }
+
+  _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI size_type size() const 
_NOEXCEPT { return __size_; }
+
+  _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI bool empty() const 
_NOEXCEPT { return __size_ == 0; }
+
+  _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI size_type capacity() 
const _NOEXCEPT { return __cap_; }
+
+  _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI allocator_type& 
__get_allocator() _NOEXCEPT { return __alloc_; }
+
+  _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI allocator_type const& 
__get_allocator() const _NOEXCEPT {
+    return __alloc_;
+  }
+
+  // Returns the sentinel object directly. Should be used in conjunction with 
automatic type deduction,
+  // not explicit types.
+  _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI size_type __sentinel() 
const _NOEXCEPT { return __size_; }
+  _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI size_type 
__raw_capacity() const _NOEXCEPT { return __cap_; }
+
+  _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI void __set_data(pointer 
__new_first) _NOEXCEPT {
+    __data_ = __new_first;
+  }
+
+  _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI void
+  __set_valid_range(pointer __new_begin, pointer __new_end) _NOEXCEPT {
+    // Size-based __split_buffers track their size directly: we need to 
explicitly update the size
+    // when the front is adjusted.
+    __size_ -= __new_begin - __begin_;
+    __begin_ = __new_begin;
+    __set_sentinel(__new_end);
+  }
+
+  _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI void
+  __set_valid_range(pointer __new_begin, size_type __new_size) _NOEXCEPT {
+    // Size-based __split_buffers track their size directly: we need to 
explicitly update the size
+    // when the front is adjusted.
+    __size_ -= __new_begin - __begin_;
+    __begin_ = __new_begin;
+    __set_sentinel(__new_size);
+  }
+
+  _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI void 
__set_sentinel(pointer __new_end) _NOEXCEPT {
+    _LIBCPP_ASSERT_INTERNAL(__data_ <= __new_end, "__new_end cannot precede 
__data_");
+    __size_ += __new_end - end();
+  }
+
+  _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI void 
__set_sentinel(size_type __new_size) _NOEXCEPT {
+    __size_ = __new_size;
+  }
+
+  _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI void 
__set_capacity(size_type __new_capacity) _NOEXCEPT {
+    __cap_ = __new_capacity;
+  }
+
+  _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI void 
__set_capacity(pointer __new_capacity) _NOEXCEPT {
+    __cap_ = __new_capacity - __begin_;
+  }
+
+  _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI size_type 
__front_spare() const _NOEXCEPT {
+    return static_cast<size_type>(__begin_ - __data_);
+  }
+
+  _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI size_type __back_spare() 
const _NOEXCEPT {
+    // `__cap_ - __end_` tells us the total number of spares when in 
size-mode. We need to remove
+    // the __front_spare from the count.
+    return __cap_ - __size_ - __front_spare();
+  }
+
+  _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI reference back() 
_NOEXCEPT { return __begin_[__size_ - 1]; }
+
+  _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI const_reference back() 
const _NOEXCEPT {
+    return __begin_[__size_ - 1];
+  }
+
+  template <class _Data2>
+  _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI void 
__swap_without_allocator(_Data2& __other) _NOEXCEPT {
+    std::swap(__data_, __other.__data_);
+    std::swap(__begin_, __other.__begin_);
+    std::swap(__cap_, __other.__cap_);
+    std::swap(__size_, __other.__size_);
+  }
+
+  _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI void 
swap(__split_buffer_size_layout& __other) _NOEXCEPT {
+    __swap_without_allocator(__other);
+    std::__swap_allocator(__alloc_, __other.__alloc_);
+  }
+
+  _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI void __reset() _NOEXCEPT 
{
+    __data_  = nullptr;
+    __begin_ = nullptr;
+    __size_  = 0;
+    __cap_   = 0;
+  }
+
+  _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI void
+  __copy_without_alloc(__split_buffer_size_layout const& __other)
+      _NOEXCEPT_(is_nothrow_copy_assignable<pointer>::value) {
+    __data_  = __other.__data_;
+    __begin_ = __other.__begin_;
+    __cap_   = __other.__cap_;
+    __size_  = __other.__size_;
+  }
+
+private:
+  pointer __data_   = nullptr;
+  pointer __begin_  = nullptr;
+  size_type __size_ = 0;
+  size_type __cap_  = 0;
+  _LIBCPP_NO_UNIQUE_ADDRESS allocator_type __alloc_;
+
+  template <class, class, class>
+  friend class __split_buffer_size_layout;
+};
+
+// __split_buffer allocates a contiguous chunk of memory and stores objects in 
the range [__begin_, __end_).
+// It has uninitialized memory in the ranges  [__data_, __begin_) and [__end_, 
__cap_). That allows
+// it to grow both in the front and back without having to move the data.
+
+template <class _Tp,
----------------
ldionne wrote:

I'd beef up this comment as follows:

```c++
// __split_buffer is conceptually a vector that holds spare capacity at both 
ends of the sequence, unlike vector which
// only holds spare capacity at the end. This characteristic allows growing a 
__split_buffer both at the front and at
// the back without having to relocate its contents (as long as there is enough 
space).
//
// The sequence is stored as a contiguous chunk of memory delimited by the 
following "pointers" (`o` denotes
// uninitialized memory and `x` denotes a valid object):
//
//     
|oooooooooooooooooooxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxoooooooooooooooooooooooo|
//      ^                  ^                                    ^               
        ^
//  __front_cap_        __begin_                              __end_            
   __back_cap_
//
// The range [__front_cap_, __begin_) contains uninitialized memory. It is 
referred to as the "front spare capacity".
// The range [__begin_, __end_) contains valid objects. It is referred to as 
the "valid range".
// The range [__end_, __back_cap_) contains uninitialized memory. It is 
referred to as the "back spare capacity".
//
// __split_buffer allows for its actual layout to be customized via the _Layout 
template parameter. That allows the
// above pointers to be stored in different representations, for example as 
offsets. A layout class must provide the
// following member functions:
//
//      _Layout();
//      explicit _Layout(const allocator_type&);
//      pointer __data();
//      const_pointer __data() const;
//
//      pointer begin();
//      const_pointer begin() const;
//
//      pointer end();
//      pointer end() const;
//
//      size_type size() const;
//      bool empty() const;
//      size_type capacity() const;
//
//      allocator_type& __get_allocator();
//      allocator_type const& __get_allocator() const;
//
//      size_type __sentinel() const;
//      size_type __raw_capacity() const;
//
//      void __set_data(pointer);
//      void __set_valid_range(pointer __begin, pointer __end);
//      void __set_valid_range(pointer __begin, size_type __size);
//      void __set_sentinel(pointer __end);
//      void __set_sentinel(size_type __size);
//
//      void __set_capacity(size_type __capacity);
//      void __set_capacity(pointer __capacity);
//
//      size_type __front_spare() const;
//      size_type __back_spare() const;
//
//      reference back();
//      const_reference back() const;
//
//      void __swap_without_allocator(_Layout&);
//      void swap(_Layout&);
//
//      void __reset();
//      void __copy_without_alloc(_Layout const&);
//
```

While writing this down, I also took the liberty of changing the name of the 
`__data_` and `__cap_` members you are currently using in the code. IMO the 
terminology used above is easiest to follow because of its symmetry.

I think that also informs us of some name changes we could make to the above 
API, like renaming `__data`.


https://github.com/llvm/llvm-project/pull/139632
_______________________________________________
lldb-commits mailing list
lldb-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits

Reply via email to