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) : info_{} {
101 next_ = static_cast<OffsetType>(outer_size / Basic::kAlignment);
102 info_.last = 1;
103 info_.alignment = Basic::kAlignment;
104 }
105
106 // `Basic` required methods.
107 friend Basic;
108 static constexpr size_t DefaultAlignment() {
109 return std::max(alignof(OffsetType),
110 Parameters::kLayoutWhenFree.alignment());
111 }
112 static constexpr size_t BlockOverhead() { return sizeof(BlockType); }
113 static constexpr size_t MinInnerSize() { return 1; }
114 static constexpr size_t ReservedWhenFree() {
115 return Parameters::kLayoutWhenFree.size();
116 }
117 constexpr size_t OuterSizeUnchecked() const;
118
119 // `Basic` overrides.
120 constexpr bool DoCheckInvariants(bool strict) const;
121
122 // `Contiguous` required methods.
124 friend Contiguous;
125
126 static constexpr size_t MaxAddressableSize() {
127 auto kOffsetMax =
128 static_cast<size_t>(std::numeric_limits<OffsetType>::max());
129 auto kSizeMax = static_cast<size_t>(std::numeric_limits<size_t>::max());
130 return std::min(kSizeMax / Basic::kAlignment, kOffsetMax) *
131 Basic::kAlignment;
132 }
133
134 constexpr bool IsLastUnchecked() const { return info_.last != 0; }
135 static constexpr BlockType* AsBlock(ByteSpan bytes);
136 constexpr void SetNext(size_t outer_size, BlockType* next);
137 constexpr size_t PrevOuterSizeUnchecked() const;
138
139 // `Contiguous` overrides.
140 constexpr BlockType* DoSplitFirst(size_t new_inner_size);
141 constexpr BlockType* DoSplitLast(size_t new_inner_size);
142 constexpr void DoMergeNext();
143
144 // `Allocatable` required methods.
146 friend Allocatable;
147 constexpr bool IsFreeUnchecked() const { return info_.used == 0; }
148 constexpr void SetFree(bool is_free);
149
150 // `Alignable` overrides.
152 friend Alignable;
153 constexpr StatusWithSize DoCanAlloc(Layout layout) const;
154 static constexpr BlockResult<BlockType> DoAllocFirst(BlockType*&& block,
155 Layout layout);
156 static constexpr BlockResult<BlockType> DoAllocLast(BlockType*&& block,
157 Layout layout);
158 constexpr BlockResult<BlockType> DoResize(size_t new_inner_size,
159 bool shifted = false);
160 static constexpr BlockResult<BlockType> DoFree(BlockType*&& block);
161
162 // `WithLayout` required methods.
164 friend WithLayout;
165 constexpr size_t RequestedSize() const {
166 return Basic::InnerSize() - padding_;
167 }
168 constexpr size_t RequestedAlignment() const { return info_.alignment; }
169 constexpr void SetRequestedSize(size_t size);
170 constexpr void SetRequestedAlignment(size_t alignment);
171
172 // `Poisonable` required methods.
174 friend Poisonable;
175 constexpr bool IsPoisonedUnchecked() const { return info_.poisoned != 0; }
176 constexpr void SetPoisoned(bool is_poisoned) { info_.poisoned = is_poisoned; }
177
180 OffsetType prev_ = 0;
181
185 OffsetType next_ = 0;
186
197 struct {
198 uint16_t used : 1;
199 uint16_t poisoned : 1;
200 uint16_t last : 1;
201 uint16_t alignment : 13;
202 } info_;
203
206 uint16_t padding_ = 0;
207};
208
209// Convenience alias that constructs the block traits automatically.
210template <typename OffsetType = uintptr_t, typename WhenFree = void>
211using DetailedBlock =
213
215
216// Template method implementations.
217
218// `Basic` methods.
219
220template <typename Parameters>
222 size_t outer_size = next_;
223 Hardening::Multiply(outer_size, Basic::kAlignment);
224 return outer_size;
225}
226
227template <typename Parameters>
228constexpr bool DetailedBlockImpl<Parameters>::DoCheckInvariants(
229 bool strict) const {
230 return Basic::DoCheckInvariants(strict) &&
231 Contiguous::DoCheckInvariants(strict) &&
232 Poisonable::DoCheckInvariants(strict);
233}
234
235// `Contiguous` methods.
236
237template <typename Parameters>
238constexpr DetailedBlockImpl<Parameters>* DetailedBlockImpl<Parameters>::AsBlock(
239 ByteSpan bytes) {
240 return ::new (bytes.data()) DetailedBlockImpl(bytes.size());
241}
242
243template <typename Parameters>
244constexpr void DetailedBlockImpl<Parameters>::SetNext(size_t outer_size,
245 BlockType* next) {
246 next_ = static_cast<OffsetType>(outer_size / Basic::kAlignment);
247 if (next == nullptr) {
248 info_.last = 1;
249 return;
250 }
251 info_.last = 0;
252 next->prev_ = next_;
253}
254
255template <typename Parameters>
256constexpr size_t DetailedBlockImpl<Parameters>::PrevOuterSizeUnchecked() const {
257 size_t outer_size = prev_;
258 Hardening::Multiply(outer_size, Basic::kAlignment);
259 return outer_size;
260}
261
262template <typename Parameters>
263constexpr DetailedBlockImpl<Parameters>*
264DetailedBlockImpl<Parameters>::DoSplitFirst(size_t new_inner_size) {
265 return Poisonable::DoSplitFirst(new_inner_size);
266}
267
268template <typename Parameters>
269constexpr DetailedBlockImpl<Parameters>*
270DetailedBlockImpl<Parameters>::DoSplitLast(size_t new_inner_size) {
271 return Poisonable::DoSplitLast(new_inner_size);
272}
273
274template <typename Parameters>
275constexpr void DetailedBlockImpl<Parameters>::DoMergeNext() {
276 Poisonable::DoMergeNext();
277}
278
279// `Alignable` methods.
280
281template <typename Parameters>
282constexpr void DetailedBlockImpl<Parameters>::SetFree(bool is_free) {
283 info_.used = !is_free;
284 Poisonable::SetFree(is_free);
285}
286
287// `Alignable` methods.
288
289template <typename Parameters>
290constexpr StatusWithSize DetailedBlockImpl<Parameters>::DoCanAlloc(
291 Layout layout) const {
292 return Alignable::DoCanAlloc(layout);
293}
294
295template <typename Parameters>
296constexpr BlockResult<DetailedBlockImpl<Parameters>>
297DetailedBlockImpl<Parameters>::DoAllocFirst(DetailedBlockImpl*&& block,
298 Layout layout) {
299 return WithLayout::DoAllocFirst(std::move(block), layout);
300}
301
302template <typename Parameters>
303constexpr BlockResult<DetailedBlockImpl<Parameters>>
304DetailedBlockImpl<Parameters>::DoAllocLast(DetailedBlockImpl*&& block,
305 Layout layout) {
306 return WithLayout::DoAllocLast(std::move(block), layout);
307}
308
309template <typename Parameters>
310constexpr BlockResult<DetailedBlockImpl<Parameters>>
311DetailedBlockImpl<Parameters>::DoResize(size_t new_inner_size, bool shifted) {
312 return WithLayout::DoResize(new_inner_size, shifted);
313}
314
315template <typename Parameters>
316constexpr BlockResult<DetailedBlockImpl<Parameters>>
317DetailedBlockImpl<Parameters>::DoFree(DetailedBlockImpl*&& block) {
318 return WithLayout::DoFree(std::move(block));
319}
320
321// `WithLayout` methods.
322
323template <typename Parameters>
324constexpr void DetailedBlockImpl<Parameters>::SetRequestedSize(size_t size) {
325 size_t inner_size = Basic::InnerSize();
326 size_t padding = inner_size;
327 Hardening::Decrement(padding, size);
328 if constexpr (Hardening::kIncludesDebugChecks) {
329 PW_ASSERT(padding <= std::numeric_limits<uint16_t>::max());
330 }
331 padding_ = static_cast<uint16_t>(padding);
332}
333
334template <typename Parameters>
335constexpr void DetailedBlockImpl<Parameters>::SetRequestedAlignment(
336 size_t alignment) {
337 if constexpr (Hardening::kIncludesDebugChecks) {
338 PW_ASSERT((alignment & (alignment - 1)) == 0);
339 PW_ASSERT(alignment < 0x2000);
340 }
341 info_.alignment = static_cast<uint16_t>(alignment);
342}
343
344} // namespace pw::allocator
Definition: status_with_size.h:51
Definition: alignable.h:44
Definition: allocatable.h:51
Definition: basic.h:95
constexpr size_t InnerSize() const
Definition: basic.h:288
Definition: result.h:116
Definition: with_layout.h:50
Definition: contiguous.h:47
Definition: detailed_block.h:88
Definition: iterable.h:76
Definition: iterable.h:35
Definition: layout.h:58
Definition: poisonable.h:53
Definition: detailed_block.h:49