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#include <cstddef>
17#include <optional>
18
19#include "pw_allocator/capability.h"
20#include "pw_allocator/config.h"
21#include "pw_allocator/deallocator.h"
22#include "pw_allocator/fragmentation.h"
23#include "pw_allocator/layout.h"
24#include "pw_allocator/shared_ptr.h"
25#include "pw_allocator/unique_ptr.h"
26#include "pw_numeric/checked_arithmetic.h"
27#include "pw_result/result.h"
28
29namespace pw {
30
32
33// Forward declare to break a circular dependency with shared_ptr.h.
34template <typename T>
35class SharedPtr;
36
42class Allocator : public Deallocator {
43 public:
50 void* Allocate(Layout layout) {
51 return layout.size() != 0 ? DoAllocate(layout) : nullptr;
52 }
53
62 template <typename T, int&... kExplicitGuard, typename... Args>
63 [[nodiscard]] std::enable_if_t<!std::is_array_v<T>, T*> New(Args&&... args) {
64 void* ptr = Allocate(Layout::Of<T>());
65 return ptr != nullptr ? new (ptr) T(std::forward<Args>(args)...) : nullptr;
66 }
67
76 template <typename T,
77 int&... kExplicitGuard,
78 typename ElementType = std::remove_extent_t<T>,
79 std::enable_if_t<is_bounded_array_v<T>, int> = 0>
80 [[nodiscard]] ElementType* New() {
81 return NewArrayImpl<ElementType>(std::extent_v<T>, alignof(ElementType));
82 }
83
92 template <typename T,
93 int&... kExplicitGuard,
94 typename ElementType = std::remove_extent_t<T>,
95 std::enable_if_t<is_unbounded_array_v<T>, int> = 0>
96 [[nodiscard]] ElementType* New(size_t count) {
97 return NewArrayImpl<ElementType>(count, alignof(ElementType));
98 }
99
101 //
109 template <typename T,
110 int&... kExplicitGuard,
111 typename ElementType = std::remove_extent_t<T>,
112 std::enable_if_t<is_unbounded_array_v<T>, int> = 0>
113 [[nodiscard]] ElementType* New(size_t count, size_t alignment) {
114 return NewArrayImpl<ElementType>(count, alignment);
115 }
116
125 template <typename T,
126 int&... kExplicitGuard,
127 std::enable_if_t<!std::is_array_v<T>, int> = 0,
128 typename... Args>
129 [[nodiscard]] UniquePtr<T> MakeUnique(Args&&... args) {
130 return UniquePtr<T>(New<T>(std::forward<Args>(args)...), *this);
131 }
132
140 template <typename T,
141 int&... kExplicitGuard,
142 std::enable_if_t<is_unbounded_array_v<T>, int> = 0>
143 [[nodiscard]] UniquePtr<T> MakeUnique(size_t size) {
144 return MakeUnique<T>(size, alignof(std::remove_extent_t<T>));
145 }
146
156 template <typename T,
157 int&... kExplicitGuard,
158 std::enable_if_t<is_unbounded_array_v<T>, int> = 0>
159 [[nodiscard]] UniquePtr<T> MakeUnique(size_t size, size_t alignment) {
160 return UniquePtr<T>(New<T>(size, alignment), size, *this);
161 }
162
169 template <typename T,
170 int&... kExplicitGuard,
171 std::enable_if_t<is_bounded_array_v<T>, int> = 0>
172 [[nodiscard]] UniquePtr<T> MakeUnique() {
173 return UniquePtr<T>(New<T>(), std::extent_v<T>, this);
174 }
175
176// TODO(b/402489948): Remove when portable atomics are provided by `pw_atomic`.
177#if PW_ALLOCATOR_HAS_ATOMICS
178
186 template <typename T,
187 int&... kExplicitGuard,
188 std::enable_if_t<!std::is_array_v<T>, int> = 0,
189 typename... Args>
190 [[nodiscard]] SharedPtr<T> MakeShared(Args&&... args) {
191 return SharedPtr<T>::template Create<Args...>(this,
192 std::forward<Args>(args)...);
193 }
194
202 template <typename T,
203 int&... kExplicitGuard,
204 std::enable_if_t<is_unbounded_array_v<T>, int> = 0>
205 [[nodiscard]] SharedPtr<T> MakeShared(size_t size) {
206 return MakeShared<T>(size, alignof(std::remove_extent_t<T>));
207 }
208
218 template <typename T,
219 int&... kExplicitGuard,
220 std::enable_if_t<is_unbounded_array_v<T>, int> = 0>
221 [[nodiscard]] SharedPtr<T> MakeShared(size_t size, size_t alignment) {
222 return SharedPtr<T>::Create(this, size, alignment);
223 }
224
234 template <typename T,
235 int&... kExplicitGuard,
236 std::enable_if_t<is_bounded_array_v<T>, int> = 0>
237 [[nodiscard]] SharedPtr<T> MakeShared() {
239 this, std::extent_v<T>, alignof(std::remove_extent_t<T>));
240 }
241
242// TODO(b/402489948): Remove when portable atomics are provided by `pw_atomic`.
243#endif // PW_ALLOCATOR_HAS_ATOMICS
244
257 bool Resize(void* ptr, size_t new_size) {
258 return ptr != nullptr && new_size != 0 && DoResize(ptr, new_size);
259 }
260
284 void* Reallocate(void* ptr, Layout new_layout) {
285 if (new_layout.size() == 0) {
286 return nullptr;
287 }
288 if (ptr == nullptr) {
289 return Allocate(new_layout);
290 }
291 return DoReallocate(ptr, new_layout);
292 }
293
296 size_t GetAllocated() const { return DoGetAllocated(); }
297
299 // TODO: https://pwbug.dev/475853116 - Make `pw::Deallocator::GetInfo` return
300 // a `std::variant` to avoid this virtual function.
301 std::optional<allocator::Fragmentation> MeasureFragmentation() const {
302 return DoMeasureFragmentation();
303 }
304
305 protected:
307 constexpr Allocator() = default;
308
309 explicit constexpr Allocator(const Capabilities& capabilities)
310 : Deallocator(Capability::kCanAllocateArbitraryLayout | capabilities) {}
311
317 virtual std::optional<allocator::Fragmentation> DoMeasureFragmentation()
318 const {
319 return std::nullopt;
320 }
321
322 private:
327 virtual void* DoAllocate(Layout layout) = 0;
328
336 virtual bool DoResize([[maybe_unused]] void* ptr,
337 [[maybe_unused]] size_t new_size) {
338 return false;
339 }
340
350 virtual void* DoReallocate(void* ptr, Layout new_layout);
351
356 virtual size_t DoGetAllocated() const { return size_t(-1); }
357
358 // Helper method for allocating arrays of objects.
359 template <typename ElementType>
360 ElementType* NewArrayImpl(size_t count, size_t alignment) {
361 void* ptr = Allocate(Layout::Of<ElementType[]>(count).Align(alignment));
362 return ptr != nullptr ? new (ptr) ElementType[count] : nullptr;
363 }
364};
365
366namespace allocator {
367
368// TODO(b/376730645): This deprecated alias cannot be removed yet due to a
369// downstream dependency.
370using Allocator [[deprecated("Use pw::Allocator instead")]] = ::pw::Allocator;
371
372} // namespace allocator
373
375
376} // namespace pw
Definition: allocator.h:42
SharedPtr< T > MakeShared(size_t size)
Definition: allocator.h:205
UniquePtr< T > MakeUnique(size_t size, size_t alignment)
Definition: allocator.h:159
ElementType * New(size_t count, size_t alignment)
Constructs an alignment-byte aligned array of count objects.
Definition: allocator.h:113
SharedPtr< T > MakeShared(Args &&... args)
Definition: allocator.h:190
UniquePtr< T > MakeUnique()
Definition: allocator.h:172
std::optional< allocator::Fragmentation > MeasureFragmentation() const
Returns fragmentation information for the allocator's memory region.
Definition: allocator.h:301
virtual size_t DoGetAllocated() const
Definition: allocator.h:356
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:221
bool Resize(void *ptr, size_t new_size)
Definition: allocator.h:257
virtual void * DoReallocate(void *ptr, Layout new_layout)
void * Reallocate(void *ptr, Layout new_layout)
Definition: allocator.h:284
UniquePtr< T > MakeUnique(Args &&... args)
Definition: allocator.h:129
std::enable_if_t<!std::is_array_v< T >, T * > New(Args &&... args)
Definition: allocator.h:63
void * Allocate(Layout layout)
Definition: allocator.h:50
SharedPtr< T > MakeShared()
Definition: allocator.h:237
ElementType * New(size_t count)
Definition: allocator.h:96
ElementType * New()
Definition: allocator.h:80
virtual std::optional< allocator::Fragmentation > DoMeasureFragmentation() const
Definition: allocator.h:317
UniquePtr< T > MakeUnique(size_t size)
Definition: allocator.h:143
size_t GetAllocated() const
Definition: allocator.h:296
virtual bool DoResize(void *ptr, size_t new_size)
Definition: allocator.h:336
Abstract interface for releasing memory.
Definition: deallocator.h:28
Definition: shared_ptr.h:64
static SharedPtr Create(Allocator *allocator, Args &&... args)
Definition: unique_ptr.h:44
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