13USERVER_NAMESPACE_BEGIN
17namespace any_storage::impl {
19using Offset = std::size_t;
21template <
typename StorageTag>
22inline Offset data_offset{0};
24template <
typename StorageTag>
25inline std::size_t count{0};
27template <
typename StorageTag>
28Offset RegisterData(std::size_t size, std::size_t alignment)
noexcept {
29 data_offset<StorageTag> +=
30 (alignment - (data_offset<StorageTag> % alignment)) % alignment;
31 Offset result = data_offset<StorageTag>;
32 data_offset<StorageTag> += size;
38void AssertStaticRegistrationAllowed();
41void Delete(std::byte* data)
noexcept {
42 reinterpret_cast<T*>(data)->~T();
47template <
typename StorageTag>
50template <
typename StorageTag,
typename Data>
51class AnyStorageDataTag final {
53 AnyStorageDataTag()
noexcept
54 : number_(any_storage::impl::count<StorageTag>),
55 offset_(any_storage::impl::RegisterData<StorageTag>(
sizeof(Data),
57 static_assert(!std::is_reference_v<Data>);
58 static_assert(!std::is_const_v<Data>);
59 static_assert(__STDCPP_DEFAULT_NEW_ALIGNMENT__ >=
alignof(Data),
60 "Overaligned data members are not supported by AnyStorage");
62 any_storage::impl::AssertStaticRegistrationAllowed();
66 const std::size_t number_;
67 const any_storage::impl::Offset offset_;
69 friend class AnyStorage<StorageTag>;
78template <
typename StorageTag>
79class AnyStorage final {
86 template <
typename Data>
87 const Data&
Get(
const AnyStorageDataTag<StorageTag, Data>& tag)
const;
91 template <
typename Data>
92 Data&
Get(
const AnyStorageDataTag<StorageTag, Data>& tag);
95 template <
typename Data>
96 Data&
Set(AnyStorageDataTag<StorageTag, Data> tag, Data data);
100 template <
typename Data,
typename... Args>
101 Data&
Emplace(
const AnyStorageDataTag<StorageTag, Data>& tag, Args&&... args);
105 template <
typename Data>
106 Data*
GetOptional(
const AnyStorageDataTag<StorageTag, Data>& tag)
noexcept;
110 template <
typename Data>
111 const Data*
GetOptional(
const AnyStorageDataTag<StorageTag, Data>& tag)
const
115 template <
typename Data>
116 void Erase(
const AnyStorageDataTag<StorageTag, Data>& tag);
119 std::unique_ptr<std::byte[]> raw_data_;
122 void (*deleter)(std::byte*)
noexcept;
126 AllocRecord* GetRecords()
noexcept;
129template <
typename StorageTag>
130AnyStorage<StorageTag>::AnyStorage()
131 : raw_data_(
new std::byte[any_storage::impl::data_offset<StorageTag> +
132 sizeof(AllocRecord) *
133 any_storage::impl::count<StorageTag>]) {
134 static_assert(std::is_trivial_v<AllocRecord>);
136 auto records = GetRecords();
137 for (std::size_t i = 0; i < any_storage::impl::count<StorageTag>; i++) {
138 auto& record = records[i];
139 record.deleter =
nullptr;
143template <
typename StorageTag>
144AnyStorage<StorageTag>::~AnyStorage() {
145 auto records = GetRecords();
146 for (std::size_t i = 0; i < any_storage::impl::count<StorageTag>; i++) {
147 auto& record = records[i];
148 if (record.deleter) record.deleter(&raw_data_[record.offset]);
152template <
typename StorageTag>
153template <
typename Data>
154Data& AnyStorage<StorageTag>::Set(
const AnyStorageDataTag<StorageTag, Data> tag,
156 auto number = tag.number_;
157 if (!GetRecords()[number].deleter)
return Emplace(tag, std::move(data));
159 auto offset = tag.offset_;
160 return *
reinterpret_cast<Data*>(&raw_data_[offset]) = std::move(data);
163template <
typename StorageTag>
164template <
typename Data,
typename... Args>
166 const AnyStorageDataTag<StorageTag, Data>& tag, Args&&... args) {
167 auto number = tag.number_;
168 auto& record = GetRecords()[number];
169 if (record.deleter) record.deleter(&raw_data_[tag.offset_]);
171 auto offset = tag.offset_;
172 auto ptr =
new (&raw_data_[offset]) Data(std::forward<Args>(args)...);
173 record = {&any_storage::impl::Delete<Data>, offset};
177template <
typename StorageTag>
178template <
typename Data>
179Data& AnyStorage<StorageTag>::
Get(
180 const AnyStorageDataTag<StorageTag, Data>& tag) {
181 auto ptr = GetOptional(tag);
182 if (ptr)
return *ptr;
183 throw std::runtime_error(
"No data");
186template <
typename StorageTag>
187template <
typename Data>
188const Data& AnyStorage<StorageTag>::
Get(
189 const AnyStorageDataTag<StorageTag, Data>& tag)
const {
191 return const_cast<AnyStorage<StorageTag>*>(
this)->Get<Data>(tag);
194template <
typename StorageTag>
195template <
typename Data>
197 const AnyStorageDataTag<StorageTag, Data>& tag)
noexcept {
198 auto number = tag.number_;
199 auto offset = tag.offset_;
200 if (!GetRecords()[number].deleter)
return nullptr;
201 return reinterpret_cast<Data*>(&raw_data_[offset]);
204template <
typename StorageTag>
205template <
typename Data>
207 const AnyStorageDataTag<StorageTag, Data>& tag)
const noexcept {
209 return const_cast<AnyStorage*>(
this)->GetOptional<Data>(tag);
212template <
typename StorageTag>
213typename AnyStorage<StorageTag>::AllocRecord*
214AnyStorage<StorageTag>::GetRecords()
noexcept {
215 return reinterpret_cast<AllocRecord*>(
216 &raw_data_[any_storage::impl::data_offset<StorageTag>]);