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 <memory>
17
18#include "pw_allocator/capability.h"
19#include "pw_allocator/hardening.h"
20#include "pw_allocator/layout.h"
21#include "pw_result/result.h"
22#include "pw_status/status.h"
23#include "pw_status/status_with_size.h"
24
25namespace pw {
26
28
31 public:
35
36 virtual ~Deallocator() = default;
37
38 constexpr const Capabilities& capabilities() const { return capabilities_; }
39
41 constexpr bool HasCapability(Capability capability) const {
42 return capabilities_.has(capability);
43 }
44
51 inline void Deallocate(void* ptr);
52
74 template <typename T,
75 int&... kExplicitGuard,
76 std::enable_if_t<!std::is_array_v<T>, int> = 0>
77 void Delete(T* ptr);
78
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 void Delete(ElementType* ptr);
84
85 template <typename T,
86 int&... kExplicitGuard,
87 typename ElementType = std::remove_extent_t<T>,
88 std::enable_if_t<is_unbounded_array_v<T>, int> = 0>
89 void Delete(ElementType* ptr, size_t count);
91
104 template <typename ElementType>
105 void DeleteArray(ElementType* ptr, size_t count);
106
114 inline StatusWithSize GetCapacity() const;
115
126 bool IsEqual(const Deallocator& other) const { return this == &other; }
127
128 protected:
129 // There are downstream consumers that have implemented Allocators outside the
130 // `pw` namespace, and that use unqualified names for `is_[un]bounded_array`.
131 template <typename T>
132 static constexpr bool is_bounded_array_v = ::pw::is_bounded_array_v<T>;
133
134 template <typename T>
135 static constexpr bool is_unbounded_array_v = ::pw::is_unbounded_array_v<T>;
136
138 constexpr Deallocator() = default;
139
140 explicit constexpr Deallocator(const Capabilities& capabilities)
141 : capabilities_(capabilities) {}
142
173 enum class InfoType {
185
189
197
209
215 kCapacity,
216
225 };
226
232 Result<Layout> GetInfo(InfoType info_type, const void* ptr) const {
233 return DoGetInfo(info_type, ptr);
234 }
235
241 static Result<Layout> GetInfo(const Deallocator& deallocator,
242 InfoType info_type,
243 const void* ptr) {
244 return deallocator.DoGetInfo(info_type, ptr);
245 }
246
249 Result<Layout> GetRequestedLayout(const void* ptr) const {
251 }
252
256 const void* ptr) {
257 return deallocator.GetRequestedLayout(ptr);
258 }
259
262 Result<Layout> GetUsableLayout(const void* ptr) const {
264 }
265
268 static Result<Layout> GetUsableLayout(const Deallocator& deallocator,
269 const void* ptr) {
270 return deallocator.GetUsableLayout(ptr);
271 }
272
275 Result<Layout> GetAllocatedLayout(const void* ptr) const {
277 }
278
282 const void* ptr) {
283 return deallocator.GetAllocatedLayout(ptr);
284 }
285
288 bool Recognizes(const void* ptr) const {
289 return DoGetInfo(InfoType::kRecognizes, ptr).ok();
290 }
291
294 static bool Recognizes(const Deallocator& deallocator, const void* ptr) {
295 return deallocator.Recognizes(ptr);
296 }
297
299 virtual void DoDeallocate([[maybe_unused]] void* ptr) = 0;
300
304 virtual Result<Layout> DoGetInfo(InfoType, const void*) const {
305 return Status::Unimplemented();
306 }
307
308 private:
309 const Capabilities capabilities_;
310};
311
313
314// Template and inline method implementations.
315
316void Deallocator::Deallocate(void* ptr) {
317 if (ptr != nullptr) {
318 DoDeallocate(ptr);
319 }
320}
321
322template <typename T,
323 int&... kExplicitGuard,
324 std::enable_if_t<!std::is_array_v<T>, int>>
326 if constexpr (allocator::Hardening::kIncludesDebugChecks) {
327 if (auto result = GetRequestedLayout(ptr); result.ok()) {
328 if constexpr (std::has_virtual_destructor_v<T>) {
329 PW_ASSERT(result->size() >= sizeof(T) &&
330 result->alignment() >= alignof(T));
331 } else {
332 PW_ASSERT(*result == Layout::Of<T>());
333 }
334 }
335 }
336 DeleteArray<T>(ptr, 1);
337}
338
339template <typename T,
340 int&... kExplicitGuard,
341 typename ElementType,
342 std::enable_if_t<is_bounded_array_v<T>, int>>
343void Deallocator::Delete(ElementType* ptr) {
344 size_t count = std::extent_v<T>;
345 if (count != 0) {
346 DeleteArray<ElementType>(&ptr[0], count);
347 }
348}
349
350template <typename T,
351 int&... kExplicitGuard,
352 typename ElementType,
353 std::enable_if_t<is_unbounded_array_v<T>, int>>
354void Deallocator::Delete(ElementType* ptr, size_t count) {
355 DeleteArray<ElementType>(ptr, count);
356}
357
358template <typename ElementType>
359void Deallocator::DeleteArray(ElementType* ptr, size_t count) {
360 if (!capabilities_.has(Capability::kSkipsDestroy)) {
361 std::destroy_n(ptr, count);
362 }
363 Deallocate(ptr);
364}
365
367 auto result = DoGetInfo(InfoType::kCapacity, nullptr);
368 return StatusWithSize(result.status(), Layout::Unwrap(result).size());
369}
370
371} // namespace pw
Abstract interface for releasing memory.
Definition: deallocator.h:30
bool Recognizes(const void *ptr) const
Definition: deallocator.h:288
static Result< Layout > GetRequestedLayout(const Deallocator &deallocator, const void *ptr)
Definition: deallocator.h:255
virtual void DoDeallocate(void *ptr)=0
Result< Layout > GetUsableLayout(const void *ptr) const
Definition: deallocator.h:262
static Result< Layout > GetInfo(const Deallocator &deallocator, InfoType info_type, const void *ptr)
Definition: deallocator.h:241
virtual Result< Layout > DoGetInfo(InfoType, const void *) const
Definition: deallocator.h:304
void Delete(T *ptr)
Definition: deallocator.h:325
StatusWithSize GetCapacity() const
Definition: deallocator.h:366
Result< Layout > GetRequestedLayout(const void *ptr) const
Definition: deallocator.h:249
InfoType
Definition: deallocator.h:173
void DeleteArray(ElementType *ptr, size_t count)
Definition: deallocator.h:359
void Deallocate(void *ptr)
Definition: deallocator.h:316
constexpr bool HasCapability(Capability capability) const
Returns whether a given capability is enabled for this object.
Definition: deallocator.h:41
Result< Layout > GetAllocatedLayout(const void *ptr) const
Definition: deallocator.h:275
static Result< Layout > GetUsableLayout(const Deallocator &deallocator, const void *ptr)
Definition: deallocator.h:268
Result< Layout > GetInfo(InfoType info_type, const void *ptr) const
Definition: deallocator.h:232
static Result< Layout > GetAllocatedLayout(const Deallocator &deallocator, const void *ptr)
Definition: deallocator.h:281
static bool Recognizes(const Deallocator &deallocator, const void *ptr)
Definition: deallocator.h:294
bool IsEqual(const Deallocator &other) const
Definition: deallocator.h:126
constexpr Deallocator()=default
TODO(b/326509341): Remove when downstream consumers migrate.
Definition: result.h:145
static constexpr Status Unimplemented()
Definition: status.h:280
Definition: status_with_size.h:51
Definition: capability.h:65
Definition: layout.h:64
static constexpr Layout Unwrap(const Result< Layout > &result)
Definition: layout.h:93
Capability
Definition: capability.h:28
The Pigweed namespace.
Definition: alignment.h:27