C/C++ API Reference
Loading...
Searching...
No Matches
contiguous.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 "lib/stdcompat/bit.h"
17#include "pw_allocator/block/basic.h"
18#include "pw_allocator/hardening.h"
19#include "pw_bytes/span.h"
20
21namespace pw::allocator {
22namespace internal {
23
24// Trivial base class for trait support.
26
27} // namespace internal
28
30
46template <typename Derived>
48 protected:
49 constexpr explicit ContiguousBlock() {
50 static_assert(
51 is_block_v<Derived>,
52 "Types derived from ContiguousBlock must also derive from BasicBlock");
53 }
54
55 public:
58 constexpr Derived* Prev() const;
59
62 constexpr Derived* Next() const;
63
64 protected:
74 constexpr Derived* DoSplitFirst(size_t new_inner_size);
75
85 constexpr Derived* DoSplitLast(size_t new_inner_size);
86
93 constexpr void DoMergeNext();
94
96 constexpr bool DoCheckInvariants(bool strict) const;
97
98 private:
99 constexpr Derived* derived() { return static_cast<Derived*>(this); }
100 constexpr const Derived* derived() const {
101 return static_cast<const Derived*>(this);
102 }
103
105 constexpr Derived* PrevUnchecked() const;
106
108 constexpr Derived* NextUnchecked() const;
109
119 static constexpr Derived* Split(Derived*& block, size_t new_inner_size);
120
121 // PoisonableBlock calls DoSplitFirst, DoSplitLast, and DoMergeNext
122 template <typename>
123 friend class PoisonableBlock;
124};
125
127template <typename BlockType>
128struct is_contiguous : std::is_base_of<internal::ContiguousBase, BlockType> {};
129
131template <typename BlockType>
133
135
136namespace internal {
137
141
144void CheckNextMisaligned(const void* block,
145 const void* next,
146 bool next_is_aligned);
147
150void CheckNextPrevMismatched(const void* block,
151 const void* next,
152 const void* next_prev,
153 bool next_prev_matches);
154
157void CheckPrevMisaligned(const void* block,
158 const void* prev,
159 bool prev_is_aligned);
160
163void CheckPrevNextMismatched(const void* block,
164 const void* prev,
165 const void* prev_next,
166 bool prev_next_matches);
167
168} // namespace internal
169
170// Template method implementations.
171
172template <typename Derived>
173constexpr Derived* ContiguousBlock<Derived>::Prev() const {
174 if constexpr (Hardening::kIncludesDebugChecks) {
175 derived()->CheckInvariants();
176 }
177 return PrevUnchecked();
178}
179
180template <typename Derived>
181constexpr Derived* ContiguousBlock<Derived>::PrevUnchecked() const {
182 size_t prev_outer_size = derived()->PrevOuterSizeUnchecked();
183 if (prev_outer_size == 0) {
184 return nullptr;
185 }
186 auto addr = cpp20::bit_cast<uintptr_t>(this);
187 Hardening::Decrement(addr, prev_outer_size);
188 return std::launder(reinterpret_cast<Derived*>(addr));
189}
190
191template <typename Derived>
192constexpr Derived* ContiguousBlock<Derived>::Next() const {
193 if constexpr (Hardening::kIncludesDebugChecks) {
194 derived()->CheckInvariants();
195 }
196 return NextUnchecked();
197}
198
199template <typename Derived>
200constexpr Derived* ContiguousBlock<Derived>::NextUnchecked() const {
201 if (derived()->IsLastUnchecked()) {
202 return nullptr;
203 }
204 size_t outer_size = derived()->OuterSizeUnchecked();
205 auto addr = cpp20::bit_cast<uintptr_t>(this);
206 Hardening::Increment(addr, outer_size);
207 return std::launder(reinterpret_cast<Derived*>(addr));
208}
209
210template <typename Derived>
212 size_t new_inner_size) {
213 Derived* next = derived()->Next();
214 size_t new_outer_size = Derived::kBlockOverhead + new_inner_size;
215 ByteSpan bytes(derived()->UsableSpace(), derived()->InnerSize());
216 bytes = bytes.subspan(new_inner_size);
217 auto* trailing = Derived::AsBlock(bytes);
218 derived()->SetNext(new_outer_size, trailing);
219 trailing->SetNext(bytes.size(), next);
220 return trailing;
221}
222
223template <typename Derived>
225 size_t new_inner_size) {
226 size_t new_outer_size = Derived::kBlockOverhead + new_inner_size;
227 return DoSplitFirst(derived()->InnerSize() - new_outer_size);
228}
229
230template <typename Derived>
232 Derived* next = derived()->Next();
233 if (next != nullptr) {
234 size_t outer_size = derived()->OuterSize() + next->OuterSize();
235 derived()->SetNext(outer_size, next->Next());
236 }
237}
238
239template <typename Derived>
240constexpr bool ContiguousBlock<Derived>::DoCheckInvariants(bool strict) const {
241 bool valid = true;
242
243 Derived* next = derived()->NextUnchecked();
244 if (next != nullptr) {
245 valid &= (cpp20::bit_cast<uintptr_t>(next) % Derived::kAlignment) == 0;
246 if constexpr (Hardening::kIncludesDebugChecks) {
247 internal::CheckNextMisaligned(this, next, valid || !strict);
248 }
249
250 Derived* next_prev = next->PrevUnchecked();
251 valid &= this == next_prev;
252 if constexpr (Hardening::kIncludesDebugChecks) {
253 internal::CheckNextPrevMismatched(
254 this, next, next_prev, valid || !strict);
255 }
256 }
257
258 Derived* prev = derived()->PrevUnchecked();
259 if (prev != nullptr) {
260 valid &= (cpp20::bit_cast<uintptr_t>(prev) % Derived::kAlignment) == 0;
261 if constexpr (Hardening::kIncludesDebugChecks) {
262 internal::CheckPrevMisaligned(this, prev, valid || !strict);
263 }
264
265 Derived* prev_next = prev->NextUnchecked();
266 valid &= this == prev_next;
267 if constexpr (Hardening::kIncludesDebugChecks) {
268 internal::CheckPrevNextMismatched(
269 this, prev, prev_next, valid || !strict);
270 }
271 }
272
273 return valid;
274}
275
276} // namespace pw::allocator
Definition: contiguous.h:47
constexpr Derived * Prev() const
Definition: contiguous.h:173
constexpr bool DoCheckInvariants(bool strict) const
Performs the ContiguousBlock invariant checks.
Definition: contiguous.h:240
constexpr Derived * Next() const
Definition: contiguous.h:192
constexpr void DoMergeNext()
Definition: contiguous.h:231
constexpr Derived * DoSplitLast(size_t new_inner_size)
Definition: contiguous.h:224
constexpr Derived * DoSplitFirst(size_t new_inner_size)
Definition: contiguous.h:211
constexpr bool is_contiguous_v
Helper variable template for is_contiguous<BlockType>::value.
Definition: contiguous.h:132
Definition: contiguous.h:25
Trait type that allow interrogating a block as to whether it is contiguous.
Definition: contiguous.h:128