18#include "pw_allocator/block/contiguous.h"
19#include "pw_allocator/block/result.h"
20#include "pw_allocator/hardening.h"
21#include "pw_allocator/layout.h"
22#include "pw_bytes/alignment.h"
23#include "pw_status/status.h"
24#include "pw_status/status_with_size.h"
26namespace pw::allocator {
48template <
typename Derived>
54 static_assert(is_contiguous_v<Derived>,
55 "Types derived from AllocatableBlock must also derive from "
212 bool shifted =
false);
218 using BlockResultPrev = internal::GenericBlockResult::Prev;
219 using BlockResultNext = internal::GenericBlockResult::Next;
221 constexpr Derived* derived() {
return static_cast<Derived*
>(
this); }
222 constexpr const Derived* derived()
const {
223 return static_cast<const Derived*
>(
this);
228 friend class AlignableBlock;
232 friend class BlockWithLayout;
237template <
typename BlockType>
242template <
typename BlockType>
247template <
typename Derived>
249 if constexpr (Hardening::kIncludesDebugChecks) {
250 derived()->CheckInvariants();
252 return derived()->IsFreeUnchecked();
255template <
typename Derived>
258 if constexpr (Hardening::kIncludesDebugChecks) {
259 derived()->CheckInvariants();
261 return derived()->DoCanAlloc(layout);
264template <
typename Derived>
267 if (!derived()->IsFree()) {
268 return StatusWithSize::FailedPrecondition();
270 if (layout.size() == 0) {
271 return StatusWithSize::InvalidArgument();
273 size_t extra = derived()->InnerSize();
274 size_t new_inner_size =
AlignUp(layout.size(), Derived::kAlignment);
276 return StatusWithSize::ResourceExhausted();
281template <
typename Derived>
283 Derived*&& block,
Layout layout) {
284 if (block ==
nullptr || layout.size() == 0) {
287 if constexpr (Hardening::kIncludesRobustChecks) {
288 block->CheckInvariants();
290 if (!block->IsFree()) {
293 return Derived::DoAllocFirst(std::move(block), layout);
296template <
typename Derived>
298 Derived*&& block,
Layout layout) {
299 size_t size =
AlignUp(layout.size(), Derived::kAlignment);
300 layout =
Layout(size, layout.alignment());
302 if (!can_alloc.
ok()) {
305 size_t extra = can_alloc.
size();
307 if (extra >= Derived::kMinOuterSize) {
309 block->DoSplitFirst(block->InnerSize() - extra);
312 block->SetFree(
false);
316template <
typename Derived>
318 Derived*&& block,
Layout layout) {
319 if (block ==
nullptr || layout.size() == 0) {
322 if constexpr (Hardening::kIncludesRobustChecks) {
323 block->CheckInvariants();
325 if (!block->IsFree()) {
328 return Derived::DoAllocLast(std::move(block), layout);
331template <
typename Derived>
333 Derived*&& block,
Layout layout) {
334 size_t size =
AlignUp(layout.size(), Derived::kAlignment);
335 layout =
Layout(size, layout.alignment());
337 if (!can_alloc.
ok()) {
340 size_t extra = can_alloc.
size();
342 Derived* prev = block->Prev();
343 if (extra >= Derived::kMinOuterSize) {
345 block = block->DoSplitLast(layout.size());
346 prev = block->Prev();
349 }
else if (extra != 0 && prev !=
nullptr) {
351 prev->DoResize(prev->InnerSize() + extra,
true).IgnoreUnlessStrict();
352 block = prev->Next();
356 block->SetFree(
false);
360template <
typename Derived>
362 size_t new_inner_size) {
363 if constexpr (Hardening::kIncludesRobustChecks) {
364 derived()->CheckInvariants();
366 if (derived()->IsFree()) {
369 return derived()->DoResize(new_inner_size,
false);
372template <
typename Derived>
374 size_t new_inner_size,
bool) {
375 size_t old_inner_size = derived()->InnerSize();
376 new_inner_size =
AlignUp(new_inner_size, Derived::kAlignment);
377 if (old_inner_size == new_inner_size) {
383 derived()->SetFree(
true);
384 Derived* next = derived()->Next();
386 if (next !=
nullptr && next->IsFree()) {
387 derived()->DoMergeNext();
390 size_t merged_inner_size = derived()->InnerSize();
391 if (merged_inner_size < new_inner_size) {
394 if (merged_inner_size != old_inner_size) {
395 derived()->DoSplitFirst(old_inner_size);
397 derived()->SetFree(
false);
400 if (new_inner_size + Derived::kMinOuterSize <= merged_inner_size) {
402 derived()->DoSplitFirst(new_inner_size);
403 result = result.next() == BlockResultNext::kMerged
407 derived()->SetFree(
false);
411template <
typename Derived>
414 if (block ==
nullptr) {
417 if constexpr (Hardening::kIncludesRobustChecks) {
418 block->CheckInvariants();
420 return Derived::DoFree(std::move(block));
423template <
typename Derived>
426 block->SetFree(
true);
430 Derived* prev = block->Prev();
431 if (prev !=
nullptr && prev->IsFree()) {
438 Derived* next = block->Next();
439 if (next !=
nullptr && next->IsFree()) {
440 block->DoMergeNext();
444 if constexpr (Hardening::kIncludesDebugChecks) {
445 block->CheckInvariants();
Definition: status_with_size.h:49
constexpr bool ok() const
True if status() == OkStatus().
Definition: status_with_size.h:152
constexpr size_t size() const
Definition: status_with_size.h:146
Definition: allocatable.h:49
constexpr BlockResult< Derived > Resize(size_t new_inner_size)
Definition: allocatable.h:361
constexpr bool IsFree() const
Definition: allocatable.h:248
constexpr bool Used() const
Definition: allocatable.h:66
static constexpr BlockResult< Derived > DoFree(Derived *&&block)
Definition: allocatable.h:424
constexpr StatusWithSize CanAlloc(Layout layout) const
Definition: allocatable.h:256
static constexpr BlockResult< Derived > AllocFirst(Derived *&&block, Layout layout)
Definition: allocatable.h:282
constexpr BlockResult< Derived > DoResize(size_t new_inner_size, bool shifted=false)
Definition: allocatable.h:373
static constexpr BlockResult< Derived > DoAllocLast(Derived *&&block, Layout layout)
Definition: allocatable.h:332
static constexpr BlockResult< Derived > AllocLast(Derived *&&block, Layout layout)
Definition: allocatable.h:317
static constexpr BlockResult< Derived > Free(Derived *&&block)
Definition: allocatable.h:412
static constexpr BlockResult< Derived > DoAllocFirst(Derived *&&block, Layout layout)
Definition: allocatable.h:297
constexpr StatusWithSize DoCanAlloc(Layout layout) const
Definition: allocatable.h:265
#define PW_SUB_OVERFLOW(a, b, out)
Definition: compiler.h:294
constexpr size_t AlignUp(uintptr_t value, size_t alignment)
Returns the value rounded up to the nearest multiple of alignment.
Definition: alignment.h:52
Definition: allocatable.h:30
Definition: allocatable.h:238