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 "
186 bool shifted =
false);
192 using BlockResultPrev = internal::GenericBlockResult::Prev;
193 using BlockResultNext = internal::GenericBlockResult::Next;
195 constexpr Derived* derived() {
return static_cast<Derived*
>(
this); }
196 constexpr const Derived* derived()
const {
197 return static_cast<const Derived*
>(
this);
202 friend class AlignableBlock;
206 friend class BlockWithLayout;
211template <
typename BlockType>
216template <
typename BlockType>
223template <
typename Derived>
225 if constexpr (Hardening::kIncludesDebugChecks) {
226 derived()->CheckInvariants();
228 return derived()->IsFreeUnchecked();
231template <
typename Derived>
234 if constexpr (Hardening::kIncludesDebugChecks) {
235 derived()->CheckInvariants();
237 return derived()->DoCanAlloc(layout);
240template <
typename Derived>
243 if (!derived()->IsFree()) {
244 return StatusWithSize::FailedPrecondition();
246 if (layout.size() == 0) {
247 return StatusWithSize::InvalidArgument();
249 size_t extra = derived()->InnerSize();
250 size_t new_inner_size =
AlignUp(layout.size(), Derived::kAlignment);
251 if (!
CheckedSub(extra, new_inner_size, extra)) {
252 return StatusWithSize::ResourceExhausted();
257template <
typename Derived>
259 Derived*&& block,
Layout layout) {
260 if (block ==
nullptr || layout.size() == 0) {
263 if constexpr (Hardening::kIncludesRobustChecks) {
264 block->CheckInvariants();
266 if (!block->IsFree()) {
269 return Derived::DoAllocFirst(std::move(block), layout);
272template <
typename Derived>
274 Derived*&& block,
Layout layout) {
275 size_t size =
AlignUp(layout.size(), Derived::kAlignment);
276 layout =
Layout(size, layout.alignment());
278 if (!can_alloc.
ok()) {
281 size_t extra = can_alloc.
size();
283 if (extra >= Derived::kMinOuterSize) {
285 block->DoSplitFirst(block->InnerSize() - extra);
288 block->SetFree(
false);
292template <
typename Derived>
294 Derived*&& block,
Layout layout) {
295 if (block ==
nullptr || layout.size() == 0) {
298 if constexpr (Hardening::kIncludesRobustChecks) {
299 block->CheckInvariants();
301 if (!block->IsFree()) {
304 return Derived::DoAllocLast(std::move(block), layout);
307template <
typename Derived>
309 Derived*&& block,
Layout layout) {
310 size_t size =
AlignUp(layout.size(), Derived::kAlignment);
311 layout =
Layout(size, layout.alignment());
313 if (!can_alloc.
ok()) {
316 size_t extra = can_alloc.
size();
318 Derived* prev = block->Prev();
319 if (extra >= Derived::kMinOuterSize) {
321 block = block->DoSplitLast(layout.size());
322 prev = block->Prev();
325 }
else if (extra != 0 && prev !=
nullptr) {
327 prev->DoResize(prev->InnerSize() + extra,
true).IgnoreUnlessStrict();
328 block = prev->Next();
332 block->SetFree(
false);
336template <
typename Derived>
338 size_t new_inner_size) {
339 if constexpr (Hardening::kIncludesRobustChecks) {
340 derived()->CheckInvariants();
342 if (derived()->IsFree()) {
345 return derived()->DoResize(new_inner_size,
false);
348template <
typename Derived>
350 size_t new_inner_size,
bool) {
351 size_t old_inner_size = derived()->InnerSize();
352 new_inner_size =
AlignUp(new_inner_size, Derived::kAlignment);
353 if (old_inner_size == new_inner_size) {
359 derived()->SetFree(
true);
360 Derived* next = derived()->Next();
362 if (next !=
nullptr && next->IsFree()) {
363 derived()->DoMergeNext();
366 size_t merged_inner_size = derived()->InnerSize();
367 if (merged_inner_size < new_inner_size) {
370 if (merged_inner_size != old_inner_size) {
371 derived()->DoSplitFirst(old_inner_size);
373 derived()->SetFree(
false);
376 if (new_inner_size + Derived::kMinOuterSize <= merged_inner_size) {
378 derived()->DoSplitFirst(new_inner_size);
379 result = result.next() == BlockResultNext::kMerged
383 derived()->SetFree(
false);
387template <
typename Derived>
390 if (block ==
nullptr) {
393 if constexpr (Hardening::kIncludesRobustChecks) {
394 block->CheckInvariants();
396 return Derived::DoFree(std::move(block));
399template <
typename Derived>
402 block->SetFree(
true);
406 Derived* prev = block->Prev();
407 if (prev !=
nullptr && prev->IsFree()) {
414 Derived* next = block->Next();
415 if (next !=
nullptr && next->IsFree()) {
416 block->DoMergeNext();
420 if constexpr (Hardening::kIncludesDebugChecks) {
421 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:337
constexpr bool IsFree() const
Definition: allocatable.h:224
constexpr bool Used() const
Definition: allocatable.h:68
static constexpr BlockResult< Derived > DoFree(Derived *&&block)
Definition: allocatable.h:400
constexpr StatusWithSize CanAlloc(Layout layout) const
Definition: allocatable.h:232
static constexpr BlockResult< Derived > AllocFirst(Derived *&&block, Layout layout)
Definition: allocatable.h:258
constexpr BlockResult< Derived > DoResize(size_t new_inner_size, bool shifted=false)
Definition: allocatable.h:349
static constexpr BlockResult< Derived > DoAllocLast(Derived *&&block, Layout layout)
Definition: allocatable.h:308
static constexpr BlockResult< Derived > AllocLast(Derived *&&block, Layout layout)
Definition: allocatable.h:293
static constexpr BlockResult< Derived > Free(Derived *&&block)
Definition: allocatable.h:388
static constexpr BlockResult< Derived > DoAllocFirst(Derived *&&block, Layout layout)
Definition: allocatable.h:273
constexpr StatusWithSize DoCanAlloc(Layout layout) const
Definition: allocatable.h:241
constexpr bool is_allocatable_v
Helper variable template for is_allocatable<BlockType>::value.
Definition: allocatable.h:217
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:212