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"
27namespace pw::allocator {
31template <
typename From,
typename To>
33 using type = std::conditional_t<std::is_const_v<From>,
35 std::remove_const_t<To>>;
38template <
typename From,
typename To>
39using copy_const_t =
typename CopyConst<From, To>::type;
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>;
92template <
typename Derived>
95 static constexpr size_t kAlignment = Derived::DefaultAlignment();
96 static constexpr size_t kBlockOverhead =
97 AlignUp(Derived::BlockOverhead(), kAlignment);
98 static constexpr size_t kMinOuterSize =
99 kBlockOverhead +
AlignUp(Derived::MinInnerSize(), kAlignment);
122 static constexpr Result<Derived*>
Init(ByteSpan region);
131 template <
typename Ptr>
138 constexpr std::byte* UsableSpaceUnchecked() {
139 return UsableSpaceUncheckedImpl(
this);
141 constexpr const std::byte* UsableSpaceUnchecked()
const {
142 return UsableSpaceUncheckedImpl(
this);
156 constexpr size_t InnerSizeUnchecked()
const;
174 constexpr const Derived* derived()
const {
175 return static_cast<const Derived*
>(
this);
179 template <
typename Ptr>
180 static constexpr internal::copy_const_ptr_t<Ptr, std::byte*>
181 UsableSpaceUncheckedImpl(Ptr block);
187struct is_block : std::is_base_of<internal::BasicBase, T> {};
197void CheckMisaligned(
const void* block,
bool is_aligned);
203template <
typename Derived>
206 if (region.size() <= Derived::kBlockOverhead) {
207 return Status::ResourceExhausted();
209 if (region.size() > Derived::MaxAddressableSize()) {
210 return Status::OutOfRange();
212 auto* block = Derived::AsBlock(region);
213 if constexpr (Hardening::kIncludesDebugChecks) {
214 block->CheckInvariants();
219template <
typename Derived>
220template <
typename Ptr>
221constexpr internal::copy_const_ptr_t<Ptr, Derived*>
223 using BlockPtr = internal::copy_const_ptr_t<Ptr, Derived*>;
224 auto addr = cpp20::bit_cast<uintptr_t>(usable_space);
225 Hardening::Decrement(addr, kBlockOverhead);
226 auto* block = std::launder(
reinterpret_cast<BlockPtr
>(addr));
227 if constexpr (Hardening::kIncludesBasicChecks) {
228 block->CheckInvariants();
233template <
typename Derived>
235 if constexpr (Hardening::kIncludesDebugChecks) {
238 return UsableSpaceUnchecked();
241template <
typename Derived>
243 if constexpr (Hardening::kIncludesDebugChecks) {
246 return UsableSpaceUnchecked();
249template <
typename Derived>
250template <
typename Ptr>
251constexpr internal::copy_const_ptr_t<Ptr, std::byte*>
252BasicBlock<Derived>::UsableSpaceUncheckedImpl(Ptr block) {
253 using BytePtr = internal::copy_const_ptr_t<Derived, std::byte*>;
254 auto addr = cpp20::bit_cast<uintptr_t>(block);
255 Hardening::Increment(addr, kBlockOverhead);
256 return cpp20::bit_cast<BytePtr>(addr);
259template <
typename Derived>
262 size_t outer_size = inner_size;
263 Hardening::Increment(outer_size, kBlockOverhead);
267template <
typename Derived>
270 size_t inner_size = outer_size;
271 Hardening::Decrement(inner_size, kBlockOverhead);
275template <
typename Derived>
277 if constexpr (Hardening::kIncludesDebugChecks) {
280 return derived()->OuterSizeUnchecked();
283template <
typename Derived>
285 if constexpr (Hardening::kIncludesDebugChecks) {
288 return InnerSizeUnchecked();
291template <
typename Derived>
293 return InnerSizeFromOuterSize(derived()->OuterSizeUnchecked());
296template <
typename Derived>
298 return derived()->DoCheckInvariants(
false);
301template <
typename Derived>
303 return derived()->DoCheckInvariants(
true);
306template <
typename Derived>
308 bool is_aligned = (cpp20::bit_cast<uintptr_t>(
this) % kAlignment) == 0;
309 if constexpr (Hardening::kIncludesDebugChecks) {
310 internal::CheckMisaligned(
this, is_aligned || !strict);
constexpr bool CheckInvariants() const
Like IsValid, but crashes if invalid.
Definition: basic.h:302
constexpr size_t OuterSize() const
Definition: basic.h:276
static constexpr Result< Derived * > Init(ByteSpan region)
Creates the first block for a given memory region.
Definition: basic.h:204
constexpr size_t InnerSize() const
Definition: basic.h:284
static constexpr size_t OuterSizeFromInnerSize(size_t inner_size)
Definition: basic.h:260
constexpr bool IsValid() const
Definition: basic.h:297
static constexpr size_t InnerSizeFromOuterSize(size_t outer_size)
Definition: basic.h:268
constexpr bool DoCheckInvariants(bool strict) const
Definition: basic.h:307
constexpr std::byte * UsableSpace()
Definition: basic.h:234
static constexpr internal::copy_const_ptr_t< Ptr, Derived * > FromUsableSpace(Ptr usable_space)
Definition: basic.h:222
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