xref: /aosp_15_r20/external/cronet/base/containers/heap_array.h (revision 6777b5387eb2ff775bb5750e3f5d96f37fb7352b)
1 // Copyright 2024 The Chromium Authors
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #ifndef BASE_CONTAINERS_HEAP_ARRAY_H_
6 #define BASE_CONTAINERS_HEAP_ARRAY_H_
7 
8 #include <stddef.h>
9 
10 #include <memory>
11 #include <type_traits>
12 #include <utility>
13 
14 #include "base/compiler_specific.h"
15 #include "base/containers/span.h"
16 #include "third_party/abseil-cpp/absl/base/attributes.h"
17 
18 namespace base {
19 
20 // HeapArray<T> is a replacement for std::unique_ptr<T[]> that keeps track
21 // of its size. It is intended to provide easy conversion to span<T> for most
22 // usage, but it also provides bounds-checked indexing.
23 //
24 // By default, elements in the array are either value-initialized (i.e. zeroed
25 // for primitive types) when the array is created using the WithSize()
26 // static method, or uninitialized when the array is created via the Uninit()
27 // static method.
28 template <typename T, typename Deleter = void>
29 class TRIVIAL_ABI GSL_OWNER HeapArray {
30  public:
31   static_assert(!std::is_const_v<T>, "HeapArray cannot hold const types");
32   static_assert(!std::is_reference_v<T>,
33                 "HeapArray cannot hold reference types");
34 
35   using iterator = base::span<T>::iterator;
36   using const_iterator = base::span<const T>::iterator;
37   // We don't put this default value in the template parameter list to allow the
38   // static_assert on is_reference_v to give a nicer error message.
39   using deleter_type = std::
40       conditional_t<std::is_void_v<Deleter>, std::default_delete<T[]>, Deleter>;
41 
42   // Allocates initialized memory capable of holding `size` elements. No memory
43   // is allocated for zero-sized arrays.
WithSize(size_t size)44   static HeapArray WithSize(size_t size)
45     requires(std::constructible_from<T>)
46   {
47     if (!size) {
48       return HeapArray();
49     }
50     return HeapArray(std::unique_ptr<T[], deleter_type>(new T[size]()), size);
51   }
52 
53   // Allocates uninitialized memory capable of holding `size` elements. T must
54   // be trivially constructible and destructible. No memory is allocated for
55   // zero-sized arrays.
Uninit(size_t size)56   static HeapArray Uninit(size_t size)
57     requires(std::is_trivially_constructible_v<T> &&
58              std::is_trivially_destructible_v<T>)
59   {
60     if (!size) {
61       return HeapArray();
62     }
63     return HeapArray(std::unique_ptr<T[], deleter_type>(new T[size]), size);
64   }
65 
CopiedFrom(base::span<const T> that)66   static HeapArray CopiedFrom(base::span<const T> that) {
67     auto result = HeapArray::Uninit(that.size());
68     result.copy_from(that);
69     return result;
70   }
71 
72   // Constructs a HeapArray from an existing pointer, taking ownership of the
73   // pointer.
74   //
75   // # Safety
76   // The pointer must be correctly aligned for type `T` and able to be deleted
77   // through the `deleter_type`, which defaults to the `delete[]` operation. The
78   // `ptr` must point to an array of at least `size` many elements. If these are
79   // not met, then Undefined Behaviour can result.
80   //
81   // # Checks
82   // When the `size` is zero, the `ptr` must be null.
FromOwningPointer(T * ptr,size_t size)83   UNSAFE_BUFFER_USAGE static HeapArray FromOwningPointer(T* ptr, size_t size) {
84     if (!size) {
85       CHECK_EQ(ptr, nullptr);
86       return HeapArray();
87     }
88     return HeapArray(std::unique_ptr<T[], deleter_type>(ptr), size);
89   }
90 
91   // Constructs an empty array and does not allocate any memory.
92   HeapArray()
93     requires(std::constructible_from<T>)
94   = default;
95 
96   // Move-only type since the memory is owned.
97   HeapArray(const HeapArray&) = delete;
98   HeapArray& operator=(const HeapArray&) = delete;
99 
100   // Move-construction leaves the moved-from object empty and containing
101   // no allocated memory.
HeapArray(HeapArray && that)102   HeapArray(HeapArray&& that)
103       : data_(std::move(that.data_)), size_(std::exchange(that.size_, 0u)) {}
104 
105   // Move-assigment leaves the moved-from object empty and containing
106   // no allocated memory.
107   HeapArray& operator=(HeapArray&& that) {
108     data_ = std::move(that.data_);
109     size_ = std::exchange(that.size_, 0u);
110     return *this;
111   }
112   ~HeapArray() = default;
113 
empty()114   bool empty() const { return size_ == 0u; }
size()115   size_t size() const { return size_; }
116 
117   // Prefer span-based methods below over data() where possible. The data()
118   // method exists primarily to allow implicit constructions of spans.
119   // Returns nullptr for a zero-sized (or moved-from) array.
data()120   T* data() ABSL_ATTRIBUTE_LIFETIME_BOUND { return data_.get(); }
data()121   const T* data() const ABSL_ATTRIBUTE_LIFETIME_BOUND { return data_.get(); }
122 
begin()123   iterator begin() ABSL_ATTRIBUTE_LIFETIME_BOUND { return as_span().begin(); }
begin()124   const_iterator begin() const ABSL_ATTRIBUTE_LIFETIME_BOUND {
125     return as_span().begin();
126   }
127 
end()128   iterator end() ABSL_ATTRIBUTE_LIFETIME_BOUND { return as_span().end(); }
end()129   const_iterator end() const ABSL_ATTRIBUTE_LIFETIME_BOUND {
130     return as_span().end();
131   }
132 
133   T& operator[](size_t idx) ABSL_ATTRIBUTE_LIFETIME_BOUND {
134     return as_span()[idx];
135   }
136   const T& operator[](size_t idx) const ABSL_ATTRIBUTE_LIFETIME_BOUND {
137     return as_span()[idx];
138   }
139 
140   // Access the HeapArray via spans. Note that span<T> is implicilty
141   // constructible from HeapArray<T>, so an explicit call to .as_span() is
142   // most useful, say, when the compiler can't deduce a template
143   // argument type.
as_span()144   base::span<T> as_span() ABSL_ATTRIBUTE_LIFETIME_BOUND {
145     return base::span<T>(data_.get(), size_);
146   }
as_span()147   base::span<const T> as_span() const ABSL_ATTRIBUTE_LIFETIME_BOUND {
148     return base::span<const T>(data_.get(), size_);
149   }
150 
151   // Convenience method to copy the contents of the entire array from a
152   // span<>. Hard CHECK occurs in span<>::copy_from() if the HeapArray and
153   // the span have different sizes.
copy_from(base::span<const T> other)154   void copy_from(base::span<const T> other) { as_span().copy_from(other); }
155 
156   // Convenience methods to slice the vector into spans.
157   // Returns a span over the HeapArray starting at `offset` of `count` elements.
158   // If `count` is unspecified, all remaining elements are included. A CHECK()
159   // occurs if any of the parameters results in an out-of-range position in
160   // the HeapArray.
161   base::span<T> subspan(size_t offset, size_t count = base::dynamic_extent)
162       ABSL_ATTRIBUTE_LIFETIME_BOUND {
163     return as_span().subspan(offset, count);
164   }
165   base::span<const T> subspan(size_t offset,
166                               size_t count = base::dynamic_extent) const
167       ABSL_ATTRIBUTE_LIFETIME_BOUND {
168     return as_span().subspan(offset, count);
169   }
170 
171   // Returns a span over the first `count` elements of the HeapArray. A CHECK()
172   // occurs if the `count` is larger than size of the HeapArray.
first(size_t count)173   base::span<T> first(size_t count) ABSL_ATTRIBUTE_LIFETIME_BOUND {
174     return as_span().first(count);
175   }
first(size_t count)176   base::span<const T> first(size_t count) const ABSL_ATTRIBUTE_LIFETIME_BOUND {
177     return as_span().first(count);
178   }
179 
180   // Returns a span over the last `count` elements of the HeapArray. A CHECK()
181   // occurs if the `count` is larger than size of the HeapArray.
last(size_t count)182   base::span<T> last(size_t count) ABSL_ATTRIBUTE_LIFETIME_BOUND {
183     return as_span().last(count);
184   }
last(size_t count)185   base::span<const T> last(size_t count) const ABSL_ATTRIBUTE_LIFETIME_BOUND {
186     return as_span().last(count);
187   }
188 
189   // Leaks the memory in the HeapArray so that it will never be freed, and
190   // consumes the HeapArray, returning an unowning span that points to the
191   // memory.
leak()192   base::span<T> leak() && {
193     HeapArray<T> dropped = std::move(*this);
194     T* leaked = dropped.data_.release();
195     return make_span(leaked, dropped.size_);
196   }
197 
198   // Delete the memory previously obtained from leak(). Argument is a pointer
199   // rather than a span to facilitate use by callers that have lost track of
200   // size information, as may happen when being passed through a C-style
201   // function callback. The void* argument type makes its signature compatible
202   // with typical void (*cb)(void*) C-style deletion callback.
DeleteLeakedData(void * ptr)203   static void DeleteLeakedData(void* ptr) {
204     // Memory is freed by unique ptr going out of scope.
205     std::unique_ptr<T[], deleter_type> deleter(static_cast<T*>(ptr));
206   }
207 
208  private:
HeapArray(std::unique_ptr<T[],deleter_type> data,size_t size)209   HeapArray(std::unique_ptr<T[], deleter_type> data, size_t size)
210       : data_(std::move(data)), size_(size) {}
211 
212   std::unique_ptr<T[], deleter_type> data_;
213   size_t size_ = 0u;
214 };
215 
216 }  // namespace base
217 
218 #endif  // BASE_CONTAINERS_HEAP_ARRAY_H_
219