C/C++ API Reference
Loading...
Searching...
No Matches
detailed_block.h
1// Copyright 2020 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 <limits>
19#include <new>
20
21#include "pw_allocator/block/alignable.h"
22#include "pw_allocator/block/allocatable.h"
23#include "pw_allocator/block/basic.h"
24#include "pw_allocator/block/contiguous.h"
25#include "pw_allocator/block/iterable.h"
26#include "pw_allocator/block/poisonable.h"
27#include "pw_allocator/block/result.h"
28#include "pw_allocator/block/with_layout.h"
29#include "pw_allocator/hardening.h"
30#include "pw_allocator/layout.h"
31#include "pw_assert/assert.h"
32#include "pw_bytes/span.h"
33#include "pw_status/status.h"
34
35namespace pw::allocator {
36
38
48template <typename OffsetType_, typename WhenFree>
50 using OffsetType = std::make_unsigned_t<OffsetType_>;
51 static constexpr Layout kLayoutWhenFree = Layout::Of<WhenFree>();
52};
53
54template <typename OffsetType_>
55struct DetailedBlockParameters<OffsetType_, void> {
56 using OffsetType = std::make_unsigned_t<OffsetType_>;
57 static constexpr Layout kLayoutWhenFree = Layout(0, 1);
58};
59
80template <typename Parameters>
82 : public BasicBlock<DetailedBlockImpl<Parameters>>,
83 public IterableBlock<DetailedBlockImpl<Parameters>>,
84 public ContiguousBlock<DetailedBlockImpl<Parameters>>,
85 public AllocatableBlock<DetailedBlockImpl<Parameters>>,
86 public AlignableBlock<DetailedBlockImpl<Parameters>>,
87 public BlockWithLayout<DetailedBlockImpl<Parameters>>,
88 public PoisonableBlock<DetailedBlockImpl<Parameters>> {
89 private:
92
93 public:
94 using OffsetType = typename Parameters::OffsetType;
95
96 using Range = typename IterableBlock<BlockType>::Range;
97 using Iterator = typename IterableBlock<BlockType>::Iterator;
98
99 private:
100 constexpr explicit DetailedBlockImpl(size_t outer_size);
101
102 // `Basic` required methods.
103 friend Basic;
104 static constexpr size_t DefaultAlignment();
105 static constexpr size_t BlockOverhead();
106 static constexpr size_t MinInnerSize();
107 static constexpr size_t ReservedWhenFree();
108 constexpr size_t OuterSizeUnchecked() const;
109
110 // `Basic` overrides.
111 constexpr bool DoCheckInvariants(bool strict) const;
112
113 // `Contiguous` required methods.
115 friend Contiguous;
116
117 static constexpr size_t MaxAddressableSize();
118 constexpr bool IsLastUnchecked() const { return info_.last != 0; }
119 static constexpr BlockType* AsBlock(ByteSpan bytes);
120 constexpr void SetNext(size_t outer_size, BlockType* next);
121 constexpr size_t PrevOuterSizeUnchecked() const;
122
123 // `Contiguous` overrides.
124 constexpr BlockType* DoSplitFirst(size_t new_inner_size);
125 constexpr BlockType* DoSplitLast(size_t new_inner_size);
126 constexpr void DoMergeNext();
127
128 // `Allocatable` required methods.
130 friend Allocatable;
131 constexpr bool IsFreeUnchecked() const { return info_.used == 0; }
132 constexpr void SetFree(bool is_free);
133
134 // `Alignable` overrides.
136 friend Alignable;
137 constexpr StatusWithSize DoCanAlloc(Layout layout) const;
138 static constexpr BlockResult<BlockType> DoAllocFirst(BlockType*&& block,
139 Layout layout);
140 static constexpr BlockResult<BlockType> DoAllocLast(BlockType*&& block,
141 Layout layout);
142 constexpr BlockResult<BlockType> DoResize(size_t new_inner_size,
143 bool shifted = false);
144 static constexpr BlockResult<BlockType> DoFree(BlockType*&& block);
145
146 // `WithLayout` required methods.
148 friend WithLayout;
149 constexpr size_t RequestedSize() const;
150 constexpr size_t RequestedAlignment() const { return info_.alignment; }
151 constexpr void SetRequestedSize(size_t size);
152 constexpr void SetRequestedAlignment(size_t alignment);
153
154 // `Poisonable` required methods.
156 friend Poisonable;
157 constexpr bool IsPoisonedUnchecked() const { return info_.poisoned != 0; }
158 constexpr void SetPoisoned(bool is_poisoned) { info_.poisoned = is_poisoned; }
159
162 OffsetType prev_ = 0;
163
167 OffsetType next_ = 0;
168
179 struct {
180 uint16_t used : 1;
181 uint16_t poisoned : 1;
182 uint16_t last : 1;
183 uint16_t alignment : 13;
184 } info_;
185
188 uint16_t padding_ = 0;
189};
190
191// Convenience alias that constructs the block traits automatically.
192template <typename OffsetType = uintptr_t, typename WhenFree = void>
193using DetailedBlock =
195
197
198// Template method implementations.
199
200template <typename Parameters>
201constexpr DetailedBlockImpl<Parameters>::DetailedBlockImpl(size_t outer_size)
202 : info_{} {
203 next_ = static_cast<OffsetType>(outer_size / Basic::kAlignment);
204 info_.last = 1;
205 info_.alignment = Basic::kAlignment;
206}
207
208// `Basic` methods.
209
210template <typename Parameters>
211constexpr size_t DetailedBlockImpl<Parameters>::DefaultAlignment() {
212 return std::max(alignof(OffsetType), Parameters::kLayoutWhenFree.alignment());
213}
214
215template <typename Parameters>
216constexpr size_t DetailedBlockImpl<Parameters>::BlockOverhead() {
217 return sizeof(BlockType);
218}
219
220template <typename Parameters>
221constexpr size_t DetailedBlockImpl<Parameters>::MinInnerSize() {
222 return 1;
223}
224
225template <typename Parameters>
226constexpr size_t DetailedBlockImpl<Parameters>::ReservedWhenFree() {
227 return Parameters::kLayoutWhenFree.size();
228}
229
230template <typename Parameters>
231constexpr size_t DetailedBlockImpl<Parameters>::OuterSizeUnchecked() const {
232 size_t outer_size = next_;
233 Hardening::Multiply(outer_size, Basic::kAlignment);
234 return outer_size;
235}
236
237template <typename Parameters>
238constexpr bool DetailedBlockImpl<Parameters>::DoCheckInvariants(
239 bool strict) const {
240 return Basic::DoCheckInvariants(strict) &&
241 Contiguous::DoCheckInvariants(strict) &&
242 Poisonable::DoCheckInvariants(strict);
243}
244
245// `Contiguous` methods.
246
247template <typename Parameters>
248constexpr size_t DetailedBlockImpl<Parameters>::MaxAddressableSize() {
249 auto kOffsetMax = static_cast<size_t>(std::numeric_limits<OffsetType>::max());
250 auto kSizeMax = std::numeric_limits<size_t>::max();
251 return std::min(kSizeMax / Basic::kAlignment, kOffsetMax) * Basic::kAlignment;
252}
253
254template <typename Parameters>
255constexpr DetailedBlockImpl<Parameters>* DetailedBlockImpl<Parameters>::AsBlock(
256 ByteSpan bytes) {
257 return ::new (bytes.data()) DetailedBlockImpl(bytes.size());
258}
259
260template <typename Parameters>
261constexpr void DetailedBlockImpl<Parameters>::SetNext(size_t outer_size,
262 BlockType* next) {
263 next_ = static_cast<OffsetType>(outer_size / Basic::kAlignment);
264 if (next == nullptr) {
265 info_.last = 1;
266 return;
267 }
268 info_.last = 0;
269 next->prev_ = next_;
270}
271
272template <typename Parameters>
273constexpr size_t DetailedBlockImpl<Parameters>::PrevOuterSizeUnchecked() const {
274 size_t outer_size = prev_;
275 Hardening::Multiply(outer_size, Basic::kAlignment);
276 return outer_size;
277}
278
279template <typename Parameters>
280constexpr DetailedBlockImpl<Parameters>*
281DetailedBlockImpl<Parameters>::DoSplitFirst(size_t new_inner_size) {
282 return Poisonable::DoSplitFirst(new_inner_size);
283}
284
285template <typename Parameters>
286constexpr DetailedBlockImpl<Parameters>*
287DetailedBlockImpl<Parameters>::DoSplitLast(size_t new_inner_size) {
288 return Poisonable::DoSplitLast(new_inner_size);
289}
290
291template <typename Parameters>
292constexpr void DetailedBlockImpl<Parameters>::DoMergeNext() {
293 Poisonable::DoMergeNext();
294}
295
296// `Alignable` methods.
297
298template <typename Parameters>
299constexpr void DetailedBlockImpl<Parameters>::SetFree(bool is_free) {
300 info_.used = !is_free;
301 padding_ = 0;
302 Poisonable::SetFree(is_free);
303}
304
305// `Alignable` methods.
306
307template <typename Parameters>
308constexpr StatusWithSize DetailedBlockImpl<Parameters>::DoCanAlloc(
309 Layout layout) const {
310 return Alignable::DoCanAlloc(layout);
311}
312
313template <typename Parameters>
314constexpr BlockResult<DetailedBlockImpl<Parameters>>
315DetailedBlockImpl<Parameters>::DoAllocFirst(DetailedBlockImpl*&& block,
316 Layout layout) {
317 return WithLayout::DoAllocFirst(std::move(block), layout);
318}
319
320template <typename Parameters>
321constexpr BlockResult<DetailedBlockImpl<Parameters>>
322DetailedBlockImpl<Parameters>::DoAllocLast(DetailedBlockImpl*&& block,
323 Layout layout) {
324 return WithLayout::DoAllocLast(std::move(block), layout);
325}
326
327template <typename Parameters>
328constexpr BlockResult<DetailedBlockImpl<Parameters>>
329DetailedBlockImpl<Parameters>::DoResize(size_t new_inner_size, bool shifted) {
330 return WithLayout::DoResize(new_inner_size, shifted);
331}
332
333template <typename Parameters>
334constexpr BlockResult<DetailedBlockImpl<Parameters>>
335DetailedBlockImpl<Parameters>::DoFree(DetailedBlockImpl*&& block) {
336 return WithLayout::DoFree(std::move(block));
337}
338
339// `WithLayout` methods.
340
341template <typename Parameters>
342constexpr size_t DetailedBlockImpl<Parameters>::RequestedSize() const {
343 if constexpr (Hardening::kIncludesDebugChecks) {
344 PW_ASSERT(padding_ <= Basic::InnerSize());
345 }
346 return Basic::InnerSize() - padding_;
347}
348
349template <typename Parameters>
350constexpr void DetailedBlockImpl<Parameters>::SetRequestedSize(size_t size) {
351 size_t inner_size = Basic::InnerSize();
352 size_t padding = inner_size;
353 Hardening::Decrement(padding, size);
354 if constexpr (Hardening::kIncludesDebugChecks) {
355 PW_ASSERT(padding <= std::numeric_limits<uint16_t>::max());
356 }
357 padding_ = static_cast<uint16_t>(padding);
358}
359
360template <typename Parameters>
361constexpr void DetailedBlockImpl<Parameters>::SetRequestedAlignment(
362 size_t alignment) {
363 if constexpr (Hardening::kIncludesDebugChecks) {
364 PW_ASSERT((alignment & (alignment - 1)) == 0);
365 PW_ASSERT(alignment < 0x2000);
366 }
367 info_.alignment = static_cast<uint16_t>(alignment);
368}
369
370} // namespace pw::allocator
Definition: status_with_size.h:51
Definition: alignable.h:44
Definition: allocatable.h:51
Definition: basic.h:95
Definition: result.h:106
Definition: with_layout.h:50
Definition: contiguous.h:47
Definition: detailed_block.h:88
Definition: iterable.h:69
Definition: iterable.h:35
Definition: layout.h:64
Definition: poisonable.h:53
Definition: detailed_block.h:49