#pragma once #include #include #include #include #include template struct TSingletonTraits { static constexpr size_t Priority = 65536; }; namespace NPrivate { void FillWithTrash(void* ptr, size_t len); void LockRecursive(std::atomic& lock) noexcept; void UnlockRecursive(std::atomic& lock) noexcept; template void Destroyer(void* ptr) { ((T*)ptr)->~T(); FillWithTrash(ptr, sizeof(T)); } template Y_NO_INLINE T* SingletonBase(std::atomic& ptr, TArgs&&... args) { alignas(T) static char buf[sizeof(T)]; static std::atomic lock; LockRecursive(lock); auto ret = ptr.load(); try { if (!ret) { ret = ::new (buf) T(std::forward(args)...); try { AtExit(Destroyer, ret, P); } catch (...) { Destroyer(ret); throw; } ptr.store(ret); } } catch (...) { UnlockRecursive(lock); throw; } UnlockRecursive(lock); return ret; } template T* SingletonInt(TArgs&&... args) { static_assert(sizeof(T) < 32000, "use HugeSingleton instead"); static std::atomic ptr; auto ret = ptr.load(); if (Y_UNLIKELY(!ret)) { ret = SingletonBase(ptr, std::forward(args)...); } return ret; } template class TDefault { public: template inline TDefault(TArgs&&... args) : T_(std::forward(args)...) { } inline const T* Get() const noexcept { return &T_; } private: T T_; }; template struct THeapStore { template inline THeapStore(TArgs&&... args) : D(new T(std::forward(args)...)) { } inline ~THeapStore() { delete D; } T* D; }; } // namespace NPrivate #define Y_DECLARE_SINGLETON_FRIEND() \ template \ friend T* ::NPrivate::SingletonInt(TArgs&&...); \ template \ friend T* ::NPrivate::SingletonBase(std::atomic&, TArgs&&...); template Y_RETURNS_NONNULL T* Singleton(TArgs&&... args) { return ::NPrivate::SingletonInt::Priority>(std::forward(args)...); } template Y_RETURNS_NONNULL T* HugeSingleton(TArgs&&... args) { return Singleton<::NPrivate::THeapStore>(std::forward(args)...)->D; } template Y_RETURNS_NONNULL T* SingletonWithPriority(TArgs&&... args) { return ::NPrivate::SingletonInt(std::forward(args)...); } template Y_RETURNS_NONNULL T* HugeSingletonWithPriority(TArgs&&... args) { return SingletonWithPriority<::NPrivate::THeapStore, P>(std::forward(args)...)->D; } template const T& Default() { return *(::NPrivate::SingletonInt, TSingletonTraits::Priority>()->Get()); }