Pigweed
 
Loading...
Searching...
No Matches
with_layout.h
1// Copyright 2024 The Pigweed Authors
2//
3// Licensed under the Apache License, Version 2.0 (the "License"); you may not
4// use this file except in compliance with the License. You may obtain a copy of
5// the License at
6//
7// https://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
11// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
12// License for the specific language governing permissions and limitations under
13// the License.
14#pragma once
15
16#include <cstddef>
17
18#include "pw_allocator/block/alignable.h"
19#include "pw_allocator/block/result.h"
20#include "pw_allocator/layout.h"
21#include "pw_assert/assert.h"
22
23namespace pw::allocator {
24namespace internal {
25
26// Trivial base class for trait support.
28
29} // namespace internal
30
47template <typename Derived>
49 protected:
50 constexpr explicit BlockWithLayout() {
51 // Assert within a function, since `Derived` is not complete when this type
52 // is defined.
53 static_assert(is_alignable_v<Derived>,
54 "Types derived from BlockWithLayout must also derive from "
55 "AlignableBlock");
56 }
57
58 public:
63 constexpr Layout RequestedLayout() const;
64
65 protected:
67 static constexpr BlockResult<Derived> DoAllocFirst(Derived*&& block,
68 Layout layout);
69
71 static constexpr BlockResult<Derived> DoAllocLast(Derived*&& block,
72 Layout layout);
73
75 constexpr BlockResult<Derived> DoResize(size_t new_inner_size,
76 bool shifted = false);
77
79 static constexpr BlockResult<Derived> DoFree(Derived*&& block);
80
81 private:
82 using BlockResultPrev = internal::GenericBlockResult::Prev;
83
84 constexpr Derived* derived() { return static_cast<Derived*>(this); }
85 constexpr const Derived* derived() const {
86 return static_cast<const Derived*>(this);
87 }
88};
89
92template <typename BlockType>
93struct has_layout : std::is_base_of<internal::BaseWithLayout, BlockType> {};
94
96template <typename BlockType>
97constexpr bool has_layout_v = has_layout<BlockType>::value;
98
99// Template method implementations.
100
101template <typename Derived>
103 if constexpr (Hardening::kIncludesDebugChecks) {
104 derived()->CheckInvariants();
105 }
106 if constexpr (Hardening::kIncludesRobustChecks) {
107 PW_ASSERT(!derived()->IsFree());
108 }
109 return Layout(derived()->RequestedSize(), derived()->RequestedAlignment());
110}
111
112template <typename Derived>
114 Derived*&& block, Layout layout) {
115 auto result = AlignableBlock<Derived>::DoAllocFirst(std::move(block), layout);
116 if (!result.ok()) {
117 return result;
118 }
119 block = result.block();
120 block->SetRequestedSize(layout.size());
121 block->SetRequestedAlignment(layout.alignment());
122 return result;
123}
124
125template <typename Derived>
127 Derived*&& block, Layout layout) {
128 auto result = AlignableBlock<Derived>::DoAllocLast(std::move(block), layout);
129 if (!result.ok()) {
130 return result;
131 }
132 block = result.block();
133 block->SetRequestedSize(layout.size());
134 block->SetRequestedAlignment(layout.alignment());
135 return result;
136}
137
138template <typename Derived>
140 size_t new_inner_size, bool shifted) {
141 size_t old_size = derived()->RequestedSize();
142 auto result =
143 derived()->AllocatableBlock<Derived>::DoResize(new_inner_size, shifted);
144 if (result.ok() && !shifted) {
145 derived()->SetRequestedSize(new_inner_size);
146 } else {
147 derived()->SetRequestedSize(old_size);
148 }
149 return result;
150}
151
152template <typename Derived>
154 Derived*&& block) {
155 auto result = AllocatableBlock<Derived>::DoFree(std::move(block));
156 if (!result.ok()) {
157 return result;
158 }
159 block = result.block();
160 Derived* prev = block->Prev();
161 if (prev == nullptr) {
162 return result;
163 }
164 size_t prev_size = prev->RequestedSize();
165 if (prev->InnerSize() - prev_size < Derived::kAlignment) {
166 return result;
167 }
168 // Reclaim bytes that were shifted to prev when the block allocated.
169 size_t old_prev_size = prev->OuterSize();
170 prev->DoResize(prev_size, true).IgnoreUnlessStrict();
171 return BlockResult(prev->Next(),
172 BlockResultPrev::kResizedSmaller,
173 old_prev_size - prev->OuterSize());
174}
175
176} // namespace pw::allocator
static constexpr BlockResult< Derived > DoAllocFirst(Derived *&&block, Layout layout)
Definition: alignable.h:125
static constexpr BlockResult< Derived > DoAllocLast(Derived *&&block, Layout layout)
Definition: alignable.h:157
static constexpr BlockResult< Derived > DoFree(Derived *&&block)
Definition: allocatable.h:423
Definition: result.h:114
Definition: with_layout.h:48
constexpr BlockResult< Derived > DoResize(size_t new_inner_size, bool shifted=false)
Definition: with_layout.h:139
constexpr Layout RequestedLayout() const
Definition: with_layout.h:102
static constexpr BlockResult< Derived > DoFree(Derived *&&block)
Definition: with_layout.h:153
static constexpr BlockResult< Derived > DoAllocFirst(Derived *&&block, Layout layout)
Definition: with_layout.h:113
static constexpr BlockResult< Derived > DoAllocLast(Derived *&&block, Layout layout)
Definition: with_layout.h:126
Definition: layout.h:56
Definition: with_layout.h:93
Definition: with_layout.h:27