Thanks to visit codestin.com
Credit goes to chromium.googlesource.com

blob: 47b22a2f3e1be9b237b3f47d6822a24b9891b7de [file] [log] [blame]
Tom Sepezd986abb22024-01-05 23:32:231// 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
Tom Sepez03a0b4352024-12-04 16:22:3014#include "base/check_op.h"
Tom Sepezd986abb22024-01-05 23:32:2315#include "base/compiler_specific.h"
16#include "base/containers/span.h"
Tom Sepezd986abb22024-01-05 23:32:2317
18namespace 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.
danakj216d6edf2024-03-28 22:30:3028template <typename T, typename Deleter = void>
Tom Sepezd986abb22024-01-05 23:32:2329class 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;
danakj216d6edf2024-03-28 22:30:3037 // 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>;
Tom Sepezd986abb22024-01-05 23:32:2341
42 // Allocates initialized memory capable of holding `size` elements. No memory
43 // is allocated for zero-sized arrays.
44 static HeapArray WithSize(size_t size)
45 requires(std::constructible_from<T>)
46 {
47 if (!size) {
48 return HeapArray();
49 }
danakj216d6edf2024-03-28 22:30:3050 return HeapArray(std::unique_ptr<T[], deleter_type>(new T[size]()), size);
Tom Sepezd986abb22024-01-05 23:32:2351 }
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.
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 }
danakj216d6edf2024-03-28 22:30:3063 return HeapArray(std::unique_ptr<T[], deleter_type>(new T[size]), size);
Tom Sepezd986abb22024-01-05 23:32:2364 }
65
Tom Sepez419a98662024-01-17 17:53:0666 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
danakj216d6edf2024-03-28 22:30:3072 // 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.
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
Kelsen Liua1d268ec2025-09-12 18:08:5491 // Constructs a HeapArray from an existing pointer and a deleter instance,
92 // taking ownership of both.
93 //
94 // # Safety
95 // The pointer must be correctly aligned for type `T` and able to be deleted
96 // through the provided `deleter` instance. The `ptr` must point to an array
97 // of at least `size` many elements. If these are not met, then Undefined
98 // Behaviour can result.
99 //
100 // # Checks
101 // When the `size` is zero, the `ptr` must be null.
102 UNSAFE_BUFFER_USAGE static HeapArray FromOwningPointer(T* ptr,
103 size_t size,
104 deleter_type deleter) {
105 if (!size) {
106 CHECK_EQ(ptr, nullptr);
107 return HeapArray(
108 std::unique_ptr<T[], deleter_type>(nullptr, std::move(deleter)), 0);
109 }
110 return HeapArray(
111 std::unique_ptr<T[], deleter_type>(ptr, std::move(deleter)), size);
112 }
113
Tom Sepezd986abb22024-01-05 23:32:23114 // Constructs an empty array and does not allocate any memory.
115 HeapArray()
116 requires(std::constructible_from<T>)
117 = default;
118
119 // Move-only type since the memory is owned.
120 HeapArray(const HeapArray&) = delete;
121 HeapArray& operator=(const HeapArray&) = delete;
122
123 // Move-construction leaves the moved-from object empty and containing
124 // no allocated memory.
125 HeapArray(HeapArray&& that)
126 : data_(std::move(that.data_)), size_(std::exchange(that.size_, 0u)) {}
127
128 // Move-assigment leaves the moved-from object empty and containing
129 // no allocated memory.
130 HeapArray& operator=(HeapArray&& that) {
131 data_ = std::move(that.data_);
132 size_ = std::exchange(that.size_, 0u);
133 return *this;
134 }
135 ~HeapArray() = default;
136
137 bool empty() const { return size_ == 0u; }
138 size_t size() const { return size_; }
139
140 // Prefer span-based methods below over data() where possible. The data()
141 // method exists primarily to allow implicit constructions of spans.
142 // Returns nullptr for a zero-sized (or moved-from) array.
Peter Kasting4b18d0c2024-09-18 00:56:11143 T* data() LIFETIME_BOUND { return data_.get(); }
144 const T* data() const LIFETIME_BOUND { return data_.get(); }
Tom Sepezd986abb22024-01-05 23:32:23145
Peter Kasting4b18d0c2024-09-18 00:56:11146 iterator begin() LIFETIME_BOUND { return as_span().begin(); }
147 const_iterator begin() const LIFETIME_BOUND { return as_span().begin(); }
Tom Sepezd986abb22024-01-05 23:32:23148
Peter Kasting4b18d0c2024-09-18 00:56:11149 iterator end() LIFETIME_BOUND { return as_span().end(); }
150 const_iterator end() const LIFETIME_BOUND { return as_span().end(); }
Tom Sepezd986abb22024-01-05 23:32:23151
Tom Sepez03a0b4352024-12-04 16:22:30152 ALWAYS_INLINE T& operator[](size_t idx) LIFETIME_BOUND {
153 CHECK_LT(idx, size_);
154 // SAFETY: bounds checked above.
155 return UNSAFE_BUFFERS(data_.get()[idx]);
156 }
157 ALWAYS_INLINE const T& operator[](size_t idx) const LIFETIME_BOUND {
158 CHECK_LT(idx, size_);
159 // SAFETY: bounds checked above.
160 return UNSAFE_BUFFERS(data_.get()[idx]);
Tom Sepezd986abb22024-01-05 23:32:23161 }
162
163 // Access the HeapArray via spans. Note that span<T> is implicilty
danakj1018fdb2024-01-09 21:21:50164 // constructible from HeapArray<T>, so an explicit call to .as_span() is
Tom Sepezd986abb22024-01-05 23:32:23165 // most useful, say, when the compiler can't deduce a template
166 // argument type.
Tom Sepez03a0b4352024-12-04 16:22:30167 ALWAYS_INLINE base::span<T> as_span() LIFETIME_BOUND {
danakjdcf74b72024-07-16 23:06:29168 // SAFETY: `size_` is the number of elements in the `data_` allocation` at
169 // all times.
170 return UNSAFE_BUFFERS(base::span<T>(data_.get(), size_));
Tom Sepezd986abb22024-01-05 23:32:23171 }
Tom Sepez03a0b4352024-12-04 16:22:30172 ALWAYS_INLINE base::span<const T> as_span() const LIFETIME_BOUND {
danakjdcf74b72024-07-16 23:06:29173 // SAFETY: `size_` is the number of elements in the `data_` allocation` at
174 // all times.
175 return UNSAFE_BUFFERS(base::span<const T>(data_.get(), size_));
Tom Sepezd986abb22024-01-05 23:32:23176 }
177
Tom Sepez7bda5402024-08-13 21:22:21178 // Convenience method to copy the contents of a span<> into the entire array.
179 // Hard CHECK occurs in span<>::copy_from() if the HeapArray and the span
180 // have different sizes.
Tom Sepez648a4272024-01-12 18:21:34181 void copy_from(base::span<const T> other) { as_span().copy_from(other); }
182
Tom Sepez7bda5402024-08-13 21:22:21183 // Convenience method to copy the contents of a span<> into the start of the
184 // array. Hard CHECK occurs in span<>::copy_prefix_from() if the HeapArray
185 // isn't large enough to contain the entire span.
186 void copy_prefix_from(base::span<const T> other) {
187 as_span().copy_prefix_from(other);
188 }
189
Tom Sepezd986abb22024-01-05 23:32:23190 // Convenience methods to slice the vector into spans.
191 // Returns a span over the HeapArray starting at `offset` of `count` elements.
192 // If `count` is unspecified, all remaining elements are included. A CHECK()
193 // occurs if any of the parameters results in an out-of-range position in
194 // the HeapArray.
Tom Sepezc7cadace2025-02-24 19:18:26195 base::span<T> subspan(size_t offset) LIFETIME_BOUND {
196 return as_span().subspan(offset);
197 }
198 base::span<const T> subspan(size_t offset) const LIFETIME_BOUND {
199 return as_span().subspan(offset);
200 }
201 base::span<T> subspan(size_t offset, size_t count) LIFETIME_BOUND {
danakj1018fdb2024-01-09 21:21:50202 return as_span().subspan(offset, count);
Tom Sepezd986abb22024-01-05 23:32:23203 }
204 base::span<const T> subspan(size_t offset,
Tom Sepezc7cadace2025-02-24 19:18:26205 size_t count) const LIFETIME_BOUND {
danakj1018fdb2024-01-09 21:21:50206 return as_span().subspan(offset, count);
Tom Sepezd986abb22024-01-05 23:32:23207 }
208
209 // Returns a span over the first `count` elements of the HeapArray. A CHECK()
210 // occurs if the `count` is larger than size of the HeapArray.
Peter Kasting4b18d0c2024-09-18 00:56:11211 base::span<T> first(size_t count) LIFETIME_BOUND {
danakj1018fdb2024-01-09 21:21:50212 return as_span().first(count);
Tom Sepezd986abb22024-01-05 23:32:23213 }
Peter Kasting4b18d0c2024-09-18 00:56:11214 base::span<const T> first(size_t count) const LIFETIME_BOUND {
danakj1018fdb2024-01-09 21:21:50215 return as_span().first(count);
Tom Sepezd986abb22024-01-05 23:32:23216 }
217
218 // Returns a span over the last `count` elements of the HeapArray. A CHECK()
219 // occurs if the `count` is larger than size of the HeapArray.
Peter Kasting4b18d0c2024-09-18 00:56:11220 base::span<T> last(size_t count) LIFETIME_BOUND {
danakj1018fdb2024-01-09 21:21:50221 return as_span().last(count);
Tom Sepezd986abb22024-01-05 23:32:23222 }
Peter Kasting4b18d0c2024-09-18 00:56:11223 base::span<const T> last(size_t count) const LIFETIME_BOUND {
danakj1018fdb2024-01-09 21:21:50224 return as_span().last(count);
Tom Sepezd986abb22024-01-05 23:32:23225 }
226
danakjad724a82024-01-25 17:37:40227 // Leaks the memory in the HeapArray so that it will never be freed, and
228 // consumes the HeapArray, returning an unowning span that points to the
229 // memory.
230 base::span<T> leak() && {
231 HeapArray<T> dropped = std::move(*this);
232 T* leaked = dropped.data_.release();
danakjdcf74b72024-07-16 23:06:29233 // SAFETY: The `size_` is the number of elements in the allocation in
234 // `data_` at all times, which is renamed as `leaked` here.
235 return UNSAFE_BUFFERS(span(leaked, dropped.size_));
danakjad724a82024-01-25 17:37:40236 }
237
Dale Curtisea394652024-07-12 21:01:15238 // Allows construction of a smaller HeapArray from an existing HeapArray w/o
239 // reallocations or copies. Note: The original allocation is preserved, so
240 // CopiedFrom() should be preferred for significant size reductions.
241 base::HeapArray<T> take_first(size_t reduced_size) && {
242 CHECK_LE(reduced_size, size_);
243 size_ = 0u;
244 if (!reduced_size) {
245 data_.reset();
246 }
247 return base::HeapArray(std::move(data_), reduced_size);
248 }
249
Tom Sepezd09479a22024-03-05 22:37:02250 // Delete the memory previously obtained from leak(). Argument is a pointer
251 // rather than a span to facilitate use by callers that have lost track of
252 // size information, as may happen when being passed through a C-style
253 // function callback. The void* argument type makes its signature compatible
254 // with typical void (*cb)(void*) C-style deletion callback.
255 static void DeleteLeakedData(void* ptr) {
256 // Memory is freed by unique ptr going out of scope.
danakj216d6edf2024-03-28 22:30:30257 std::unique_ptr<T[], deleter_type> deleter(static_cast<T*>(ptr));
Tom Sepezd09479a22024-03-05 22:37:02258 }
259
Tom Sepezd986abb22024-01-05 23:32:23260 private:
danakj216d6edf2024-03-28 22:30:30261 HeapArray(std::unique_ptr<T[], deleter_type> data, size_t size)
Tom Sepezd986abb22024-01-05 23:32:23262 : data_(std::move(data)), size_(size) {}
263
danakj216d6edf2024-03-28 22:30:30264 std::unique_ptr<T[], deleter_type> data_;
Tom Sepezd986abb22024-01-05 23:32:23265 size_t size_ = 0u;
266};
267
268} // namespace base
269
270#endif // BASE_CONTAINERS_HEAP_ARRAY_H_