C/C++ API Reference
Loading...
Searching...
No Matches
entry.h
1// Copyright 2025 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
20#include "pw_allocator/deallocator.h"
21#include "pw_allocator/internal/control_block.h"
22#include "pw_bytes/span.h"
23#include "pw_containers/dynamic_deque.h"
24#include "pw_preprocessor/compiler.h"
25
26namespace pw::multibuf::v2::internal {
27
30enum class Mutability {
31 kMutable,
32 kConst,
33};
34
47struct Entry {
49 using size_type = Deque::size_type;
50 using difference_type = Deque::difference_type;
51
53 static constexpr size_t kMaxSize = ~(1U << 15);
54
56 static constexpr size_type kMemoryContextIndex = 0;
57
59 static constexpr size_type kDataIndex = 1;
60
62 static constexpr size_type kBaseViewIndex = 2;
63
65 static constexpr size_type kMinEntriesPerChunk = 3;
66
68 [[nodiscard]] static constexpr size_type num_chunks(
69 const Deque& deque, size_type entries_per_chunk) {
70 return deque.size() / entries_per_chunk;
71 }
72
75 [[nodiscard]] static constexpr size_type num_layers(
76 size_type entries_per_chunk) {
77 return entries_per_chunk - Entry::kMinEntriesPerChunk + 1;
78 }
79
81 [[nodiscard]] static constexpr size_type memory_context_index(
82 size_type chunk, size_type entries_per_chunk) {
83 return chunk * entries_per_chunk + kMemoryContextIndex;
84 }
85
87 [[nodiscard]] static constexpr size_type data_index(
88 size_type chunk, size_type entries_per_chunk) {
89 return chunk * entries_per_chunk + kDataIndex;
90 }
91
93 [[nodiscard]] static constexpr size_type base_view_index(
94 size_type chunk, size_type entries_per_chunk) {
95 return chunk * entries_per_chunk + kBaseViewIndex;
96 }
97
99 [[nodiscard]] static constexpr size_type view_index(
100 size_type chunk, size_type entries_per_chunk, size_type layer) {
101 return chunk * entries_per_chunk + kBaseViewIndex + layer - 1;
102 }
103
105 [[nodiscard]] static constexpr size_type top_view_index(
106 size_type chunk, size_type entries_per_chunk) {
107 return (chunk + 1) * entries_per_chunk - 1;
108 }
109
111 [[nodiscard]] static constexpr std::byte* GetData(
112 const Deque& deque, size_type chunk, size_type entries_per_chunk) {
113 return deque[data_index(chunk, entries_per_chunk)].data;
114 }
115
118 [[nodiscard]] static constexpr bool IsOwned(const Deque& deque,
119 size_type chunk,
120 size_type entries_per_chunk) {
121 return deque[base_view_index(chunk, entries_per_chunk)].base_view.owned;
122 }
123
126 [[nodiscard]] static constexpr bool IsShared(const Deque& deque,
127 size_type chunk,
128 size_type entries_per_chunk) {
129 return deque[base_view_index(chunk, entries_per_chunk)].base_view.shared;
130 }
131
133 [[nodiscard]] static constexpr bool IsSealed(const Deque& deque,
134 size_type chunk,
135 size_type entries_per_chunk) {
136 return entries_per_chunk == Entry::kMinEntriesPerChunk
137 ? false
138 : deque[top_view_index(chunk, entries_per_chunk)].view.sealed;
139 }
140
142 [[nodiscard]] static constexpr Deallocator& GetDeallocator(
143 const Deque& deque, size_type chunk, size_type entries_per_chunk) {
144 PW_ASSERT(IsOwned(deque, chunk, entries_per_chunk));
145 return *(deque[memory_context_index(chunk, entries_per_chunk)].deallocator);
146 }
147
149 [[nodiscard]] static constexpr allocator::internal::ControlBlock&
150 GetControlBlock(const Deque& deque,
151 size_type chunk,
152 size_type entries_per_chunk) {
153 PW_ASSERT(IsShared(deque, chunk, entries_per_chunk));
154 return *(
155 deque[memory_context_index(chunk, entries_per_chunk)].control_block);
156 }
157
159 [[nodiscard]] static constexpr bool IsBoundary(const Deque& deque,
160 size_type chunk,
161 size_type entries_per_chunk,
162 size_type layer) {
163 return layer == 1 ? true
164 : deque[view_index(chunk, entries_per_chunk, layer)]
165 .view.boundary;
166 }
167
169 [[nodiscard]] static constexpr bool IsBoundary(const Deque& deque,
170 size_type chunk,
171 size_type entries_per_chunk) {
172 return IsBoundary(
173 deque, chunk, entries_per_chunk, num_layers(entries_per_chunk));
174 }
175
177 [[nodiscard]] static constexpr size_type GetOffset(
178 const Deque& deque,
179 size_type chunk,
180 size_type entries_per_chunk,
181 size_type layer) {
182 return layer == 1
183 ? deque[base_view_index(chunk, entries_per_chunk)]
184 .base_view.offset
185 : deque[view_index(chunk, entries_per_chunk, layer)].view.offset;
186 }
187
189 [[nodiscard]] static constexpr size_type GetOffset(
190 const Deque& deque, size_type chunk, size_type entries_per_chunk) {
191 return GetOffset(
192 deque, chunk, entries_per_chunk, num_layers(entries_per_chunk));
193 }
194
197 [[nodiscard]] static constexpr size_type GetRelativeOffset(
198 const Deque& deque,
199 size_type chunk,
200 size_type entries_per_chunk,
201 size_type layer) {
202 return layer == 1 ? GetOffset(deque, chunk, entries_per_chunk, layer)
203 : (GetOffset(deque, chunk, entries_per_chunk, layer) -
204 GetOffset(deque, chunk, entries_per_chunk, layer - 1));
205 }
206
209 [[nodiscard]] static constexpr size_type GetRelativeOffset(
210 const Deque& deque, size_type chunk, size_type entries_per_chunk) {
211 return GetRelativeOffset(
212 deque, chunk, entries_per_chunk, num_layers(entries_per_chunk));
213 }
214
216 [[nodiscard]] static constexpr size_type GetLength(
217 const Deque& deque,
218 size_type chunk,
219 size_type entries_per_chunk,
220 size_type layer) {
221 return layer == 1
222 ? deque[base_view_index(chunk, entries_per_chunk)]
223 .base_view.length
224 : deque[view_index(chunk, entries_per_chunk, layer)].view.length;
225 }
226
228 [[nodiscard]] static constexpr size_type GetLength(
229 const Deque& deque, size_type chunk, size_type entries_per_chunk) {
230 return GetLength(
231 deque, chunk, entries_per_chunk, num_layers(entries_per_chunk));
232 }
233
235 [[nodiscard]] static constexpr ByteSpan GetView(const Deque& deque,
236 size_type chunk,
237 size_type entries_per_chunk,
238 size_type layer) {
239 std::byte* data = GetData(deque, chunk, entries_per_chunk);
240 size_type offset = GetOffset(deque, chunk, entries_per_chunk, layer);
241 size_type length = GetLength(deque, chunk, entries_per_chunk, layer);
242 return ByteSpan(data + offset, length);
243 }
244
246 [[nodiscard]] static constexpr ByteSpan GetView(const Deque& deque,
247 size_type chunk,
248 size_type entries_per_chunk) {
249 return GetView(
250 deque, chunk, entries_per_chunk, num_layers(entries_per_chunk));
251 }
252
254 struct BaseView {
256 size_type offset : 15;
257
260 size_type owned : 1;
261
263 size_type length : 15;
264
267 size_type shared : 1;
268 };
269
272 struct View {
274 size_type offset : 15;
275
280 size_type sealed : 1;
281
283 size_type length : 15;
284
288 size_type boundary : 1;
289 };
290
305 union {
308
310 allocator::internal::ControlBlock* control_block;
311
313 std::byte* data;
314
315 BaseView base_view;
316
317 View view;
318 };
319
320 // All fields should fit into a pointer's width.
321 static_assert(sizeof(BaseView) <= sizeof(void*));
322 static_assert(sizeof(View) <= sizeof(void*));
323};
324
325} // namespace pw::multibuf::v2::internal
Abstract interface for releasing memory.
Definition: deallocator.h:29
Definition: dynamic_deque.h:60
constexpr size_type size() const noexcept
Returns the number of elements in the deque.
Definition: generic_deque.h:69
Describes the entire memory region.
Definition: entry.h:254
size_type owned
Definition: entry.h:260
size_type length
Amount of data from the buffer to present.
Definition: entry.h:263
size_type offset
Starting offset within the buffer of the data to present.
Definition: entry.h:256
size_type shared
Definition: entry.h:267
Definition: entry.h:272
size_type length
Amount of data from the buffer to present.
Definition: entry.h:283
size_type offset
Starting offset within the buffer of the data to present.
Definition: entry.h:274
size_type sealed
Definition: entry.h:280
size_type boundary
Definition: entry.h:288
Definition: entry.h:47
static constexpr size_type kBaseViewIndex
Per-chunk index entry that holds the base view of the data.
Definition: entry.h:62
static constexpr size_type kDataIndex
Per-chunk index entry that holds the data pointer.
Definition: entry.h:59
static constexpr size_type num_chunks(const Deque &deque, size_type entries_per_chunk)
Returns the number of chunks in a deque.
Definition: entry.h:68
static constexpr Deallocator & GetDeallocator(const Deque &deque, size_type chunk, size_type entries_per_chunk)
Returns the deallocator for a chunk, which must be owned.
Definition: entry.h:142
static constexpr bool IsSealed(const Deque &deque, size_type chunk, size_type entries_per_chunk)
Returns whether the chunk is part of a sealed layer.
Definition: entry.h:133
static constexpr size_type GetRelativeOffset(const Deque &deque, size_type chunk, size_type entries_per_chunk)
Definition: entry.h:209
Deallocator * deallocator
Optional deallocator involved in freeing owned memory.
Definition: entry.h:307
static constexpr size_type kMemoryContextIndex
Per-chunk index entry that holds the deallocator or control block.
Definition: entry.h:56
allocator::internal::ControlBlock * control_block
Optional control block involved in freeing shared memory.
Definition: entry.h:310
std::byte * data
Pointer to memory.
Definition: entry.h:313
static constexpr size_type num_layers(size_type entries_per_chunk)
Definition: entry.h:75
static constexpr size_t kMaxSize
Offset and length must fit in 15 bits.
Definition: entry.h:53
static constexpr ByteSpan GetView(const Deque &deque, size_type chunk, size_type entries_per_chunk, size_type layer)
Returns a view of the visible data length of the chunk at the given layer.
Definition: entry.h:235
static constexpr size_type GetLength(const Deque &deque, size_type chunk, size_type entries_per_chunk, size_type layer)
Returns the length of the given layer of the chunk.
Definition: entry.h:216
static constexpr bool IsBoundary(const Deque &deque, size_type chunk, size_type entries_per_chunk)
Returns whether the top layer of a chunk represents a fragment boundary.
Definition: entry.h:169
static constexpr bool IsShared(const Deque &deque, size_type chunk, size_type entries_per_chunk)
Definition: entry.h:126
static constexpr size_type GetRelativeOffset(const Deque &deque, size_type chunk, size_type entries_per_chunk, size_type layer)
Definition: entry.h:197
static constexpr size_type GetLength(const Deque &deque, size_type chunk, size_type entries_per_chunk)
Returns the length of the top layer of the chunk.
Definition: entry.h:228
static constexpr ByteSpan GetView(const Deque &deque, size_type chunk, size_type entries_per_chunk)
Returns a view of the visible data length of the chunk at the top layer.
Definition: entry.h:246
static constexpr size_type memory_context_index(size_type chunk, size_type entries_per_chunk)
Returns the index to the data entry of a given chunk.
Definition: entry.h:81
static constexpr size_type GetOffset(const Deque &deque, size_type chunk, size_type entries_per_chunk, size_type layer)
Returns the offset of the given layer of the chunk.
Definition: entry.h:177
static constexpr size_type base_view_index(size_type chunk, size_type entries_per_chunk)
Returns the index to the base view entry of a given chunk.
Definition: entry.h:93
static constexpr size_type top_view_index(size_type chunk, size_type entries_per_chunk)
Returns the index to the top view entry of a given chunk.
Definition: entry.h:105
static constexpr bool IsBoundary(const Deque &deque, size_type chunk, size_type entries_per_chunk, size_type layer)
Returns whether the given layer of a chunk represents a fragment boundary.
Definition: entry.h:159
static constexpr size_type view_index(size_type chunk, size_type entries_per_chunk, size_type layer)
Returns the index to a view entry of a given chunk.
Definition: entry.h:99
static constexpr size_type kMinEntriesPerChunk
Minimum number of entries per chunk.
Definition: entry.h:65
static constexpr size_type GetOffset(const Deque &deque, size_type chunk, size_type entries_per_chunk)
Returns the offset of the top layer of the chunk.
Definition: entry.h:189
static constexpr std::byte * GetData(const Deque &deque, size_type chunk, size_type entries_per_chunk)
Returns the memory backing the chunk at the given index.
Definition: entry.h:111
static constexpr allocator::internal::ControlBlock & GetControlBlock(const Deque &deque, size_type chunk, size_type entries_per_chunk)
Returns the control block for a chunk, which must be shared.
Definition: entry.h:150
static constexpr bool IsOwned(const Deque &deque, size_type chunk, size_type entries_per_chunk)
Definition: entry.h:118
static constexpr size_type data_index(size_type chunk, size_type entries_per_chunk)
Returns the index to the data entry of a given chunk.
Definition: entry.h:87