C/C++ API Reference
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#ifndef PW_ALLOCATOR_PUBLIC_PW_ALLOCATOR_ALLOCATOR_H_
17#define PW_ALLOCATOR_PUBLIC_PW_ALLOCATOR_ALLOCATOR_H_
18
19#include <cstddef>
20#include <optional>
21
22#include "pw_allocator/capability.h"
23#include "pw_allocator/config.h"
24#include "pw_allocator/deallocator.h"
25#include "pw_allocator/fragmentation.h"
26#include "pw_allocator/layout.h"
27#include "pw_allocator/shared_ptr.h"
28#include "pw_allocator/unique_ptr.h"
29#include "pw_numeric/checked_arithmetic.h"
30#include "pw_result/result.h"
31
32namespace pw {
33
35
36// Forward declare to break a circular dependency with shared_ptr.h.
37template <typename T>
38class SharedPtr;
39
45class Allocator : public Deallocator {
46 public:
53 void* Allocate(Layout layout) {
54 return layout.size() != 0 ? DoAllocate(layout) : nullptr;
55 }
56
65 template <typename T, int&... kExplicitGuard, typename... Args>
66 [[nodiscard]] std::enable_if_t<!std::is_array_v<T>, T*> New(Args&&... args) {
67 void* ptr = Allocate(Layout::Of<T>());
68 return ptr != nullptr ? new (ptr) T(std::forward<Args>(args)...) : nullptr;
69 }
70
79 template <typename T,
80 int&... kExplicitGuard,
81 typename ElementType = std::remove_extent_t<T>,
82 std::enable_if_t<is_bounded_array_v<T>, int> = 0>
83 [[nodiscard]] ElementType* New() {
84 return NewArrayImpl<ElementType>(std::extent_v<T>, alignof(ElementType));
85 }
86
95 template <typename T,
96 int&... kExplicitGuard,
97 typename ElementType = std::remove_extent_t<T>,
98 std::enable_if_t<is_unbounded_array_v<T>, int> = 0>
99 [[nodiscard]] ElementType* New(size_t count) {
100 return NewArrayImpl<ElementType>(count, alignof(ElementType));
101 }
102
104 //
112 template <typename T,
113 int&... kExplicitGuard,
114 typename ElementType = std::remove_extent_t<T>,
115 std::enable_if_t<is_unbounded_array_v<T>, int> = 0>
116 [[nodiscard]] ElementType* New(size_t count, size_t alignment) {
117 return NewArrayImpl<ElementType>(count, alignment);
118 }
119
124 template <typename T>
125 T* NewArray(size_t count) {
126 return New<T[]>(count, alignof(T));
127 }
128
133 template <typename T>
134 T* NewArray(size_t count, size_t alignment) {
135 return New<T[]>(count, alignment);
136 }
137
146 template <typename T,
147 int&... kExplicitGuard,
148 std::enable_if_t<!std::is_array_v<T>, int> = 0,
149 typename... Args>
150 [[nodiscard]] UniquePtr<T> MakeUnique(Args&&... args) {
151 return UniquePtr<T>(New<T>(std::forward<Args>(args)...), *this);
152 }
153
161 template <typename T,
162 int&... kExplicitGuard,
163 std::enable_if_t<is_unbounded_array_v<T>, int> = 0>
164 [[nodiscard]] UniquePtr<T> MakeUnique(size_t size) {
165 return MakeUnique<T>(size, alignof(std::remove_extent_t<T>));
166 }
167
177 template <typename T,
178 int&... kExplicitGuard,
179 std::enable_if_t<is_unbounded_array_v<T>, int> = 0>
180 [[nodiscard]] UniquePtr<T> MakeUnique(size_t size, size_t alignment) {
181 return UniquePtr<T>(New<T>(size, alignment), size, *this);
182 }
183
190 template <typename T,
191 int&... kExplicitGuard,
192 std::enable_if_t<is_bounded_array_v<T>, int> = 0>
193 [[nodiscard]] UniquePtr<T> MakeUnique() {
194 return UniquePtr<T>(New<T>(), std::extent_v<T>, this);
195 }
196
201 template <typename T>
202 [[nodiscard]] UniquePtr<T[]> MakeUniqueArray(size_t size) {
203 return MakeUnique<T[]>(size, alignof(std::remove_extent_t<T>));
204 }
205
210 template <typename T>
211 [[nodiscard]] UniquePtr<T[]> MakeUniqueArray(size_t size, size_t alignment) {
212 return MakeUnique<T[]>(size, alignment);
213 }
214
215// TODO(b/402489948): Remove when portable atomics are provided by `pw_atomic`.
216#if PW_ALLOCATOR_HAS_ATOMICS
217
225 template <typename T,
226 int&... kExplicitGuard,
227 std::enable_if_t<!std::is_array_v<T>, int> = 0,
228 typename... Args>
229 [[nodiscard]] SharedPtr<T> MakeShared(Args&&... args) {
230 return SharedPtr<T>::template Create<Args...>(this,
231 std::forward<Args>(args)...);
232 }
233
241 template <typename T,
242 int&... kExplicitGuard,
243 std::enable_if_t<is_unbounded_array_v<T>, int> = 0>
244 [[nodiscard]] SharedPtr<T> MakeShared(size_t size) {
245 return MakeShared<T>(size, alignof(std::remove_extent_t<T>));
246 }
247
257 template <typename T,
258 int&... kExplicitGuard,
259 std::enable_if_t<is_unbounded_array_v<T>, int> = 0>
260 [[nodiscard]] SharedPtr<T> MakeShared(size_t size, size_t alignment) {
261 return SharedPtr<T>::Create(this, size, alignment);
262 }
263
273 template <typename T,
274 int&... kExplicitGuard,
275 std::enable_if_t<is_bounded_array_v<T>, int> = 0>
276 [[nodiscard]] SharedPtr<T> MakeShared() {
278 this, std::extent_v<T>, alignof(std::remove_extent_t<T>));
279 }
280
281// TODO(b/402489948): Remove when portable atomics are provided by `pw_atomic`.
282#endif // PW_ALLOCATOR_HAS_ATOMICS
283
296 bool Resize(void* ptr, size_t new_size) {
297 return ptr != nullptr && new_size != 0 && DoResize(ptr, new_size);
298 }
299
303 bool Resize(void* ptr, Layout layout, size_t new_size) {
304 return ptr != nullptr && new_size != 0 && DoResize(ptr, layout, new_size);
305 }
306
330 void* Reallocate(void* ptr, Layout new_layout) {
331 if (new_layout.size() == 0) {
332 return nullptr;
333 }
334 if (ptr == nullptr) {
335 return Allocate(new_layout);
336 }
337 return DoReallocate(ptr, new_layout);
338 }
339
343 void* Reallocate(void* ptr, Layout old_layout, size_t new_size) {
344 if (new_size == 0) {
345 return nullptr;
346 }
347 if (ptr == nullptr) {
348 return Allocate(Layout(new_size, old_layout.alignment()));
349 }
350 return DoReallocate(ptr, old_layout, new_size);
351 }
352
355 size_t GetAllocated() const { return DoGetAllocated(); }
356
358 // TODO: https://pwbug.dev/475853116 - Make `pw::Deallocator::GetInfo` return
359 // a `std::variant` to avoid this virtual function.
360 std::optional<allocator::Fragmentation> MeasureFragmentation() const {
361 return DoMeasureFragmentation();
362 }
363
364 protected:
366 constexpr Allocator() = default;
367
368 explicit constexpr Allocator(const Capabilities& capabilities)
369 : Deallocator(Capability::kCanAllocateArbitraryLayout | capabilities) {}
370
376 virtual std::optional<allocator::Fragmentation> DoMeasureFragmentation()
377 const {
378 return std::nullopt;
379 }
380
381 private:
386 virtual void* DoAllocate(Layout layout) = 0;
387
395 virtual bool DoResize([[maybe_unused]] void* ptr,
396 [[maybe_unused]] size_t new_size) {
397 return false;
398 }
399
403 virtual bool DoResize(void*, Layout, size_t) { return false; }
404
414 virtual void* DoReallocate(void* ptr, Layout new_layout);
415
419 virtual void* DoReallocate(void* ptr, Layout old_layout, size_t new_size);
420
425 virtual size_t DoGetAllocated() const { return size_t(-1); }
426
427 // Helper method for allocating arrays of objects.
428 template <typename ElementType>
429 ElementType* NewArrayImpl(size_t count, size_t alignment) {
430 void* ptr = Allocate(Layout::Of<ElementType[]>(count).Align(alignment));
431 return ptr != nullptr ? new (ptr) ElementType[count] : nullptr;
432 }
433};
434
435namespace allocator {
436
437// Alias for module consumers using the older name for the above type.
438using Allocator = ::pw::Allocator;
439
440} // namespace allocator
441
443
444} // namespace pw
445
446#endif // PW_ALLOCATOR_PUBLIC_PW_ALLOCATOR_ALLOCATOR_H_
Definition: allocator.h:45
SharedPtr< T > MakeShared(size_t size)
Definition: allocator.h:244
UniquePtr< T > MakeUnique(size_t size, size_t alignment)
Definition: allocator.h:180
ElementType * New(size_t count, size_t alignment)
Constructs an alignment-byte aligned array of count objects.
Definition: allocator.h:116
SharedPtr< T > MakeShared(Args &&... args)
Definition: allocator.h:229
UniquePtr< T > MakeUnique()
Definition: allocator.h:193
T * NewArray(size_t count)
Definition: allocator.h:125
std::optional< allocator::Fragmentation > MeasureFragmentation() const
Returns fragmentation information for the allocator's memory region.
Definition: allocator.h:360
virtual size_t DoGetAllocated() const
Definition: allocator.h:425
T * NewArray(size_t count, size_t alignment)
Definition: allocator.h:134
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:260
bool Resize(void *ptr, size_t new_size)
Definition: allocator.h:296
virtual void * DoReallocate(void *ptr, Layout new_layout)
UniquePtr< T[]> MakeUniqueArray(size_t size)
Definition: allocator.h:202
virtual void * DoReallocate(void *ptr, Layout old_layout, size_t new_size)
void * Reallocate(void *ptr, Layout new_layout)
Definition: allocator.h:330
void * Reallocate(void *ptr, Layout old_layout, size_t new_size)
Definition: allocator.h:343
UniquePtr< T > MakeUnique(Args &&... args)
Definition: allocator.h:150
virtual bool DoResize(void *, Layout, size_t)
Definition: allocator.h:403
std::enable_if_t<!std::is_array_v< T >, T * > New(Args &&... args)
Definition: allocator.h:66
bool Resize(void *ptr, Layout layout, size_t new_size)
Definition: allocator.h:303
void * Allocate(Layout layout)
Definition: allocator.h:53
SharedPtr< T > MakeShared()
Definition: allocator.h:276
ElementType * New(size_t count)
Definition: allocator.h:99
UniquePtr< T[]> MakeUniqueArray(size_t size, size_t alignment)
Definition: allocator.h:211
ElementType * New()
Definition: allocator.h:83
virtual std::optional< allocator::Fragmentation > DoMeasureFragmentation() const
Definition: allocator.h:376
UniquePtr< T > MakeUnique(size_t size)
Definition: allocator.h:164
size_t GetAllocated() const
Definition: allocator.h:355
virtual bool DoResize(void *ptr, size_t new_size)
Definition: allocator.h:395
Abstract interface for releasing memory.
Definition: deallocator.h:29
Definition: shared_ptr.h:67
Definition: unique_ptr.h:43
Definition: capability.h:65
Definition: layout.h:58
static constexpr std::enable_if_t<!std::is_array_v< T >, Layout > Of()
Creates a Layout for the given type.
Definition: layout.h:68
Capability
Definition: capability.h:28
The Pigweed namespace.
Definition: alignment.h:27