Pixie
Loading...
Searching...
No Matches
storage.h
Go to the documentation of this file.
1#pragma once
2
10
11#include <pixie/serialization.h>
12#include <pixie/split_span.h>
13
14#include <concepts>
15#include <cstddef>
16#include <cstdint>
17#include <span>
18#include <stdexcept>
19
20namespace pixie {
21
64template <class Impl>
65class StorageBase : public SerializationBase<Impl> {
66 public:
68 using position_type = std::uint64_t;
69
75 std::size_t size_bytes() const { return impl().size_bytes_impl(); }
76
78 std::size_t size_bits() const { return size_bytes() * 8; }
79
81 bool empty() const { return size_bytes() == 0; }
82
84 position_type begin_position() const { return impl().begin_position_impl(); }
85
87 position_type end_position() const { return impl().end_position_impl(); }
88
90 bool contains(position_type position, std::size_t count_bytes) const {
91 const position_type begin = begin_position();
92 const position_type end = end_position();
93 return position >= begin && position <= end &&
94 count_bytes <= end - position;
95 }
96
98 std::span<const std::byte> as_bytes() const
99 requires requires(const Impl& value) { value.as_bytes_impl(); }
100 {
101 return impl().as_bytes_impl();
102 }
103
110 requires requires(Impl& value) {
111 {
112 value.segments_impl(position_type{}, std::size_t{})
113 } -> std::same_as<SplitSpan<std::byte>>;
114 }
115 {
117 }
118
127
137 SplitSpan<std::byte> segments(position_type position, std::size_t count_bytes)
138 requires requires(Impl& value) {
139 {
140 value.segments_impl(position_type{}, std::size_t{})
141 } -> std::same_as<SplitSpan<std::byte>>;
142 }
143 {
144 if constexpr (requires(Impl& value) {
145 value.prepare_segments_impl(position_type{}, std::size_t{});
146 }) {
147 impl().prepare_segments_impl(position, count_bytes);
148 }
149 validate_range(position, count_bytes);
150 return impl().segments_impl(position, count_bytes);
151 }
152
160 std::size_t count_bytes) const {
161 validate_range(position, count_bytes);
162 return impl().segments_impl(position, count_bytes);
163 }
164
170 std::span<const std::uint16_t> as_words16() const
171 requires requires(const Impl& value) { value.as_bytes_impl(); }
172 {
173 return as_words<std::uint16_t>();
174 }
175
181 std::span<const std::uint64_t> as_words64() const
182 requires requires(const Impl& value) { value.as_bytes_impl(); }
183 {
184 return as_words<std::uint64_t>();
185 }
186
188 auto view() const
189 requires requires(const Impl& value) {
190 value.view_impl(std::size_t{}, std::size_t{});
191 }
192 {
193 return impl().view_impl(0, size_bytes());
194 }
195
202 auto view(std::size_t offset_bytes, std::size_t count_bytes) const
203 requires requires(const Impl& value) {
204 value.view_impl(std::size_t{}, std::size_t{});
205 }
206 {
207 return impl().view_impl(offset_bytes, count_bytes);
208 }
209
213 void serialize_impl(BinaryWriter& writer) const {
214 writer.write_size(size_bytes());
215 for (const std::span<const std::byte> segment : segments()) {
216 writer.write_bytes(segment);
217 }
218 }
219
221 void resize(std::size_t size_bits)
222 requires requires(Impl& value) { value.resize_impl(size_bits); }
223 {
224 impl().resize_impl(size_bits);
225 }
226
229 requires requires(Impl& value) { value.writable_bytes_impl(); }
230 {
231 return impl().writable_bytes_impl();
232 }
233
236 requires requires(Impl& value) { value.writable_words16_impl(); }
237 {
238 return impl().writable_words16_impl();
239 }
240
243 requires requires(Impl& value) { value.writable_words64_impl(); }
244 {
245 return impl().writable_words64_impl();
246 }
247
249 std::size_t allocated_bytes() const
250 requires requires(const Impl& value) { value.allocated_bytes_impl(); }
251 {
252 return impl().allocated_bytes_impl();
253 }
254
257 requires requires(Impl& value) { value.shrink_to_fit_impl(); }
258 {
259 impl().shrink_to_fit_impl();
260 }
261
262 private:
264 void validate_range(position_type position, std::size_t count_bytes) const {
265 if (!contains(position, count_bytes)) {
266 throw std::out_of_range("Storage range is outside the working window");
267 }
268 }
269
271 const Impl& impl() const { return static_cast<const Impl&>(*this); }
272
274 Impl& impl() { return static_cast<Impl&>(*this); }
275
276 template <class Word>
277 std::span<const Word> as_words() const {
278 const auto bytes = as_bytes();
279 if (bytes.size() % sizeof(Word) != 0 ||
280 reinterpret_cast<std::uintptr_t>(bytes.data()) % alignof(Word) != 0) {
281 throw std::invalid_argument("Storage is not aligned to the word type");
282 }
283 return {reinterpret_cast<const Word*>(bytes.data()),
284 bytes.size() / sizeof(Word)};
285 }
286};
287
289template <class Storage>
291 std::derived_from<Storage, StorageBase<Storage>>;
292
293} // namespace pixie
Bounded-buffer writer for canonical little-endian binary data.
Definition serialization.h:198
void write_bytes(std::span< const std::byte > bytes)
Append bytes without interpretation.
Definition serialization.h:297
void write_size(std::size_t value)
Write a platform size as an unsigned 64-bit integer.
Definition serialization.h:287
CRTP facade for optional binary serialization and deserialization.
Definition serialization.h:693
A logical contiguous sequence stored in at most two physical spans.
Definition split_span.h:25
CRTP facade for byte-addressable storage.
Definition storage.h:65
SplitSpan< std::byte > segments(position_type position, std::size_t count_bytes)
Return a checked writable logical byte range as one or two spans.
Definition storage.h:137
auto view() const
Return a non-owning read-only view of all exposed bytes.
Definition storage.h:188
std::span< const std::byte > as_bytes() const
Return a contiguous read-only view of all logical exposed bytes.
Definition storage.h:98
SplitSpan< const std::byte > segments() const
Return all logical bytes as one or two physical spans.
Definition storage.h:124
SplitSpan< std::byte > segments()
Return all logical bytes as one or two writable physical spans.
Definition storage.h:109
bool contains(position_type position, std::size_t count_bytes) const
Return whether a complete logical range is currently exposed.
Definition storage.h:90
auto writable_words64()
Return writable storage as 64-bit words.
Definition storage.h:242
void shrink_to_fit()
Request release of unused reserved storage.
Definition storage.h:256
std::span< const std::uint16_t > as_words16() const
Return a read-only view as 16-bit words.
Definition storage.h:170
std::span< const std::uint64_t > as_words64() const
Return a read-only view as 64-bit words.
Definition storage.h:181
position_type begin_position() const
Return the first logical byte position currently exposed.
Definition storage.h:84
void serialize_impl(BinaryWriter &writer) const
Serialize the exposed bytes with a 64-bit little-endian size prefix.
Definition storage.h:213
auto view(std::size_t offset_bytes, std::size_t count_bytes) const
Return a non-owning read-only byte subrange.
Definition storage.h:202
std::size_t size_bits() const
Return the exposed storage size in bits.
Definition storage.h:78
std::uint64_t position_type
Monotonic logical byte position used to address storage ranges.
Definition storage.h:68
auto writable_words16()
Return writable storage as 16-bit words.
Definition storage.h:235
std::size_t size_bytes() const
Return the logical exposed storage size in bytes.
Definition storage.h:75
SplitSpan< const std::byte > segments(position_type position, std::size_t count_bytes) const
Return a checked logical byte range as one or two physical spans.
Definition storage.h:159
position_type end_position() const
Return the position one past the last logical byte exposed.
Definition storage.h:87
auto writable_bytes()
Return writable storage bytes.
Definition storage.h:228
std::size_t allocated_bytes() const
Return bytes reserved by an owning storage implementation.
Definition storage.h:249
void resize(std::size_t size_bits)
Resize mutable storage to hold at least size_bits bits.
Definition storage.h:221
bool empty() const
Check whether the storage is empty.
Definition storage.h:81
A concrete CRTP implementation of StorageBase.
Definition storage.h:290
Checked byte-oriented binary serialization primitives.
Allocation-free logical ranges split across at most two spans.