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
116 static constexpr Result<Derived*> Init(ByteSpan region);
117
125 template <typename Ptr>
126 static constexpr internal::copy_const_ptr_t<Ptr, Derived*> FromUsableSpace(
127 Ptr usable_space);
128
130 constexpr std::byte* UsableSpace();
131 constexpr const std::byte* UsableSpace() const;
132 constexpr std::byte* UsableSpaceUnchecked() {
133 return UsableSpaceUncheckedImpl(this);
134 }
135 constexpr const std::byte* UsableSpaceUnchecked() const {
136 return UsableSpaceUncheckedImpl(this);
137 }
138
140 static constexpr size_t OuterSizeFromInnerSize(size_t inner_size);
141
143 static constexpr size_t InnerSizeFromOuterSize(size_t outer_size);
144
146 constexpr size_t OuterSize() const;
147
149 constexpr size_t InnerSize() const;
150 constexpr size_t InnerSizeUnchecked() const;
151
153 constexpr bool IsValid() const;
154
156 constexpr bool CheckInvariants() const;
157
158 protected:
159 constexpr BasicBlock() = default;
160
165 constexpr bool DoCheckInvariants(bool strict) const;
166
167 private:
168 constexpr const Derived* derived() const {
169 return static_cast<const Derived*>(this);
170 }
171
173 template <typename Ptr>
174 static constexpr internal::copy_const_ptr_t<Ptr, std::byte*>
175 UsableSpaceUncheckedImpl(Ptr block);
176};
177
180template <typename T>
181struct is_block : std::is_base_of<internal::BasicBase, T> {};
182
184template <typename T>
186
188
189namespace internal {
190
193void CheckMisaligned(const void* block, bool is_aligned);
194
195} // namespace internal
196
197// Template method implementations.
198
199template <typename Derived>
201 region = GetAlignedSubspan(region, Derived::kAlignment);
202 if (region.size() <= Derived::kBlockOverhead) {
204 }
205 if (region.size() > Derived::MaxAddressableSize()) {
206 return Status::OutOfRange();
207 }
208 auto* block = Derived::AsBlock(region);
209 if constexpr (Hardening::kIncludesDebugChecks) {
210 block->CheckInvariants();
211 }
212 return block;
213}
214
215template <typename Derived>
216template <typename Ptr>
217constexpr internal::copy_const_ptr_t<Ptr, Derived*>
219 using BlockPtr = internal::copy_const_ptr_t<Ptr, Derived*>;
220 auto addr = cpp20::bit_cast<uintptr_t>(usable_space);
221 Hardening::Decrement(addr, kBlockOverhead);
222 auto* block = std::launder(reinterpret_cast<BlockPtr>(addr));
223 if constexpr (Hardening::kIncludesBasicChecks) {
224 block->CheckInvariants();
225 }
226 return block;
227}
228
229template <typename Derived>
230constexpr std::byte* BasicBlock<Derived>::UsableSpace() {
231 if constexpr (Hardening::kIncludesDebugChecks) {
232 CheckInvariants();
233 }
234 return UsableSpaceUnchecked();
235}
236
237template <typename Derived>
238constexpr const std::byte* BasicBlock<Derived>::UsableSpace() const {
239 if constexpr (Hardening::kIncludesDebugChecks) {
240 CheckInvariants();
241 }
242 return UsableSpaceUnchecked();
243}
244
245template <typename Derived>
246template <typename Ptr>
247constexpr internal::copy_const_ptr_t<Ptr, std::byte*>
248BasicBlock<Derived>::UsableSpaceUncheckedImpl(Ptr block) {
249 using BytePtr = internal::copy_const_ptr_t<Derived, std::byte*>;
250 auto addr = cpp20::bit_cast<uintptr_t>(block);
251 Hardening::Increment(addr, kBlockOverhead);
252 return cpp20::bit_cast<BytePtr>(addr);
253}
254
255template <typename Derived>
257 size_t inner_size) {
258 size_t outer_size = inner_size;
259 Hardening::Increment(outer_size, kBlockOverhead);
260 return outer_size;
261}
262
263template <typename Derived>
265 size_t outer_size) {
266 size_t inner_size = outer_size;
267 Hardening::Decrement(inner_size, kBlockOverhead);
268 return inner_size;
269}
270
271template <typename Derived>
272constexpr size_t BasicBlock<Derived>::OuterSize() const {
273 if constexpr (Hardening::kIncludesDebugChecks) {
274 CheckInvariants();
275 }
276 return derived()->OuterSizeUnchecked();
277}
278
279template <typename Derived>
280constexpr size_t BasicBlock<Derived>::InnerSize() const {
281 if constexpr (Hardening::kIncludesDebugChecks) {
282 CheckInvariants();
283 }
284 return InnerSizeUnchecked();
285}
286
287template <typename Derived>
288constexpr size_t BasicBlock<Derived>::InnerSizeUnchecked() const {
289 return InnerSizeFromOuterSize(derived()->OuterSizeUnchecked());
290}
291
292template <typename Derived>
293constexpr bool BasicBlock<Derived>::IsValid() const {
294 return derived()->DoCheckInvariants(/*strict=*/false);
295}
296
297template <typename Derived>
299 return derived()->DoCheckInvariants(/*strict=*/true);
300}
301
302template <typename Derived>
303constexpr bool BasicBlock<Derived>::DoCheckInvariants(bool strict) const {
304 bool is_aligned = (cpp20::bit_cast<uintptr_t>(this) % kAlignment) == 0;
305 if constexpr (Hardening::kIncludesDebugChecks) {
306 internal::CheckMisaligned(this, is_aligned || !strict);
307 }
308 return is_aligned;
309}
310
311} // namespace pw::allocator
Definition: result.h:143
static constexpr Status OutOfRange()
Definition: status.h:267
static constexpr Status ResourceExhausted()
Definition: status.h:230
Definition: basic.h:95
constexpr bool CheckInvariants() const
Like IsValid, but crashes if invalid.
Definition: basic.h:298
constexpr size_t OuterSize() const
Definition: basic.h:272
static constexpr Result< Derived * > Init(ByteSpan region)
Creates the first block for a given memory region.
Definition: basic.h:200
constexpr size_t InnerSize() const
Definition: basic.h:280
static constexpr size_t OuterSizeFromInnerSize(size_t inner_size)
Definition: basic.h:256
constexpr bool IsValid() const
Definition: basic.h:293
static constexpr size_t InnerSizeFromOuterSize(size_t outer_size)
Definition: basic.h:264
constexpr bool DoCheckInvariants(bool strict) const
Definition: basic.h:303
constexpr std::byte * UsableSpace()
Definition: basic.h:230
static constexpr internal::copy_const_ptr_t< Ptr, Derived * > FromUsableSpace(Ptr usable_space)
Definition: basic.h:218
constexpr bool is_block_v
Helper variable template for is_block<T>::value.
Definition: basic.h:185
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:54
Helper type that copies const-qualifers between types.
Definition: basic.h:32
Definition: basic.h:181