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>]);