#pragma once #include #include #include #include namespace NThreading { class IGenericLocalStorage { public: struct TTraits { size_t Size = 0; std::function Constructor; std::function Destructor; }; struct TData : TNonCopyable { TVector Memory; std::function Destructor; public: ~TData() { if (Destructor) { Destructor(&Memory[0]); } } }; public: virtual ~IGenericLocalStorage() {}; void* GetMemory(const TTraits& traits) const { TData* data = GetData(); if (!data->Destructor) { data->Destructor = traits.Destructor; data->Memory.resize(traits.Size); traits.Constructor(&data->Memory[0]); } return &data->Memory[0]; } private: virtual TData* GetData() const = 0; }; using TGenericLocalStorageFactory = std::function()>; void SetGenericLocalStorageFactory(TGenericLocalStorageFactory factory); THolder MakeGenericLocalStorage(); template class TGenericLocalValue { private: static const auto& Traits() { const static IGenericLocalStorage::TTraits traits = { .Size = sizeof(T), .Constructor = [](void* addr) { new (addr) T(); }, .Destructor = [](void* addr) { static_cast(addr)->~T(); } }; return traits; }; public: T* Get() const { std::call_once(InitOnce_, [this]() { Storage_ = MakeGenericLocalStorage(); }); return static_cast(Storage_->GetMemory(Traits())); } T& GetRef() const { return *Get(); } private: mutable std::once_flag InitOnce_; mutable THolder Storage_; }; }