28 static_assert(std::is_trivially_copyable_v<T>);
31 MetadataArray() =
default;
33 explicit MetadataArray(std::size_t count)
36 std::ranges::fill(allocate(count), std::byte{0});
39 explicit MetadataArray(std::span<const T> values)
42 auto bytes = allocate(values.size());
43 if (!values.empty()) {
44 std::memcpy(bytes.data(), values.data(), values.size_bytes());
48 const T* data()
const {
49 return reinterpret_cast<const T*
>(storage_.as_bytes().data());
55 return reinterpret_cast<T*
>(storage_.writable_bytes().data());
58 const T& operator[](std::size_t index)
const {
return data()[index]; }
60 T& operator[](std::size_t index)
66 std::size_t size()
const {
return storage_.size_bytes() /
sizeof(T); }
68 bool empty()
const {
return size() == 0; }
70 std::size_t allocated_bytes()
const
71 requires requires(
const Storage& storage) { storage.allocated_bytes(); }
73 return storage_.allocated_bytes();
79 std::span<std::byte> allocate(std::size_t count)
82 if (count > std::numeric_limits<std::size_t>::max() / (
sizeof(T) * 8)) {
83 throw std::length_error(
"Compressed metadata allocation too large");
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)) !=
98 throw std::invalid_argument(
99 "Compressed metadata storage must be contiguous and word aligned");