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) {
285 return BlockResult(block, Status::InvalidArgument());
287 if constexpr (Hardening::kIncludesRobustChecks) {
288 block->CheckInvariants();
290 if (!block->IsFree()) {
291 return BlockResult(block, Status::FailedPrecondition());
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);
310 result =
BlockResult(block, BlockResultNext::kSplitNew);
312 block->SetFree(
false);
316template <
typename Derived>
318 Derived*&& block,
Layout layout) {
319 if (block ==
nullptr || layout.size() == 0) {
320 return BlockResult(block, Status::InvalidArgument());
322 if constexpr (Hardening::kIncludesRobustChecks) {
323 block->CheckInvariants();
325 if (!block->IsFree()) {
326 return BlockResult(block, Status::FailedPrecondition());
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();
347 result =
BlockResult(block, BlockResultPrev::kSplitNew);
349 }
else if (extra != 0 && prev !=
nullptr) {
351 prev->DoResize(prev->InnerSize() + extra,
true).IgnoreUnlessStrict();
352 block = prev->Next();
353 result =
BlockResult(block, BlockResultPrev::kResizedLarger, extra);
355 block->SetFree(
false);
359template <
typename Derived>
361 size_t new_inner_size) {
362 if constexpr (Hardening::kIncludesRobustChecks) {
363 derived()->CheckInvariants();
365 if (derived()->IsFree()) {
366 return BlockResult(derived(), Status::FailedPrecondition());
368 return derived()->DoResize(new_inner_size,
false);
371template <
typename Derived>
373 size_t new_inner_size,
bool) {
374 size_t old_inner_size = derived()->InnerSize();
375 new_inner_size =
AlignUp(new_inner_size, Derived::kAlignment);
376 if (old_inner_size == new_inner_size) {
382 derived()->SetFree(
true);
383 Derived* next = derived()->Next();
385 if (next !=
nullptr && next->IsFree()) {
386 derived()->DoMergeNext();
387 result =
BlockResult(derived(), BlockResultNext::kMerged);
389 size_t merged_inner_size = derived()->InnerSize();
390 if (merged_inner_size < new_inner_size) {
393 if (merged_inner_size != old_inner_size) {
394 derived()->DoSplitFirst(old_inner_size);
396 derived()->SetFree(
false);
397 return BlockResult(derived(), Status::ResourceExhausted());
399 if (new_inner_size + Derived::kMinOuterSize <= merged_inner_size) {
401 derived()->DoSplitFirst(new_inner_size);
402 result = result.next() == BlockResultNext::kMerged
403 ?
BlockResult(derived(), BlockResultNext::kResized)
404 :
BlockResult(derived(), BlockResultNext::kSplitNew);
406 derived()->SetFree(
false);
410template <
typename Derived>
413 if (block ==
nullptr) {
414 return BlockResult(block, Status::InvalidArgument());
416 if constexpr (Hardening::kIncludesRobustChecks) {
417 block->CheckInvariants();
419 return Derived::DoFree(std::move(block));
422template <
typename Derived>
425 block->SetFree(
true);
429 Derived* prev = block->Prev();
430 if (prev !=
nullptr && prev->IsFree()) {
433 result =
BlockResult(block, BlockResultNext::kMerged);
437 Derived* next = block->Next();
438 if (next !=
nullptr && next->IsFree()) {
439 block->DoMergeNext();
440 result =
BlockResult(block, BlockResultNext::kMerged);
443 if constexpr (Hardening::kIncludesDebugChecks) {
444 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:360
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:423
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:372
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:411
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