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 // Assert within a function, since `Derived` is not complete when this type
51 // is defined.
52 static_assert(
53 is_block_v<Derived>,
54 "Types derived from ContiguousBlock must also derive from BasicBlock");
55 }
56
57 public:
60 constexpr Derived* Prev() const;
61
64 constexpr Derived* Next() const;
65
66 protected:
76 constexpr Derived* DoSplitFirst(size_t new_inner_size);
77
87 constexpr Derived* DoSplitLast(size_t new_inner_size);
88
95 constexpr void DoMergeNext();
96
98 constexpr bool DoCheckInvariants(bool strict) const;
99
100 private:
101 constexpr Derived* derived() { return static_cast<Derived*>(this); }
102 constexpr const Derived* derived() const {
103 return static_cast<const Derived*>(this);
104 }
105
107 constexpr Derived* PrevUnchecked() const;
108
110 constexpr Derived* NextUnchecked() const;
111
121 static constexpr Derived* Split(Derived*& block, size_t new_inner_size);
122
123 // PoisonableBlock calls DoSplitFirst, DoSplitLast, and DoMergeNext
124 template <typename>
125 friend class PoisonableBlock;
126};
127
129template <typename BlockType>
130struct is_contiguous : std::is_base_of<internal::ContiguousBase, BlockType> {};
131
133template <typename BlockType>
135
137
138namespace internal {
139
143
146void CheckNextMisaligned(const void* block,
147 const void* next,
148 bool next_is_aligned);
149
152void CheckNextPrevMismatched(const void* block,
153 const void* next,
154 const void* next_prev,
155 bool next_prev_matches);
156
159void CheckPrevMisaligned(const void* block,
160 const void* prev,
161 bool prev_is_aligned);
162
165void CheckPrevNextMismatched(const void* block,
166 const void* prev,
167 const void* prev_next,
168 bool prev_next_matches);
169
170} // namespace internal
171
172// Template method implementations.
173
174template <typename Derived>
175constexpr Derived* ContiguousBlock<Derived>::Prev() const {
176 if constexpr (Hardening::kIncludesDebugChecks) {
177 derived()->CheckInvariants();
178 }
179 return PrevUnchecked();
180}
181
182template <typename Derived>
183constexpr Derived* ContiguousBlock<Derived>::PrevUnchecked() const {
184 size_t prev_outer_size = derived()->PrevOuterSizeUnchecked();
185 if (prev_outer_size == 0) {
186 return nullptr;
187 }
188 auto addr = cpp20::bit_cast<uintptr_t>(this);
189 Hardening::Decrement(addr, prev_outer_size);
190 return std::launder(reinterpret_cast<Derived*>(addr));
191}
192
193template <typename Derived>
194constexpr Derived* ContiguousBlock<Derived>::Next() const {
195 if constexpr (Hardening::kIncludesDebugChecks) {
196 derived()->CheckInvariants();
197 }
198 return NextUnchecked();
199}
200
201template <typename Derived>
202constexpr Derived* ContiguousBlock<Derived>::NextUnchecked() const {
203 if (derived()->IsLastUnchecked()) {
204 return nullptr;
205 }
206 size_t outer_size = derived()->OuterSizeUnchecked();
207 auto addr = cpp20::bit_cast<uintptr_t>(this);
208 Hardening::Increment(addr, outer_size);
209 return std::launder(reinterpret_cast<Derived*>(addr));
210}
211
212template <typename Derived>
214 size_t new_inner_size) {
215 Derived* next = derived()->Next();
216 size_t new_outer_size = Derived::kBlockOverhead + new_inner_size;
217 ByteSpan bytes(derived()->UsableSpace(), derived()->InnerSize());
218 bytes = bytes.subspan(new_inner_size);
219 auto* trailing = Derived::AsBlock(bytes);
220 derived()->SetNext(new_outer_size, trailing);
221 trailing->SetNext(bytes.size(), next);
222 return trailing;
223}
224
225template <typename Derived>
227 size_t new_inner_size) {
228 size_t new_outer_size = Derived::kBlockOverhead + new_inner_size;
229 return DoSplitFirst(derived()->InnerSize() - new_outer_size);
230}
231
232template <typename Derived>
234 Derived* next = derived()->Next();
235 if (next != nullptr) {
236 size_t outer_size = derived()->OuterSize() + next->OuterSize();
237 derived()->SetNext(outer_size, next->Next());
238 }
239}
240
241template <typename Derived>
242constexpr bool ContiguousBlock<Derived>::DoCheckInvariants(bool strict) const {
243 bool valid = true;
244
245 Derived* next = derived()->NextUnchecked();
246 if (next != nullptr) {
247 valid &= (cpp20::bit_cast<uintptr_t>(next) % Derived::kAlignment) == 0;
248 if constexpr (Hardening::kIncludesDebugChecks) {
249 internal::CheckNextMisaligned(this, next, valid || !strict);
250 }
251
252 Derived* next_prev = next->PrevUnchecked();
253 valid &= this == next_prev;
254 if constexpr (Hardening::kIncludesDebugChecks) {
255 internal::CheckNextPrevMismatched(
256 this, next, next_prev, valid || !strict);
257 }
258 }
259
260 Derived* prev = derived()->PrevUnchecked();
261 if (prev != nullptr) {
262 valid &= (cpp20::bit_cast<uintptr_t>(prev) % Derived::kAlignment) == 0;
263 if constexpr (Hardening::kIncludesDebugChecks) {
264 internal::CheckPrevMisaligned(this, prev, valid || !strict);
265 }
266
267 Derived* prev_next = prev->NextUnchecked();
268 valid &= this == prev_next;
269 if constexpr (Hardening::kIncludesDebugChecks) {
270 internal::CheckPrevNextMismatched(
271 this, prev, prev_next, valid || !strict);
272 }
273 }
274
275 return valid;
276}
277
278} // namespace pw::allocator
Definition: contiguous.h:47
constexpr Derived * Prev() const
Definition: contiguous.h:175
constexpr bool DoCheckInvariants(bool strict) const
Performs the ContiguousBlock invariant checks.
Definition: contiguous.h:242
constexpr Derived * Next() const
Definition: contiguous.h:194
constexpr void DoMergeNext()
Definition: contiguous.h:233
constexpr Derived * DoSplitLast(size_t new_inner_size)
Definition: contiguous.h:226
constexpr Derived * DoSplitFirst(size_t new_inner_size)
Definition: contiguous.h:213
constexpr bool is_contiguous_v
Helper variable template for is_contiguous<BlockType>::value.
Definition: contiguous.h:134
Definition: contiguous.h:25
Trait type that allow interrogating a block as to whether it is contiguous.
Definition: contiguous.h:130