C/C++ API Reference
Loading...
Searching...
No Matches
deallocator.h
1// Copyright 2024 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 "pw_allocator/capability.h"
17#include "pw_allocator/hardening.h"
18#include "pw_allocator/layout.h"
19#include "pw_result/result.h"
20#include "pw_status/status.h"
21#include "pw_status/status_with_size.h"
22
23namespace pw {
24
26
29 protected:
30 // Alias types and variables needed for SFINAE below.
31 template <typename T>
32 static constexpr bool is_bounded_array_v =
33 allocator::internal::is_bounded_array_v<T>;
34
35 template <typename T>
36 static constexpr bool is_unbounded_array_v =
37 allocator::internal::is_unbounded_array_v<T>;
38
39 public:
43
44 virtual ~Deallocator() = default;
45
46 constexpr const Capabilities& capabilities() const { return capabilities_; }
47
49 constexpr bool HasCapability(Capability capability) const {
50 return capabilities_.has(capability);
51 }
52
59 void Deallocate(void* ptr) {
60 if (ptr != nullptr) {
61 DoDeallocate(ptr);
62 }
63 }
64
86 template <typename T,
87 int&... kExplicitGuard,
88 std::enable_if_t<!std::is_array_v<T>, int> = 0>
89 void Delete(T* ptr) {
90 if constexpr (allocator::Hardening::kIncludesDebugChecks) {
91 if (auto result = GetRequestedLayout(ptr); result.ok()) {
92 if constexpr (std::has_virtual_destructor_v<T>) {
93 PW_ASSERT(result->size() >= sizeof(T) &&
94 result->alignment() >= alignof(T));
95 } else {
96 PW_ASSERT(*result == Layout::Of<T>());
97 }
98 }
99 }
100 DeleteArray<T>(ptr, 1);
101 }
102
103 template <typename T,
104 int&... kExplicitGuard,
105 typename ElementType = std::remove_extent_t<T>,
106 std::enable_if_t<is_bounded_array_v<T>, int> = 0>
107 void Delete(ElementType* ptr) {
108 size_t count = std::extent_v<T>;
109 if (count != 0) {
110 DeleteArray<ElementType>(&ptr[0], count);
111 }
112 }
113
114 template <typename T,
115 int&... kExplicitGuard,
116 typename ElementType = std::remove_extent_t<T>,
117 std::enable_if_t<is_unbounded_array_v<T>, int> = 0>
118 void Delete(ElementType* ptr, size_t count) {
119 DeleteArray<ElementType>(ptr, count);
120 }
122
135 template <typename ElementType>
136 void DeleteArray(ElementType* ptr, size_t count) {
137 if (!capabilities_.has(Capability::kSkipsDestroy)) {
138 std::destroy_n(ptr, count);
139 }
140 Deallocate(ptr);
141 }
142
151 auto result = DoGetInfo(InfoType::kCapacity, nullptr);
152 return StatusWithSize(result.status(), Layout::Unwrap(result).size());
153 }
154
165 bool IsEqual(const Deallocator& other) const { return this == &other; }
166
167 protected:
169 constexpr Deallocator() = default;
170
171 explicit constexpr Deallocator(const Capabilities& capabilities)
172 : capabilities_(capabilities) {}
173
202 enum class InfoType {
213 kRequestedLayoutOf,
214
225 kUsableLayoutOf,
226
237 kAllocatedLayoutOf,
238
244 kCapacity,
245
253 kRecognizes,
254 };
255
261 Result<Layout> GetInfo(InfoType info_type, const void* ptr) const {
262 return DoGetInfo(info_type, ptr);
263 }
264
270 static Result<Layout> GetInfo(const Deallocator& deallocator,
271 InfoType info_type,
272 const void* ptr) {
273 return deallocator.DoGetInfo(info_type, ptr);
274 }
275
278 Result<Layout> GetRequestedLayout(const void* ptr) const {
279 return DoGetInfo(InfoType::kRequestedLayoutOf, ptr);
280 }
281
284 static Result<Layout> GetRequestedLayout(const Deallocator& deallocator,
285 const void* ptr) {
286 return deallocator.GetRequestedLayout(ptr);
287 }
288
291 Result<Layout> GetUsableLayout(const void* ptr) const {
292 return DoGetInfo(InfoType::kUsableLayoutOf, ptr);
293 }
294
297 static Result<Layout> GetUsableLayout(const Deallocator& deallocator,
298 const void* ptr) {
299 return deallocator.GetUsableLayout(ptr);
300 }
301
304 Result<Layout> GetAllocatedLayout(const void* ptr) const {
305 return DoGetInfo(InfoType::kAllocatedLayoutOf, ptr);
306 }
307
310 static Result<Layout> GetAllocatedLayout(const Deallocator& deallocator,
311 const void* ptr) {
312 return deallocator.GetAllocatedLayout(ptr);
313 }
314
317 bool Recognizes(const void* ptr) const {
318 return DoGetInfo(InfoType::kRecognizes, ptr).ok();
319 }
320
323 static bool Recognizes(const Deallocator& deallocator, const void* ptr) {
324 return deallocator.Recognizes(ptr);
325 }
326
327 private:
331 virtual void DoDeallocate([[maybe_unused]] void* ptr) = 0;
332
334 virtual Result<Layout> DoGetInfo(InfoType, const void*) const {
335 return Status::Unimplemented();
336 }
337
338 const Capabilities capabilities_;
339};
340
342
343} // namespace pw
Abstract interface for releasing memory.
Definition: deallocator.h:28
static constexpr Status Unimplemented()
Definition: status.h:280
Definition: status_with_size.h:51
Definition: capability.h:65
Definition: layout.h:58
static constexpr Layout Unwrap(const Result< Layout > &result)
Definition: layout.h:91
void Delete(T *ptr)
Definition: deallocator.h:89
StatusWithSize GetCapacity() const
Definition: deallocator.h:150
void DeleteArray(ElementType *ptr, size_t count)
Definition: deallocator.h:136
void Deallocate(void *ptr)
Definition: deallocator.h:59
constexpr bool HasCapability(Capability capability) const
Returns whether a given capability is enabled for this object.
Definition: deallocator.h:49
Capability
Definition: capability.h:28
bool IsEqual(const Deallocator &other) const
Definition: deallocator.h:165
constexpr Deallocator()=default
TODO(b/326509341): Remove when downstream consumers migrate.
The Pigweed namespace.
Definition: alignment.h:27