21#include "pw_allocator/block/alignable.h"
22#include "pw_allocator/block/allocatable.h"
23#include "pw_allocator/block/basic.h"
24#include "pw_allocator/block/contiguous.h"
25#include "pw_allocator/block/iterable.h"
26#include "pw_allocator/block/poisonable.h"
27#include "pw_allocator/block/result.h"
28#include "pw_allocator/block/with_layout.h"
29#include "pw_allocator/hardening.h"
30#include "pw_allocator/layout.h"
31#include "pw_assert/assert.h"
32#include "pw_bytes/span.h"
33#include "pw_status/status.h"
35namespace pw::allocator {
48template <
typename OffsetType_,
typename WhenFree>
50 using OffsetType = std::make_unsigned_t<OffsetType_>;
51 static constexpr Layout kLayoutWhenFree = Layout::Of<WhenFree>();
54template <
typename OffsetType_>
56 using OffsetType = std::make_unsigned_t<OffsetType_>;
80template <
typename Parameters>
82 :
public BasicBlock<DetailedBlockImpl<Parameters>>,
94 using OffsetType =
typename Parameters::OffsetType;
104 static constexpr size_t DefaultAlignment();
105 static constexpr size_t BlockOverhead();
106 static constexpr size_t MinInnerSize();
107 static constexpr size_t ReservedWhenFree();
108 constexpr size_t OuterSizeUnchecked()
const;
111 constexpr bool DoCheckInvariants(
bool strict)
const;
117 static constexpr size_t MaxAddressableSize();
118 constexpr bool IsLastUnchecked()
const {
return info_.last != 0; }
120 constexpr void SetNext(
size_t outer_size,
BlockType* next);
121 constexpr size_t PrevOuterSizeUnchecked()
const;
124 constexpr BlockType* DoSplitFirst(
size_t new_inner_size);
125 constexpr BlockType* DoSplitLast(
size_t new_inner_size);
126 constexpr void DoMergeNext();
131 constexpr bool IsFreeUnchecked()
const {
return info_.used == 0; }
132 constexpr void SetFree(
bool is_free);
143 bool shifted =
false);
149 constexpr size_t RequestedSize()
const;
150 constexpr size_t RequestedAlignment()
const {
return info_.alignment; }
151 constexpr void SetRequestedSize(
size_t size);
152 constexpr void SetRequestedAlignment(
size_t alignment);
157 constexpr bool IsPoisonedUnchecked()
const {
return info_.poisoned != 0; }
158 constexpr void SetPoisoned(
bool is_poisoned) { info_.poisoned = is_poisoned; }
162 OffsetType prev_ = 0;
167 OffsetType next_ = 0;
181 uint16_t poisoned : 1;
183 uint16_t alignment : 13;
188 uint16_t padding_ = 0;
192template <
typename OffsetType = u
intptr_t,
typename WhenFree =
void>
200template <
typename Parameters>
203 next_ =
static_cast<OffsetType
>(outer_size / Basic::kAlignment);
205 info_.alignment = Basic::kAlignment;
210template <
typename Parameters>
211constexpr size_t DetailedBlockImpl<Parameters>::DefaultAlignment() {
212 return std::max(
alignof(OffsetType), Parameters::kLayoutWhenFree.alignment());
215template <
typename Parameters>
216constexpr size_t DetailedBlockImpl<Parameters>::BlockOverhead() {
217 return sizeof(BlockType);
220template <
typename Parameters>
221constexpr size_t DetailedBlockImpl<Parameters>::MinInnerSize() {
225template <
typename Parameters>
226constexpr size_t DetailedBlockImpl<Parameters>::ReservedWhenFree() {
227 return Parameters::kLayoutWhenFree.size();
230template <
typename Parameters>
231constexpr size_t DetailedBlockImpl<Parameters>::OuterSizeUnchecked()
const {
232 size_t outer_size = next_;
233 Hardening::Multiply(outer_size, Basic::kAlignment);
237template <
typename Parameters>
238constexpr bool DetailedBlockImpl<Parameters>::DoCheckInvariants(
240 return Basic::DoCheckInvariants(strict) &&
241 Contiguous::DoCheckInvariants(strict) &&
242 Poisonable::DoCheckInvariants(strict);
247template <
typename Parameters>
248constexpr size_t DetailedBlockImpl<Parameters>::MaxAddressableSize() {
249 auto kOffsetMax =
static_cast<size_t>(std::numeric_limits<OffsetType>::max());
250 auto kSizeMax = std::numeric_limits<size_t>::max();
251 return std::min(kSizeMax / Basic::kAlignment, kOffsetMax) * Basic::kAlignment;
254template <
typename Parameters>
255constexpr DetailedBlockImpl<Parameters>* DetailedBlockImpl<Parameters>::AsBlock(
257 return ::new (bytes.data()) DetailedBlockImpl(bytes.size());
260template <typename Parameters>
261constexpr
void DetailedBlockImpl<Parameters>::SetNext(
size_t outer_size,
263 next_ =
static_cast<OffsetType
>(outer_size / Basic::kAlignment);
264 if (next ==
nullptr) {
272template <
typename Parameters>
273constexpr size_t DetailedBlockImpl<Parameters>::PrevOuterSizeUnchecked()
const {
274 size_t outer_size = prev_;
275 Hardening::Multiply(outer_size, Basic::kAlignment);
279template <
typename Parameters>
280constexpr DetailedBlockImpl<Parameters>*
281DetailedBlockImpl<Parameters>::DoSplitFirst(
size_t new_inner_size) {
282 return Poisonable::DoSplitFirst(new_inner_size);
285template <
typename Parameters>
286constexpr DetailedBlockImpl<Parameters>*
287DetailedBlockImpl<Parameters>::DoSplitLast(
size_t new_inner_size) {
288 return Poisonable::DoSplitLast(new_inner_size);
291template <
typename Parameters>
292constexpr void DetailedBlockImpl<Parameters>::DoMergeNext() {
293 Poisonable::DoMergeNext();
298template <
typename Parameters>
299constexpr void DetailedBlockImpl<Parameters>::SetFree(
bool is_free) {
300 info_.used = !is_free;
302 Poisonable::SetFree(is_free);
307template <
typename Parameters>
308constexpr StatusWithSize DetailedBlockImpl<Parameters>::DoCanAlloc(
309 Layout layout)
const {
310 return Alignable::DoCanAlloc(layout);
313template <
typename Parameters>
314constexpr BlockResult<DetailedBlockImpl<Parameters>>
315DetailedBlockImpl<Parameters>::DoAllocFirst(DetailedBlockImpl*&& block,
317 return WithLayout::DoAllocFirst(std::move(block), layout);
320template <
typename Parameters>
321constexpr BlockResult<DetailedBlockImpl<Parameters>>
322DetailedBlockImpl<Parameters>::DoAllocLast(DetailedBlockImpl*&& block,
324 return WithLayout::DoAllocLast(std::move(block), layout);
327template <
typename Parameters>
328constexpr BlockResult<DetailedBlockImpl<Parameters>>
329DetailedBlockImpl<Parameters>::DoResize(
size_t new_inner_size,
bool shifted) {
330 return WithLayout::DoResize(new_inner_size, shifted);
333template <
typename Parameters>
334constexpr BlockResult<DetailedBlockImpl<Parameters>>
335DetailedBlockImpl<Parameters>::DoFree(DetailedBlockImpl*&& block) {
336 return WithLayout::DoFree(std::move(block));
341template <
typename Parameters>
342constexpr size_t DetailedBlockImpl<Parameters>::RequestedSize()
const {
343 if constexpr (Hardening::kIncludesDebugChecks) {
344 PW_ASSERT(padding_ <= Basic::InnerSize());
346 return Basic::InnerSize() - padding_;
349template <
typename Parameters>
350constexpr void DetailedBlockImpl<Parameters>::SetRequestedSize(
size_t size) {
351 size_t inner_size = Basic::InnerSize();
352 size_t padding = inner_size;
353 Hardening::Decrement(padding, size);
354 if constexpr (Hardening::kIncludesDebugChecks) {
355 PW_ASSERT(padding <= std::numeric_limits<uint16_t>::max());
357 padding_ =
static_cast<uint16_t
>(padding);
360template <
typename Parameters>
361constexpr void DetailedBlockImpl<Parameters>::SetRequestedAlignment(
363 if constexpr (Hardening::kIncludesDebugChecks) {
364 PW_ASSERT((alignment & (alignment - 1)) == 0);
365 PW_ASSERT(alignment < 0x2000);
367 info_.alignment =
static_cast<uint16_t
>(alignment);
Definition: status_with_size.h:51
Definition: alignable.h:44
Definition: allocatable.h:51
Definition: with_layout.h:50
Definition: contiguous.h:47
Definition: detailed_block.h:88
Definition: iterable.h:50
Definition: iterable.h:69
Definition: iterable.h:35
Definition: poisonable.h:53
Definition: detailed_block.h:49