Pixie
Loading...
Searching...
No Matches
metadata_array.h
1#pragma once
2
3#include <pixie/storage.h>
4
5#include <algorithm>
6#include <cstddef>
7#include <cstdint>
8#include <cstring>
9#include <limits>
10#include <span>
11#include <stdexcept>
12#include <type_traits>
13
14namespace pixie::detail::compressed {
15
16template <class Storage>
18 StorageImplementation<Storage> && std::default_initializable<Storage> &&
19 requires(Storage& storage, const Storage& readonly) {
20 storage.resize(std::size_t{});
21 { storage.writable_bytes() } -> std::same_as<std::span<std::byte>>;
22 { readonly.as_bytes() } -> std::same_as<std::span<const std::byte>>;
23 };
24
25// Fixed-size typed metadata; validate storage once, before initializing bytes.
26template <class T, StorageImplementation Storage>
27class MetadataArray {
28 static_assert(std::is_trivially_copyable_v<T>);
29
30 public:
31 MetadataArray() = default;
32
33 explicit MetadataArray(std::size_t count)
35 {
36 std::ranges::fill(allocate(count), std::byte{0});
37 }
38
39 explicit MetadataArray(std::span<const T> values)
41 {
42 auto bytes = allocate(values.size());
43 if (!values.empty()) {
44 std::memcpy(bytes.data(), values.data(), values.size_bytes());
45 }
46 }
47
48 const T* data() const {
49 return reinterpret_cast<const T*>(storage_.as_bytes().data());
50 }
51
52 T* data()
54 {
55 return reinterpret_cast<T*>(storage_.writable_bytes().data());
56 }
57
58 const T& operator[](std::size_t index) const { return data()[index]; }
59
60 T& operator[](std::size_t index)
62 {
63 return data()[index];
64 }
65
66 std::size_t size() const { return storage_.size_bytes() / sizeof(T); }
67
68 bool empty() const { return size() == 0; }
69
70 std::size_t allocated_bytes() const
71 requires requires(const Storage& storage) { storage.allocated_bytes(); }
72 {
73 return storage_.allocated_bytes();
74 }
75
76 private:
77 Storage storage_;
78
79 std::span<std::byte> allocate(std::size_t count)
81 {
82 if (count > std::numeric_limits<std::size_t>::max() / (sizeof(T) * 8)) {
83 throw std::length_error("Compressed metadata allocation too large");
84 }
85 if (count == 0) {
86 return {};
87 }
88 const auto byte_count = count * sizeof(T);
89 storage_.resize(byte_count * 8);
90 auto bytes = storage_.writable_bytes();
91 const auto readonly = storage_.as_bytes();
92 if (bytes.size() != byte_count || readonly.size() != byte_count ||
93 readonly.data() != bytes.data() ||
94 storage_.size_bytes() != byte_count ||
95 reinterpret_cast<std::uintptr_t>(bytes.data()) %
96 std::max(alignof(T), alignof(std::uint64_t)) !=
97 0) {
98 throw std::invalid_argument(
99 "Compressed metadata storage must be contiguous and word aligned");
100 }
101 return bytes;
102 }
103};
104
105} // namespace pixie::detail::compressed
A concrete CRTP implementation of StorageBase.
Definition storage.h:290
Common interface for byte-addressable storage.