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 "
181 bool shifted =
false);
187 using BlockResultPrev = internal::GenericBlockResult::Prev;
188 using BlockResultNext = internal::GenericBlockResult::Next;
190 constexpr Derived* derived() {
return static_cast<Derived*
>(
this); }
191 constexpr const Derived* derived()
const {
192 return static_cast<const Derived*
>(
this);
197 friend class AlignableBlock;
201 friend class BlockWithLayout;
206template <
typename BlockType>
211template <
typename BlockType>
218template <
typename Derived>
220 if constexpr (Hardening::kIncludesDebugChecks) {
221 derived()->CheckInvariants();
223 return derived()->IsFreeUnchecked();
226template <
typename Derived>
229 if constexpr (Hardening::kIncludesDebugChecks) {
230 derived()->CheckInvariants();
232 return derived()->DoCanAlloc(layout);
235template <
typename Derived>
238 if (!derived()->IsFree()) {
239 return StatusWithSize::FailedPrecondition();
241 if (layout.size() == 0) {
242 return StatusWithSize::InvalidArgument();
244 size_t extra = derived()->InnerSize();
245 size_t new_inner_size =
AlignUp(layout.size(), Derived::kAlignment);
246 if (!
CheckedSub(extra, new_inner_size, extra)) {
247 return StatusWithSize::ResourceExhausted();
252template <
typename Derived>
254 Derived*&& block,
Layout layout) {
255 if (block ==
nullptr || layout.size() == 0) {
258 if constexpr (Hardening::kIncludesRobustChecks) {
259 block->CheckInvariants();
261 if (!block->IsFree()) {
264 return Derived::DoAllocFirst(std::move(block), layout);
267template <
typename Derived>
269 Derived*&& block,
Layout layout) {
270 size_t size =
AlignUp(layout.size(), Derived::kAlignment);
271 layout =
Layout(size, layout.alignment());
273 if (!can_alloc.
ok()) {
276 size_t extra = can_alloc.
size();
278 if (extra >= Derived::kMinOuterSize) {
280 block->DoSplitFirst(block->InnerSize() - extra);
283 block->SetFree(
false);
287template <
typename Derived>
289 Derived*&& block,
Layout layout) {
290 if (block ==
nullptr || layout.size() == 0) {
293 if constexpr (Hardening::kIncludesRobustChecks) {
294 block->CheckInvariants();
296 if (!block->IsFree()) {
299 return Derived::DoAllocLast(std::move(block), layout);
302template <
typename Derived>
304 Derived*&& block,
Layout layout) {
305 size_t size =
AlignUp(layout.size(), Derived::kAlignment);
306 layout =
Layout(size, layout.alignment());
308 if (!can_alloc.
ok()) {
311 size_t extra = can_alloc.
size();
313 Derived* prev = block->Prev();
314 if (extra >= Derived::kMinOuterSize) {
316 block = block->DoSplitLast(layout.size());
317 prev = block->Prev();
320 }
else if (extra != 0 && prev !=
nullptr) {
322 prev->DoResize(prev->InnerSize() + extra,
true).IgnoreUnlessStrict();
323 block = prev->Next();
327 block->SetFree(
false);
331template <
typename Derived>
333 size_t new_inner_size) {
334 if constexpr (Hardening::kIncludesRobustChecks) {
335 derived()->CheckInvariants();
337 if (derived()->IsFree()) {
340 return derived()->DoResize(new_inner_size,
false);
343template <
typename Derived>
345 size_t new_inner_size,
bool) {
346 size_t old_inner_size = derived()->InnerSize();
347 new_inner_size =
AlignUp(new_inner_size, Derived::kAlignment);
348 if (old_inner_size == new_inner_size) {
354 derived()->SetFree(
true);
355 Derived* next = derived()->Next();
357 if (next !=
nullptr && next->IsFree()) {
358 derived()->DoMergeNext();
361 size_t merged_inner_size = derived()->InnerSize();
362 if (merged_inner_size < new_inner_size) {
365 if (merged_inner_size != old_inner_size) {
366 derived()->DoSplitFirst(old_inner_size);
368 derived()->SetFree(
false);
371 if (new_inner_size + Derived::kMinOuterSize <= merged_inner_size) {
373 derived()->DoSplitFirst(new_inner_size);
374 result = result.next() == BlockResultNext::kMerged
378 derived()->SetFree(
false);
382template <
typename Derived>
385 if (block ==
nullptr) {
388 if constexpr (Hardening::kIncludesRobustChecks) {
389 block->CheckInvariants();
391 return Derived::DoFree(std::move(block));
394template <
typename Derived>
397 block->SetFree(
true);
401 Derived* prev = block->Prev();
402 if (prev !=
nullptr && prev->IsFree()) {
409 Derived* next = block->Next();
410 if (next !=
nullptr && next->IsFree()) {
411 block->DoMergeNext();
415 if constexpr (Hardening::kIncludesDebugChecks) {
416 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:332
constexpr bool IsFree() const
Definition: allocatable.h:219
static constexpr BlockResult< Derived > DoFree(Derived *&&block)
Definition: allocatable.h:395
constexpr StatusWithSize CanAlloc(Layout layout) const
Definition: allocatable.h:227
static constexpr BlockResult< Derived > AllocFirst(Derived *&&block, Layout layout)
Definition: allocatable.h:253
constexpr BlockResult< Derived > DoResize(size_t new_inner_size, bool shifted=false)
Definition: allocatable.h:344
static constexpr BlockResult< Derived > DoAllocLast(Derived *&&block, Layout layout)
Definition: allocatable.h:303
static constexpr BlockResult< Derived > AllocLast(Derived *&&block, Layout layout)
Definition: allocatable.h:288
static constexpr BlockResult< Derived > Free(Derived *&&block)
Definition: allocatable.h:383
static constexpr BlockResult< Derived > DoAllocFirst(Derived *&&block, Layout layout)
Definition: allocatable.h:268
constexpr StatusWithSize DoCanAlloc(Layout layout) const
Definition: allocatable.h:236
constexpr bool is_allocatable_v
Helper variable template for is_allocatable<BlockType>::value.
Definition: allocatable.h:212
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:207