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
21#include "pw_allocator/capability.h"
22#include "pw_allocator/config.h"
23#include "pw_allocator/deallocator.h"
24#include "pw_allocator/layout.h"
25#include "pw_allocator/shared_ptr.h"
26#include "pw_allocator/unique_ptr.h"
27#include "pw_numeric/checked_arithmetic.h"
28#include "pw_result/result.h"
29
30namespace pw {
31
33
34// Forward declare to break a circular dependency with shared_ptr.h.
35template <typename T>
36class SharedPtr;
37
43class Allocator : public Deallocator {
44 public:
51 void* Allocate(Layout layout) {
52 return layout.size() != 0 ? DoAllocate(layout) : nullptr;
53 }
54
63 template <typename T, int&... kExplicitGuard, typename... Args>
64 [[nodiscard]] std::enable_if_t<!std::is_array_v<T>, T*> New(Args&&... args) {
65 void* ptr = Allocate(Layout::Of<T>());
66 return ptr != nullptr ? new (ptr) T(std::forward<Args>(args)...) : nullptr;
67 }
68
77 template <typename T,
78 int&... kExplicitGuard,
79 typename ElementType = std::remove_extent_t<T>,
80 std::enable_if_t<is_bounded_array_v<T>, int> = 0>
81 [[nodiscard]] ElementType* New() {
82 return NewArrayImpl<ElementType>(std::extent_v<T>, alignof(ElementType));
83 }
84
93 template <typename T,
94 int&... kExplicitGuard,
95 typename ElementType = std::remove_extent_t<T>,
96 std::enable_if_t<is_unbounded_array_v<T>, int> = 0>
97 [[nodiscard]] ElementType* New(size_t count) {
98 return NewArrayImpl<ElementType>(count, alignof(ElementType));
99 }
100
102 //
110 template <typename T,
111 int&... kExplicitGuard,
112 typename ElementType = std::remove_extent_t<T>,
113 std::enable_if_t<is_unbounded_array_v<T>, int> = 0>
114 [[nodiscard]] ElementType* New(size_t count, size_t alignment) {
115 return NewArrayImpl<ElementType>(count, alignment);
116 }
117
122 template <typename T>
123 T* NewArray(size_t count) {
124 return New<T[]>(count, alignof(T));
125 }
126
131 template <typename T>
132 T* NewArray(size_t count, size_t alignment) {
133 return New<T[]>(count, alignment);
134 }
135
144 template <typename T,
145 int&... kExplicitGuard,
146 std::enable_if_t<!std::is_array_v<T>, int> = 0,
147 typename... Args>
148 [[nodiscard]] UniquePtr<T> MakeUnique(Args&&... args) {
149 return UniquePtr<T>(New<T>(std::forward<Args>(args)...), *this);
150 }
151
159 template <typename T,
160 int&... kExplicitGuard,
161 std::enable_if_t<is_unbounded_array_v<T>, int> = 0>
162 [[nodiscard]] UniquePtr<T> MakeUnique(size_t size) {
163 return MakeUnique<T>(size, alignof(std::remove_extent_t<T>));
164 }
165
175 template <typename T,
176 int&... kExplicitGuard,
177 std::enable_if_t<is_unbounded_array_v<T>, int> = 0>
178 [[nodiscard]] UniquePtr<T> MakeUnique(size_t size, size_t alignment) {
179 return UniquePtr<T>(New<T>(size, alignment), size, *this);
180 }
181
188 template <typename T,
189 int&... kExplicitGuard,
190 std::enable_if_t<is_bounded_array_v<T>, int> = 0>
191 [[nodiscard]] UniquePtr<T> MakeUnique() {
192 return UniquePtr<T>(New<T>(), std::extent_v<T>, this);
193 }
194
199 template <typename T>
200 [[nodiscard]] UniquePtr<T[]> MakeUniqueArray(size_t size) {
201 return MakeUnique<T[]>(size, alignof(std::remove_extent_t<T>));
202 }
203
208 template <typename T>
209 [[nodiscard]] UniquePtr<T[]> MakeUniqueArray(size_t size, size_t alignment) {
210 return MakeUnique<T[]>(size, alignment);
211 }
212
213// TODO(b/402489948): Remove when portable atomics are provided by `pw_atomic`.
214#if PW_ALLOCATOR_HAS_ATOMICS
215
223 template <typename T,
224 int&... kExplicitGuard,
225 std::enable_if_t<!std::is_array_v<T>, int> = 0,
226 typename... Args>
227 [[nodiscard]] SharedPtr<T> MakeShared(Args&&... args) {
228 return SharedPtr<T>::template Create<Args...>(this,
229 std::forward<Args>(args)...);
230 }
231
239 template <typename T,
240 int&... kExplicitGuard,
241 std::enable_if_t<is_unbounded_array_v<T>, int> = 0>
242 [[nodiscard]] SharedPtr<T> MakeShared(size_t size) {
243 return MakeShared<T>(size, alignof(std::remove_extent_t<T>));
244 }
245
255 template <typename T,
256 int&... kExplicitGuard,
257 std::enable_if_t<is_unbounded_array_v<T>, int> = 0>
258 [[nodiscard]] SharedPtr<T> MakeShared(size_t size, size_t alignment) {
259 return SharedPtr<T>::Create(this, size, alignment);
260 }
261
271 template <typename T,
272 int&... kExplicitGuard,
273 std::enable_if_t<is_bounded_array_v<T>, int> = 0>
274 [[nodiscard]] SharedPtr<T> MakeShared() {
276 this, std::extent_v<T>, alignof(std::remove_extent_t<T>));
277 }
278
279// TODO(b/402489948): Remove when portable atomics are provided by `pw_atomic`.
280#endif // PW_ALLOCATOR_HAS_ATOMICS
281
294 bool Resize(void* ptr, size_t new_size) {
295 return ptr != nullptr && new_size != 0 && DoResize(ptr, new_size);
296 }
297
301 bool Resize(void* ptr, Layout layout, size_t new_size) {
302 return ptr != nullptr && new_size != 0 && DoResize(ptr, layout, new_size);
303 }
304
328 void* Reallocate(void* ptr, Layout new_layout) {
329 if (new_layout.size() == 0) {
330 return nullptr;
331 }
332 if (ptr == nullptr) {
333 return Allocate(new_layout);
334 }
335 return DoReallocate(ptr, new_layout);
336 }
337
341 void* Reallocate(void* ptr, Layout old_layout, size_t new_size) {
342 if (new_size == 0) {
343 return nullptr;
344 }
345 if (ptr == nullptr) {
346 return Allocate(Layout(new_size, old_layout.alignment()));
347 }
348 return DoReallocate(ptr, old_layout, new_size);
349 }
350
353 size_t GetAllocated() const { return DoGetAllocated(); }
354
355 protected:
357 constexpr Allocator() = default;
358
359 explicit constexpr Allocator(const Capabilities& capabilities)
360 : Deallocator(Capability::kCanAllocateArbitraryLayout | capabilities) {}
361
362 private:
367 virtual void* DoAllocate(Layout layout) = 0;
368
376 virtual bool DoResize([[maybe_unused]] void* ptr,
377 [[maybe_unused]] size_t new_size) {
378 return false;
379 }
380
384 virtual bool DoResize(void*, Layout, size_t) { return false; }
385
395 virtual void* DoReallocate(void* ptr, Layout new_layout);
396
400 virtual void* DoReallocate(void* ptr, Layout old_layout, size_t new_size);
401
406 virtual size_t DoGetAllocated() const { return size_t(-1); }
407
408 // Helper method for allocating arrays of objects.
409 template <typename ElementType>
410 ElementType* NewArrayImpl(size_t count, size_t alignment) {
411 void* ptr = Allocate(Layout::Of<ElementType[]>(count).Align(alignment));
412 return ptr != nullptr ? new (ptr) ElementType[count] : nullptr;
413 }
414};
415
416namespace allocator {
417
418// Alias for module consumers using the older name for the above type.
419using Allocator = ::pw::Allocator;
420
421} // namespace allocator
422
424
425} // namespace pw
426
427#endif // PW_ALLOCATOR_PUBLIC_PW_ALLOCATOR_ALLOCATOR_H_
Definition: allocator.h:43
SharedPtr< T > MakeShared(size_t size)
Definition: allocator.h:242
UniquePtr< T > MakeUnique(size_t size, size_t alignment)
Definition: allocator.h:178
ElementType * New(size_t count, size_t alignment)
Constructs an alignment-byte aligned array of count objects.
Definition: allocator.h:114
SharedPtr< T > MakeShared(Args &&... args)
Definition: allocator.h:227
UniquePtr< T > MakeUnique()
Definition: allocator.h:191
T * NewArray(size_t count)
Definition: allocator.h:123
virtual size_t DoGetAllocated() const
Definition: allocator.h:406
T * NewArray(size_t count, size_t alignment)
Definition: allocator.h:132
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:258
bool Resize(void *ptr, size_t new_size)
Definition: allocator.h:294
virtual void * DoReallocate(void *ptr, Layout new_layout)
UniquePtr< T[]> MakeUniqueArray(size_t size)
Definition: allocator.h:200
virtual void * DoReallocate(void *ptr, Layout old_layout, size_t new_size)
void * Reallocate(void *ptr, Layout new_layout)
Definition: allocator.h:328
void * Reallocate(void *ptr, Layout old_layout, size_t new_size)
Definition: allocator.h:341
UniquePtr< T > MakeUnique(Args &&... args)
Definition: allocator.h:148
virtual bool DoResize(void *, Layout, size_t)
Definition: allocator.h:384
std::enable_if_t<!std::is_array_v< T >, T * > New(Args &&... args)
Definition: allocator.h:64
bool Resize(void *ptr, Layout layout, size_t new_size)
Definition: allocator.h:301
void * Allocate(Layout layout)
Definition: allocator.h:51
SharedPtr< T > MakeShared()
Definition: allocator.h:274
ElementType * New(size_t count)
Definition: allocator.h:97
UniquePtr< T[]> MakeUniqueArray(size_t size, size_t alignment)
Definition: allocator.h:209
ElementType * New()
Definition: allocator.h:81
UniquePtr< T > MakeUnique(size_t size)
Definition: allocator.h:162
size_t GetAllocated() const
Definition: allocator.h:353
virtual bool DoResize(void *ptr, size_t new_size)
Definition: allocator.h:376
Abstract interface for releasing memory.
Definition: deallocator.h:29
Definition: shared_ptr.h:63
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