C/C++ API Reference
Loading...
Searching...
No Matches
with_layout.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
18#include "pw_allocator/block/alignable.h"
19#include "pw_allocator/block/result.h"
20#include "pw_allocator/layout.h"
21#include "pw_assert/assert.h"
22
23namespace pw::allocator {
24namespace internal {
25
26// Trivial base class for trait support.
28
29} // namespace internal
30
32
49template <typename Derived>
51 protected:
52 constexpr explicit BlockWithLayout() {
53 // Assert within a function, since `Derived` is not complete when this type
54 // is defined.
55 static_assert(is_alignable_v<Derived>,
56 "Types derived from BlockWithLayout must also derive from "
57 "AlignableBlock");
58 }
59
60 public:
65 constexpr Layout RequestedLayout() const;
66
67 protected:
69 static constexpr BlockResult<Derived> DoAllocFirst(Derived*&& block,
70 Layout layout);
71
73 static constexpr BlockResult<Derived> DoAllocLast(Derived*&& block,
74 Layout layout);
75
77 constexpr BlockResult<Derived> DoResize(size_t new_inner_size,
78 bool shifted = false);
79
81 static constexpr BlockResult<Derived> DoFree(Derived*&& block);
82
83 private:
84 using BlockResultPrev = internal::GenericBlockResult::Prev;
85
86 constexpr Derived* derived() { return static_cast<Derived*>(this); }
87 constexpr const Derived* derived() const {
88 return static_cast<const Derived*>(this);
89 }
90};
91
94template <typename BlockType>
95struct has_layout : std::is_base_of<internal::BaseWithLayout, BlockType> {};
96
98template <typename BlockType>
100
102
103// Template method implementations.
104
105template <typename Derived>
107 if constexpr (Hardening::kIncludesDebugChecks) {
108 derived()->CheckInvariants();
109 }
110 if constexpr (Hardening::kIncludesRobustChecks) {
111 PW_ASSERT(!derived()->IsFree());
112 }
113 return Layout(derived()->RequestedSize(), derived()->RequestedAlignment());
114}
115
116template <typename Derived>
118 Derived*&& block, Layout layout) {
119 auto result = AlignableBlock<Derived>::DoAllocFirst(std::move(block), layout);
120 if (!result.ok()) {
121 return result;
122 }
123 block = result.block();
124 block->SetRequestedSize(layout.size());
125 block->SetRequestedAlignment(layout.alignment());
126 return result;
127}
128
129template <typename Derived>
131 Derived*&& block, Layout layout) {
132 auto result = AlignableBlock<Derived>::DoAllocLast(std::move(block), layout);
133 if (!result.ok()) {
134 return result;
135 }
136 block = result.block();
137 block->SetRequestedSize(layout.size());
138 block->SetRequestedAlignment(layout.alignment());
139 return result;
140}
141
142template <typename Derived>
144 size_t new_inner_size, bool shifted) {
145 size_t old_size = derived()->RequestedSize();
146 auto result =
147 derived()->AllocatableBlock<Derived>::DoResize(new_inner_size, shifted);
148 if (result.ok() && !shifted) {
149 derived()->SetRequestedSize(new_inner_size);
150 } else {
151 derived()->SetRequestedSize(old_size);
152 }
153 return result;
154}
155
156template <typename Derived>
158 Derived*&& block) {
159 auto result = AllocatableBlock<Derived>::DoFree(std::move(block));
160 if (!result.ok()) {
161 return result;
162 }
163 block = result.block();
164 Derived* prev = block->Prev();
165 if (prev == nullptr) {
166 return result;
167 }
168 size_t prev_size = prev->RequestedSize();
169 if (prev->InnerSize() - prev_size < Derived::kAlignment) {
170 return result;
171 }
172 // Reclaim bytes that were shifted to prev when the block allocated.
173 size_t old_prev_size = prev->OuterSize();
174 prev->DoResize(prev_size, true).IgnoreUnlessStrict();
175 return BlockResult<Derived>(prev->Next(),
176 BlockResultPrev::kResizedSmaller,
177 old_prev_size - prev->OuterSize());
178}
179
180} // namespace pw::allocator
static constexpr BlockResult< Derived > DoAllocFirst(Derived *&&block, Layout layout)
Definition: alignable.h:129
static constexpr BlockResult< Derived > DoAllocLast(Derived *&&block, Layout layout)
Definition: alignable.h:161
static constexpr BlockResult< Derived > DoFree(Derived *&&block)
Definition: allocatable.h:428
Definition: result.h:116
Definition: with_layout.h:50
constexpr BlockResult< Derived > DoResize(size_t new_inner_size, bool shifted=false)
Definition: with_layout.h:143
constexpr Layout RequestedLayout() const
Definition: with_layout.h:106
static constexpr BlockResult< Derived > DoFree(Derived *&&block)
Definition: with_layout.h:157
static constexpr BlockResult< Derived > DoAllocFirst(Derived *&&block, Layout layout)
Definition: with_layout.h:117
static constexpr BlockResult< Derived > DoAllocLast(Derived *&&block, Layout layout)
Definition: with_layout.h:130
Definition: layout.h:58
constexpr bool has_layout_v
Helper variable template for has_layout<BlockType>::value.
Definition: with_layout.h:99
Definition: with_layout.h:95
Definition: with_layout.h:27