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>
54 static_assert(is_contiguous_v<Derived>,
55 "Types derived from AllocatableBlock must also derive from "
179 bool shifted =
false);
188 constexpr Derived* derived() {
return static_cast<Derived*
>(
this); }
189 constexpr const Derived* derived()
const {
190 return static_cast<const Derived*
>(
this);
195 friend class AlignableBlock;
199 friend class BlockWithLayout;
204template <
typename BlockType>
209template <
typename BlockType>
216template <
typename Derived>
218 if constexpr (Hardening::kIncludesDebugChecks) {
219 derived()->CheckInvariants();
221 return derived()->IsFreeUnchecked();
224template <
typename Derived>
227 if constexpr (Hardening::kIncludesDebugChecks) {
228 derived()->CheckInvariants();
230 return derived()->DoCanAlloc(layout);
233template <
typename Derived>
236 if (!derived()->IsFree()) {
237 return StatusWithSize::FailedPrecondition();
239 if (layout.size() == 0) {
240 return StatusWithSize::InvalidArgument();
242 size_t extra = derived()->InnerSize();
243 size_t new_inner_size =
AlignUp(layout.size(), Derived::kAlignment);
244 if (!
CheckedSub(extra, new_inner_size, extra)) {
245 return StatusWithSize::ResourceExhausted();
250template <
typename Derived>
252 Derived*&& block,
Layout layout) {
253 if (block ==
nullptr || layout.size() == 0) {
256 if constexpr (Hardening::kIncludesRobustChecks) {
257 block->CheckInvariants();
259 if (!block->IsFree()) {
262 return Derived::DoAllocFirst(std::move(block), layout);
265template <
typename Derived>
267 Derived*&& block,
Layout layout) {
268 size_t size =
AlignUp(layout.size(), Derived::kAlignment);
269 layout =
Layout(size, layout.alignment());
271 if (!can_alloc.
ok()) {
274 size_t extra = can_alloc.
size();
276 if (extra >= Derived::kMinOuterSize) {
278 block->DoSplitFirst(block->InnerSize() - extra);
281 block->SetFree(
false);
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::DoAllocLast(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 Derived* prev = block->Prev();
312 if (extra >= Derived::kMinOuterSize) {
314 block = block->DoSplitLast(layout.size());
315 prev = block->Prev();
318 }
else if (extra != 0 && prev !=
nullptr) {
320 prev->DoResize(prev->InnerSize() + extra,
true).IgnoreUnlessStrict();
321 block = prev->Next();
325 block->SetFree(
false);
329template <
typename Derived>
331 size_t new_inner_size) {
332 if constexpr (Hardening::kIncludesRobustChecks) {
333 derived()->CheckInvariants();
335 if (derived()->IsFree()) {
338 return derived()->DoResize(new_inner_size,
false);
341template <
typename Derived>
343 size_t new_inner_size,
bool) {
344 size_t old_inner_size = derived()->InnerSize();
345 new_inner_size =
AlignUp(new_inner_size, Derived::kAlignment);
346 if (old_inner_size == new_inner_size) {
352 derived()->SetFree(
true);
353 Derived* next = derived()->Next();
355 if (next !=
nullptr && next->IsFree()) {
356 derived()->DoMergeNext();
359 size_t merged_inner_size = derived()->InnerSize();
360 if (merged_inner_size < new_inner_size) {
363 if (merged_inner_size != old_inner_size) {
364 derived()->DoSplitFirst(old_inner_size);
366 derived()->SetFree(
false);
369 if (new_inner_size + Derived::kMinOuterSize <= merged_inner_size) {
371 derived()->DoSplitFirst(new_inner_size);
372 result = result.next() == BlockResultNext::kMerged
376 derived()->SetFree(
false);
380template <
typename Derived>
383 if (block ==
nullptr) {
386 if constexpr (Hardening::kIncludesRobustChecks) {
387 block->CheckInvariants();
389 return Derived::DoFree(std::move(block));
392template <
typename Derived>
395 block->SetFree(
true);
399 Derived* prev = block->Prev();
400 if (prev !=
nullptr && prev->IsFree()) {
407 Derived* next = block->Next();
408 if (next !=
nullptr && next->IsFree()) {
409 block->DoMergeNext();
413 if constexpr (Hardening::kIncludesDebugChecks) {
414 block->CheckInvariants();
static constexpr Status InvalidArgument()
Definition: status.h:164
static constexpr Status FailedPrecondition()
Definition: status.h:243
static constexpr Status ResourceExhausted()
Definition: status.h:230
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:330
constexpr bool IsFree() const
Definition: allocatable.h:217
static constexpr BlockResult< Derived > DoFree(Derived *&&block)
Definition: allocatable.h:393
constexpr StatusWithSize CanAlloc(Layout layout) const
Definition: allocatable.h:225
static constexpr BlockResult< Derived > AllocFirst(Derived *&&block, Layout layout)
Definition: allocatable.h:251
constexpr BlockResult< Derived > DoResize(size_t new_inner_size, bool shifted=false)
Definition: allocatable.h:342
static constexpr BlockResult< Derived > DoAllocLast(Derived *&&block, Layout layout)
Definition: allocatable.h:301
static constexpr BlockResult< Derived > AllocLast(Derived *&&block, Layout layout)
Definition: allocatable.h:286
static constexpr BlockResult< Derived > Free(Derived *&&block)
Definition: allocatable.h:381
static constexpr BlockResult< Derived > DoAllocFirst(Derived *&&block, Layout layout)
Definition: allocatable.h:266
constexpr StatusWithSize DoCanAlloc(Layout layout) const
Definition: allocatable.h:234
Next
Definition: result.h:45
Prev
Definition: result.h:36
constexpr bool is_allocatable_v
Helper variable template for is_allocatable<BlockType>::value.
Definition: allocatable.h:210
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:205