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> += (alignment - (data_offset<StorageTag> % alignment)) % alignment;
30 Offset result = data_offset<StorageTag>;
31 data_offset<StorageTag> += size;
37void AssertStaticRegistrationAllowed();
40void Delete(std::byte* data)
noexcept {
41 reinterpret_cast<T*>(data)->~T();
46template <
typename StorageTag>
49template <
typename StorageTag,
typename Data>
50class AnyStorageDataTag final {
52 AnyStorageDataTag()
noexcept
53 : number_(any_storage::impl::count<StorageTag>),
54 offset_(any_storage::impl::RegisterData<StorageTag>(
sizeof(Data),
alignof(Data))) {
55 static_assert(!std::is_reference_v<Data>);
56 static_assert(!std::is_const_v<Data>);
58 __STDCPP_DEFAULT_NEW_ALIGNMENT__ >=
alignof(Data),
59 "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>;
50class AnyStorageDataTag final {
…};
78template <
typename StorageTag>
79class AnyStorage final {
83 AnyStorage(AnyStorage&& other)
noexcept =
default;
84 AnyStorage& operator=(AnyStorage&& other)
noexcept;
88 template <
typename Data>
89 const Data&
Get(
const AnyStorageDataTag<StorageTag, Data>& tag)
const;
93 template <
typename Data>
94 Data&
Get(
const AnyStorageDataTag<StorageTag, Data>& tag);
97 template <
typename Data>
98 Data&
Set(AnyStorageDataTag<StorageTag, Data> tag, Data data);
102 template <
typename Data,
typename... Args>
103 Data&
Emplace(
const AnyStorageDataTag<StorageTag, Data>& tag, Args&&... args);
107 template <
typename Data>
108 Data*
GetOptional(
const AnyStorageDataTag<StorageTag, Data>& tag)
noexcept;
112 template <
typename Data>
113 const Data*
GetOptional(
const AnyStorageDataTag<StorageTag, Data>& tag)
const noexcept;
116 template <
typename Data>
117 void Erase(
const AnyStorageDataTag<StorageTag, Data>& tag);
121 void (*deleter)(std::byte*)
noexcept;
125 AllocRecord* GetRecords()
noexcept;
127 static any_storage::impl::Offset CalcOffset()
noexcept;
129 void Destroy()
noexcept;
131 std::unique_ptr<std::byte[]> raw_data_;
79class AnyStorage final {
…};
134template <
typename StorageTag>
135any_storage::impl::Offset AnyStorage<StorageTag>::CalcOffset()
noexcept {
136 const auto offset = any_storage::impl::data_offset<StorageTag>;
137 return ((offset +
alignof(AllocRecord) - 1) /
alignof(AllocRecord)) *
alignof(AllocRecord);
140template <
typename StorageTag>
141AnyStorage<StorageTag>::AnyStorage()
142 : raw_data_(
new std::byte[CalcOffset() +
sizeof(AllocRecord) * any_storage::impl::count<StorageTag>]) {
143 static_assert(std::is_trivial_v<AllocRecord>);
146 auto records = GetRecords();
147 for (std::size_t i = 0; i < any_storage::impl::count<StorageTag>; i++) {
148 auto& record = records[i];
149 record.deleter =
nullptr;
153template <
typename StorageTag>
154AnyStorage<StorageTag>& AnyStorage<StorageTag>::operator=(AnyStorage&& other)
noexcept {
155 if (
this != &other) {
157 raw_data_ = std::move(other.raw_data_);
162template <
typename StorageTag>
163AnyStorage<StorageTag>::~AnyStorage() {
167template <
typename StorageTag>
168void AnyStorage<StorageTag>::Destroy()
noexcept {
169 auto records = GetRecords();
170 for (std::size_t i = 0; i < any_storage::impl::count<StorageTag>; i++) {
171 auto& record = records[i];
172 if (record.deleter) record.deleter(&raw_data_[record.offset]);
177template <
typename Data>
178Data& AnyStorage<StorageTag>::
Set(
const AnyStorageDataTag<StorageTag, Data> tag, Data data) {
179 auto number = tag.number_;
180 if (!GetRecords()[number].deleter)
return Emplace(tag, std::move(data));
182 auto offset = tag.offset_;
183 return *
reinterpret_cast<Data*>(&raw_data_[offset]) = std::move(data);
178Data& AnyStorage<StorageTag>::
Set(
const AnyStorageDataTag<StorageTag, Data> tag, Data data) {
…}
187template <
typename Data,
typename... Args>
188Data& AnyStorage<StorageTag>::
Emplace(
const AnyStorageDataTag<StorageTag, Data>& tag, Args&&... args) {
189 auto number = tag.number_;
190 auto& record = GetRecords()[number];
191 if (record.deleter) record.deleter(&raw_data_[tag.offset_]);
193 auto offset = tag.offset_;
194 auto ptr =
new (&raw_data_[offset]) Data(std::forward<Args>(args)...);
195 record = {&any_storage::impl::Delete<Data>, offset};
188Data& AnyStorage<StorageTag>::
Emplace(
const AnyStorageDataTag<StorageTag, Data>& tag, Args&&... args) {
…}
200template <
typename Data>
201Data& AnyStorage<StorageTag>::
Get(
const AnyStorageDataTag<StorageTag, Data>& tag) {
202 auto ptr = GetOptional(tag);
203 if (ptr)
return *ptr;
204 throw std::runtime_error(
"No data");
201Data& AnyStorage<StorageTag>::
Get(
const AnyStorageDataTag<StorageTag, Data>& tag) {
…}
208template <
typename Data>
209const Data& AnyStorage<StorageTag>::
Get(
const AnyStorageDataTag<StorageTag, Data>& tag)
const {
211 return const_cast<AnyStorage<StorageTag>*>(
this)->Get<Data>(tag);
209const Data& AnyStorage<StorageTag>::
Get(
const AnyStorageDataTag<StorageTag, Data>& tag)
const {
…}
215template <
typename Data>
216Data* AnyStorage<StorageTag>::
GetOptional(
const AnyStorageDataTag<StorageTag, Data>& tag)
noexcept {
217 auto number = tag.number_;
218 auto offset = tag.offset_;
219 if (!GetRecords()[number].deleter)
return nullptr;
220 return reinterpret_cast<Data*>(&raw_data_[offset]);
216Data* AnyStorage<StorageTag>::
GetOptional(
const AnyStorageDataTag<StorageTag, Data>& tag)
noexcept {
…}
224template <
typename Data>
225const Data* AnyStorage<StorageTag>::
GetOptional(
const AnyStorageDataTag<StorageTag, Data>& tag)
const noexcept {
227 return const_cast<AnyStorage*>(
this)->GetOptional<Data>(tag);
225const Data* AnyStorage<StorageTag>::
GetOptional(
const AnyStorageDataTag<StorageTag, Data>& tag)
const noexcept {
…}
230template <
typename StorageTag>
231typename AnyStorage<StorageTag>::AllocRecord* AnyStorage<StorageTag>::GetRecords()
noexcept {
232 return reinterpret_cast<AllocRecord*>(&raw_data_[CalcOffset()]);