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 {
50template <
typename Derived>
56 static_assert(is_contiguous_v<Derived>,
57 "Types derived from AllocatableBlock must also derive from "
214 bool shifted =
false);
220 using BlockResultPrev = internal::GenericBlockResult::Prev;
221 using BlockResultNext = internal::GenericBlockResult::Next;
223 constexpr Derived* derived() {
return static_cast<Derived*
>(
this); }
224 constexpr const Derived* derived()
const {
225 return static_cast<const Derived*
>(
this);
230 friend class AlignableBlock;
234 friend class BlockWithLayout;
239template <
typename BlockType>
244template <
typename BlockType>
251template <
typename Derived>
253 if constexpr (Hardening::kIncludesDebugChecks) {
254 derived()->CheckInvariants();
256 return derived()->IsFreeUnchecked();
259template <
typename Derived>
262 if constexpr (Hardening::kIncludesDebugChecks) {
263 derived()->CheckInvariants();
265 return derived()->DoCanAlloc(layout);
268template <
typename Derived>
271 if (!derived()->IsFree()) {
272 return StatusWithSize::FailedPrecondition();
274 if (layout.size() == 0) {
275 return StatusWithSize::InvalidArgument();
277 size_t extra = derived()->InnerSize();
278 size_t new_inner_size =
AlignUp(layout.size(), Derived::kAlignment);
279 if (!
CheckedSub(extra, new_inner_size, extra)) {
280 return StatusWithSize::ResourceExhausted();
285template <
typename Derived>
287 Derived*&& block,
Layout layout) {
288 if (block ==
nullptr || layout.size() == 0) {
291 if constexpr (Hardening::kIncludesRobustChecks) {
292 block->CheckInvariants();
294 if (!block->IsFree()) {
297 return Derived::DoAllocFirst(std::move(block), layout);
300template <
typename Derived>
302 Derived*&& block,
Layout layout) {
303 size_t size =
AlignUp(layout.size(), Derived::kAlignment);
304 layout =
Layout(size, layout.alignment());
306 if (!can_alloc.
ok()) {
309 size_t extra = can_alloc.
size();
311 if (extra >= Derived::kMinOuterSize) {
313 block->DoSplitFirst(block->InnerSize() - extra);
316 block->SetFree(
false);
320template <
typename Derived>
322 Derived*&& block,
Layout layout) {
323 if (block ==
nullptr || layout.size() == 0) {
326 if constexpr (Hardening::kIncludesRobustChecks) {
327 block->CheckInvariants();
329 if (!block->IsFree()) {
332 return Derived::DoAllocLast(std::move(block), layout);
335template <
typename Derived>
337 Derived*&& block,
Layout layout) {
338 size_t size =
AlignUp(layout.size(), Derived::kAlignment);
339 layout =
Layout(size, layout.alignment());
341 if (!can_alloc.
ok()) {
344 size_t extra = can_alloc.
size();
346 Derived* prev = block->Prev();
347 if (extra >= Derived::kMinOuterSize) {
349 block = block->DoSplitLast(layout.size());
350 prev = block->Prev();
353 }
else if (extra != 0 && prev !=
nullptr) {
355 prev->DoResize(prev->InnerSize() + extra,
true).IgnoreUnlessStrict();
356 block = prev->Next();
360 block->SetFree(
false);
364template <
typename Derived>
366 size_t new_inner_size) {
367 if constexpr (Hardening::kIncludesRobustChecks) {
368 derived()->CheckInvariants();
370 if (derived()->IsFree()) {
373 return derived()->DoResize(new_inner_size,
false);
376template <
typename Derived>
378 size_t new_inner_size,
bool) {
379 size_t old_inner_size = derived()->InnerSize();
380 new_inner_size =
AlignUp(new_inner_size, Derived::kAlignment);
381 if (old_inner_size == new_inner_size) {
387 derived()->SetFree(
true);
388 Derived* next = derived()->Next();
390 if (next !=
nullptr && next->IsFree()) {
391 derived()->DoMergeNext();
394 size_t merged_inner_size = derived()->InnerSize();
395 if (merged_inner_size < new_inner_size) {
398 if (merged_inner_size != old_inner_size) {
399 derived()->DoSplitFirst(old_inner_size);
401 derived()->SetFree(
false);
404 if (new_inner_size + Derived::kMinOuterSize <= merged_inner_size) {
406 derived()->DoSplitFirst(new_inner_size);
407 result = result.next() == BlockResultNext::kMerged
411 derived()->SetFree(
false);
415template <
typename Derived>
418 if (block ==
nullptr) {
421 if constexpr (Hardening::kIncludesRobustChecks) {
422 block->CheckInvariants();
424 return Derived::DoFree(std::move(block));
427template <
typename Derived>
430 block->SetFree(
true);
434 Derived* prev = block->Prev();
435 if (prev !=
nullptr && prev->IsFree()) {
442 Derived* next = block->Next();
443 if (next !=
nullptr && next->IsFree()) {
444 block->DoMergeNext();
448 if constexpr (Hardening::kIncludesDebugChecks) {
449 block->CheckInvariants();
static constexpr Status InvalidArgument()
Argument was malformed; e.g. invalid characters when parsing integer.
Definition: status.h:131
static constexpr Status FailedPrecondition()
System isn’t in the required state; e.g. deleting a non-empty directory.
Definition: status.h:162
static constexpr Status ResourceExhausted()
Definition: status.h:157
Definition: status_with_size.h:51
constexpr bool ok() const
True if status() == OkStatus().
Definition: status_with_size.h:154
constexpr size_t size() const
Definition: status_with_size.h:148
Definition: allocatable.h:51
constexpr BlockResult< Derived > Resize(size_t new_inner_size)
Definition: allocatable.h:365
constexpr bool IsFree() const
Definition: allocatable.h:252
constexpr bool Used() const
Definition: allocatable.h:68
static constexpr BlockResult< Derived > DoFree(Derived *&&block)
Definition: allocatable.h:428
constexpr StatusWithSize CanAlloc(Layout layout) const
Definition: allocatable.h:260
static constexpr BlockResult< Derived > AllocFirst(Derived *&&block, Layout layout)
Definition: allocatable.h:286
constexpr BlockResult< Derived > DoResize(size_t new_inner_size, bool shifted=false)
Definition: allocatable.h:377
static constexpr BlockResult< Derived > DoAllocLast(Derived *&&block, Layout layout)
Definition: allocatable.h:336
static constexpr BlockResult< Derived > AllocLast(Derived *&&block, Layout layout)
Definition: allocatable.h:321
static constexpr BlockResult< Derived > Free(Derived *&&block)
Definition: allocatable.h:416
static constexpr BlockResult< Derived > DoAllocFirst(Derived *&&block, Layout layout)
Definition: allocatable.h:301
constexpr StatusWithSize DoCanAlloc(Layout layout) const
Definition: allocatable.h:269
constexpr bool is_allocatable_v
Helper variable template for is_allocatable<BlockType>::value.
Definition: allocatable.h:245
constexpr size_t AlignUp(uintptr_t value, size_t alignment)
Returns the value rounded up to the nearest multiple of alignment.
Definition: alignment.h:54
constexpr bool CheckedSub(A a, B b, T &result)
Definition: checked_arithmetic.h:138
Definition: allocatable.h:30
Definition: allocatable.h:240