Pigweed
 
Loading...
Searching...
No Matches
allocator.h
1// Copyright 2023 The Pigweed Authors
2//
3// Licensed under the Apache License, Version 2.0 (the "License"); you may not
4// use this file except in compliance with the License. You may obtain a copy of
5// the License at
6//
7// https://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
11// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
12// License for the specific language governing permissions and limitations under
13// the License.
14#pragma once
15
16#include <cstddef>
17
18#include "pw_allocator/capability.h"
19#include "pw_allocator/deallocator.h"
20#include "pw_allocator/internal/control_block.h"
21#include "pw_allocator/layout.h"
22#include "pw_allocator/shared_ptr.h"
23#include "pw_allocator/unique_ptr.h"
24#include "pw_numeric/checked_arithmetic.h"
25#include "pw_result/result.h"
26
27namespace pw {
28
34class Allocator : public Deallocator {
35 private:
36 using ControlBlock = allocator::internal::ControlBlock;
37
38 public:
45 void* Allocate(Layout layout) {
46 return layout.size() != 0 ? DoAllocate(layout) : nullptr;
47 }
48
56 template <typename T, int&... kExplicitGuard, typename... Args>
57 [[nodiscard]] std::enable_if_t<!std::is_array_v<T>, T*> New(Args&&... args) {
58 void* ptr = Allocate(Layout::Of<T>());
59 if (ptr == nullptr) {
60 return nullptr;
61 }
62 return new (ptr) T(std::forward<Args>(args)...);
63 }
64
72 template <typename T,
73 int&... kExplicitGuard,
74 typename ElementType = std::remove_extent_t<T>,
75 std::enable_if_t<is_unbounded_array_v<T>, int> = 0>
76 [[nodiscard]] ElementType* New(size_t count) {
77 return New<T>(count, alignof(ElementType));
78 }
79
89 template <typename T,
90 int&... kExplicitGuard,
91 typename ElementType = std::remove_extent_t<T>,
92 std::enable_if_t<is_unbounded_array_v<T>, int> = 0>
93 [[nodiscard]] ElementType* New(size_t count, size_t alignment) {
94 void* ptr = Allocate(Layout::Of<T>(count).Align(alignment));
95 return ptr != nullptr ? new (ptr) ElementType[count] : nullptr;
96 }
97
102 template <typename T>
103 T* NewArray(size_t count) {
104 return New<T[]>(count, alignof(T));
105 }
106
111 template <typename T>
112 T* NewArray(size_t count, size_t alignment) {
113 return New<T[]>(count, alignment);
114 }
115
123 template <typename T,
124 int&... kExplicitGuard,
125 std::enable_if_t<!std::is_array_v<T>, int> = 0,
126 typename... Args>
127 [[nodiscard]] UniquePtr<T> MakeUnique(Args&&... args) {
128 return Deallocator::WrapUnique<T>(New<T>(std::forward<Args>(args)...));
129 }
130
138 template <typename T,
139 int&... kExplicitGuard,
140 std::enable_if_t<is_unbounded_array_v<T>, int> = 0>
141 [[nodiscard]] UniquePtr<T> MakeUnique(size_t size) {
142 return MakeUnique<T>(size, alignof(std::remove_extent_t<T>));
143 }
144
154 template <typename T,
155 int&... kExplicitGuard,
156 std::enable_if_t<is_unbounded_array_v<T>, int> = 0>
157 [[nodiscard]] UniquePtr<T> MakeUnique(size_t size, size_t alignment) {
158 return Deallocator::WrapUnique<T>(New<T>(size, alignment), size);
159 }
160
165 template <typename T>
166 [[nodiscard]] UniquePtr<T[]> MakeUniqueArray(size_t size) {
167 return MakeUnique<T[]>(size, alignof(std::remove_extent_t<T>));
168 }
169
174 template <typename T>
175 [[nodiscard]] UniquePtr<T[]> MakeUniqueArray(size_t size, size_t alignment) {
176 return MakeUnique<T[]>(size, alignment);
177 }
178
179 // Disallow calls with explicitly-sized array types like `T[kN]`.
180 template <typename T,
181 int&... kExplicitGuard,
182 std::enable_if_t<is_bounded_array_v<T>, int> = 0,
183 typename... Args>
184 void MakeUnique(Args&&...) = delete;
185
193 template <typename T,
194 int&... kExplicitGuard,
195 std::enable_if_t<!std::is_array_v<T>, int> = 0,
196 typename... Args>
197 [[nodiscard]] SharedPtr<T> MakeShared(Args&&... args) {
198 auto* control_block = ControlBlock::Create(this, Layout::Of<T>(), 1);
199 if (control_block == nullptr) {
200 return nullptr;
201 }
202 auto* t = new (control_block->data()) T(std::forward<Args>(args)...);
203 return SharedPtr<T>(t, control_block);
204 }
205
213 template <typename T,
214 int&... kExplicitGuard,
215 std::enable_if_t<is_unbounded_array_v<T>, int> = 0>
216 [[nodiscard]] SharedPtr<T> MakeShared(size_t size) {
217 return MakeShared<T>(size, alignof(std::remove_extent_t<T>));
218 }
219
229 template <typename T,
230 int&... kExplicitGuard,
231 std::enable_if_t<is_unbounded_array_v<T>, int> = 0>
232 [[nodiscard]] SharedPtr<T> MakeShared(size_t size, size_t alignment) {
233 Layout layout = Layout::Of<T>(size).Align(alignment);
234 auto* control_block = ControlBlock::Create(this, layout, size);
235 if (control_block == nullptr) {
236 return nullptr;
237 }
238 auto* t = new (control_block->data()) std::remove_extent_t<T>[size];
239 return SharedPtr<T>(t, control_block);
240 }
241
242 // Disallow calls with explicitly-sized array types like `T[kN]`.
243 template <typename T,
244 int&... kExplicitGuard,
245 std::enable_if_t<is_bounded_array_v<T>, int> = 0,
246 typename... Args>
247 std::enable_if_t<is_bounded_array_v<T>> MakeShared(Args&&...) = delete;
248
261 bool Resize(void* ptr, size_t new_size) {
262 return ptr != nullptr && new_size != 0 && DoResize(ptr, new_size);
263 }
264
268 bool Resize(void* ptr, Layout layout, size_t new_size) {
269 return ptr != nullptr && new_size != 0 && DoResize(ptr, layout, new_size);
270 }
271
295 void* Reallocate(void* ptr, Layout new_layout) {
296 if (new_layout.size() == 0) {
297 return nullptr;
298 }
299 if (ptr == nullptr) {
300 return Allocate(new_layout);
301 }
302 return DoReallocate(ptr, new_layout);
303 }
304
308 void* Reallocate(void* ptr, Layout old_layout, size_t new_size) {
309 if (new_size == 0) {
310 return nullptr;
311 }
312 if (ptr == nullptr) {
313 return Allocate(Layout(new_size, old_layout.alignment()));
314 }
315 return DoReallocate(ptr, old_layout, new_size);
316 }
317
320 size_t GetAllocated() const { return DoGetAllocated(); }
321
322 protected:
324 constexpr Allocator() = default;
325
326 explicit constexpr Allocator(const Capabilities& capabilities)
327 : Deallocator(capabilities) {}
328
329 private:
334 virtual void* DoAllocate(Layout layout) = 0;
335
343 virtual bool DoResize(void* /*ptr*/, size_t /*new_size*/) { return false; }
344
348 virtual bool DoResize(void*, Layout, size_t) { return false; }
349
359 virtual void* DoReallocate(void* ptr, Layout new_layout);
360
364 virtual void* DoReallocate(void* ptr, Layout old_layout, size_t new_size);
365
370 virtual size_t DoGetAllocated() const { return size_t(-1); }
371};
372
373namespace allocator {
374
375// Alias for module consumers using the older name for the above type.
376using Allocator = ::pw::Allocator;
377
378} // namespace allocator
379} // namespace pw
Definition: allocator.h:34
SharedPtr< T > MakeShared(size_t size)
Definition: allocator.h:216
UniquePtr< T > MakeUnique(size_t size, size_t alignment)
Definition: allocator.h:157
ElementType * New(size_t count, size_t alignment)
Definition: allocator.h:93
SharedPtr< T > MakeShared(Args &&... args)
Definition: allocator.h:197
T * NewArray(size_t count)
Definition: allocator.h:103
virtual bool DoResize(void *, size_t)
Definition: allocator.h:343
virtual size_t DoGetAllocated() const
Definition: allocator.h:370
T * NewArray(size_t count, size_t alignment)
Definition: allocator.h:112
virtual void * DoAllocate(Layout layout)=0
constexpr Allocator()=default
TODO(b/326509341): Remove when downstream consumers migrate.
SharedPtr< T > MakeShared(size_t size, size_t alignment)
Definition: allocator.h:232
bool Resize(void *ptr, size_t new_size)
Definition: allocator.h:261
virtual void * DoReallocate(void *ptr, Layout new_layout)
UniquePtr< T[]> MakeUniqueArray(size_t size)
Definition: allocator.h:166
virtual void * DoReallocate(void *ptr, Layout old_layout, size_t new_size)
void * Reallocate(void *ptr, Layout new_layout)
Definition: allocator.h:295
void * Reallocate(void *ptr, Layout old_layout, size_t new_size)
Definition: allocator.h:308
UniquePtr< T > MakeUnique(Args &&... args)
Definition: allocator.h:127
virtual bool DoResize(void *, Layout, size_t)
Definition: allocator.h:348
std::enable_if_t<!std::is_array_v< T >, T * > New(Args &&... args)
Definition: allocator.h:57
bool Resize(void *ptr, Layout layout, size_t new_size)
Definition: allocator.h:268
void * Allocate(Layout layout)
Definition: allocator.h:45
ElementType * New(size_t count)
Definition: allocator.h:76
UniquePtr< T[]> MakeUniqueArray(size_t size, size_t alignment)
Definition: allocator.h:175
UniquePtr< T > MakeUnique(size_t size)
Definition: allocator.h:141
size_t GetAllocated() const
Definition: allocator.h:320
Abstract interface for releasing memory.
Definition: deallocator.h:26
Definition: shared_ptr.h:44
Definition: unique_ptr.h:40
Definition: capability.h:62
Definition: layout.h:56
Provides basic helpers for reading and writing UTF-8 encoded strings.
Definition: alignment.h:27