C/C++ API Reference
Loading...
Searching...
No Matches
basic.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#include <cstdint>
18#include <new>
19#include <type_traits>
20
21#include "lib/stdcompat/bit.h"
22#include "pw_allocator/hardening.h"
23#include "pw_bytes/alignment.h"
24#include "pw_result/result.h"
25#include "pw_status/status.h"
26
27namespace pw::allocator {
28namespace internal {
29
31template <typename From, typename To>
32struct CopyConst {
33 using type = std::conditional_t<std::is_const_v<From>,
34 std::add_const_t<To>,
35 std::remove_const_t<To>>;
36};
37
38template <typename From, typename To>
39using copy_const_t = typename CopyConst<From, To>::type;
40
41template <typename From, typename To>
42using copy_const_ptr_t =
43 std::add_pointer_t<typename CopyConst<std::remove_pointer_t<From>,
44 std::remove_pointer_t<To>>::type>;
45
46// Trivial base class for trait support.
47struct BasicBase {};
48
49} // namespace internal
50
52
94template <typename Derived>
96 public:
97 static constexpr size_t kAlignment = Derived::DefaultAlignment();
98 static constexpr size_t kBlockOverhead =
99 AlignUp(Derived::BlockOverhead(), kAlignment);
100 static constexpr size_t kMinOuterSize =
101 kBlockOverhead + AlignUp(Derived::MinInnerSize(), kAlignment);
102
103 ~BasicBlock() = default;
104
105 // No copy or move.
106 BasicBlock(const BasicBlock& other) = delete;
107 BasicBlock& operator=(const BasicBlock& other) = delete;
108
124 static constexpr Result<Derived*> Init(ByteSpan region);
125
133 template <typename Ptr>
134 static constexpr internal::copy_const_ptr_t<Ptr, Derived*> FromUsableSpace(
135 Ptr usable_space);
136
138 constexpr std::byte* UsableSpace();
139 constexpr const std::byte* UsableSpace() const;
140 constexpr std::byte* UsableSpaceUnchecked() {
141 return UsableSpaceUncheckedImpl(this);
142 }
143 constexpr const std::byte* UsableSpaceUnchecked() const {
144 return UsableSpaceUncheckedImpl(this);
145 }
146
148 static constexpr size_t OuterSizeFromInnerSize(size_t inner_size);
149
151 static constexpr size_t InnerSizeFromOuterSize(size_t outer_size);
152
154 constexpr size_t OuterSize() const;
155
157 constexpr size_t InnerSize() const;
158 constexpr size_t InnerSizeUnchecked() const;
159
161 constexpr bool IsValid() const;
162
164 constexpr bool CheckInvariants() const;
165
166 protected:
167 constexpr BasicBlock() = default;
168
173 constexpr bool DoCheckInvariants(bool strict) const;
174
175 private:
176 constexpr const Derived* derived() const {
177 return static_cast<const Derived*>(this);
178 }
179
181 template <typename Ptr>
182 static constexpr internal::copy_const_ptr_t<Ptr, std::byte*>
183 UsableSpaceUncheckedImpl(Ptr block);
184};
185
188template <typename T>
189struct is_block : std::is_base_of<internal::BasicBase, T> {};
190
192template <typename T>
194
196
197namespace internal {
198
201void CheckMisaligned(const void* block, bool is_aligned);
202
203} // namespace internal
204
205// Template method implementations.
206
207template <typename Derived>
209 region = GetAlignedSubspan(region, Derived::kAlignment);
210 if (region.size() <= Derived::kBlockOverhead) {
211 return Status::ResourceExhausted();
212 }
213 if (region.size() > Derived::MaxAddressableSize()) {
214 return Status::OutOfRange();
215 }
216 auto* block = Derived::AsBlock(region);
217 if constexpr (Hardening::kIncludesDebugChecks) {
218 block->CheckInvariants();
219 }
220 return block;
221}
222
223template <typename Derived>
224template <typename Ptr>
225constexpr internal::copy_const_ptr_t<Ptr, Derived*>
227 using BlockPtr = internal::copy_const_ptr_t<Ptr, Derived*>;
228 auto addr = cpp20::bit_cast<uintptr_t>(usable_space);
229 Hardening::Decrement(addr, kBlockOverhead);
230 auto* block = std::launder(reinterpret_cast<BlockPtr>(addr));
231 if constexpr (Hardening::kIncludesBasicChecks) {
232 block->CheckInvariants();
233 }
234 return block;
235}
236
237template <typename Derived>
238constexpr std::byte* BasicBlock<Derived>::UsableSpace() {
239 if constexpr (Hardening::kIncludesDebugChecks) {
240 CheckInvariants();
241 }
242 return UsableSpaceUnchecked();
243}
244
245template <typename Derived>
246constexpr const std::byte* BasicBlock<Derived>::UsableSpace() const {
247 if constexpr (Hardening::kIncludesDebugChecks) {
248 CheckInvariants();
249 }
250 return UsableSpaceUnchecked();
251}
252
253template <typename Derived>
254template <typename Ptr>
255constexpr internal::copy_const_ptr_t<Ptr, std::byte*>
256BasicBlock<Derived>::UsableSpaceUncheckedImpl(Ptr block) {
257 using BytePtr = internal::copy_const_ptr_t<Derived, std::byte*>;
258 auto addr = cpp20::bit_cast<uintptr_t>(block);
259 Hardening::Increment(addr, kBlockOverhead);
260 return cpp20::bit_cast<BytePtr>(addr);
261}
262
263template <typename Derived>
265 size_t inner_size) {
266 size_t outer_size = inner_size;
267 Hardening::Increment(outer_size, kBlockOverhead);
268 return outer_size;
269}
270
271template <typename Derived>
273 size_t outer_size) {
274 size_t inner_size = outer_size;
275 Hardening::Decrement(inner_size, kBlockOverhead);
276 return inner_size;
277}
278
279template <typename Derived>
280constexpr size_t BasicBlock<Derived>::OuterSize() const {
281 if constexpr (Hardening::kIncludesDebugChecks) {
282 CheckInvariants();
283 }
284 return derived()->OuterSizeUnchecked();
285}
286
287template <typename Derived>
288constexpr size_t BasicBlock<Derived>::InnerSize() const {
289 if constexpr (Hardening::kIncludesDebugChecks) {
290 CheckInvariants();
291 }
292 return InnerSizeUnchecked();
293}
294
295template <typename Derived>
296constexpr size_t BasicBlock<Derived>::InnerSizeUnchecked() const {
297 return InnerSizeFromOuterSize(derived()->OuterSizeUnchecked());
298}
299
300template <typename Derived>
301constexpr bool BasicBlock<Derived>::IsValid() const {
302 return derived()->DoCheckInvariants(/*strict=*/false);
303}
304
305template <typename Derived>
307 return derived()->DoCheckInvariants(/*strict=*/true);
308}
309
310template <typename Derived>
311constexpr bool BasicBlock<Derived>::DoCheckInvariants(bool strict) const {
312 bool is_aligned = (cpp20::bit_cast<uintptr_t>(this) % kAlignment) == 0;
313 if constexpr (Hardening::kIncludesDebugChecks) {
314 internal::CheckMisaligned(this, is_aligned || !strict);
315 }
316 return is_aligned;
317}
318
319} // namespace pw::allocator
Definition: poll.h:25
Definition: basic.h:95
constexpr bool CheckInvariants() const
Like IsValid, but crashes if invalid.
Definition: basic.h:306
constexpr size_t OuterSize() const
Definition: basic.h:280
static constexpr Result< Derived * > Init(ByteSpan region)
Creates the first block for a given memory region.
Definition: basic.h:208
constexpr size_t InnerSize() const
Definition: basic.h:288
static constexpr size_t OuterSizeFromInnerSize(size_t inner_size)
Definition: basic.h:264
constexpr bool IsValid() const
Definition: basic.h:301
static constexpr size_t InnerSizeFromOuterSize(size_t outer_size)
Definition: basic.h:272
constexpr bool DoCheckInvariants(bool strict) const
Definition: basic.h:311
constexpr std::byte * UsableSpace()
Definition: basic.h:238
static constexpr internal::copy_const_ptr_t< Ptr, Derived * > FromUsableSpace(Ptr usable_space)
Definition: basic.h:226
constexpr bool is_block_v
Helper variable template for is_block<T>::value.
Definition: basic.h:193
ByteSpan GetAlignedSubspan(ByteSpan bytes, size_t alignment)
constexpr size_t AlignUp(uintptr_t value, size_t alignment)
Returns the value rounded up to the nearest multiple of alignment.
Definition: alignment.h:52
Helper type that copies const-qualifers between types.
Definition: basic.h:32
Definition: basic.h:189