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