diff options
author | Devtools Arcadia <arcadia-devtools@yandex-team.ru> | 2022-02-07 18:08:42 +0300 |
---|---|---|
committer | Devtools Arcadia <arcadia-devtools@mous.vla.yp-c.yandex.net> | 2022-02-07 18:08:42 +0300 |
commit | 1110808a9d39d4b808aef724c861a2e1a38d2a69 (patch) | |
tree | e26c9fed0de5d9873cce7e00bc214573dc2195b7 /util/generic/singleton.h | |
download | ydb-1110808a9d39d4b808aef724c861a2e1a38d2a69.tar.gz |
intermediate changes
ref:cde9a383711a11544ce7e107a78147fb96cc4029
Diffstat (limited to 'util/generic/singleton.h')
-rw-r--r-- | util/generic/singleton.h | 136 |
1 files changed, 136 insertions, 0 deletions
diff --git a/util/generic/singleton.h b/util/generic/singleton.h new file mode 100644 index 0000000000..f5fa047f5c --- /dev/null +++ b/util/generic/singleton.h @@ -0,0 +1,136 @@ +#pragma once + +#include <util/system/atexit.h> +#include <util/system/atomic.h> + +#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(TAtomic& lock) noexcept; + void UnlockRecursive(TAtomic& 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(T*& ptr, TArgs&&... args) { + alignas(T) static char buf[sizeof(T)]; + static TAtomic lock; + + LockRecursive(lock); + + auto ret = AtomicGet(ptr); + + try { + if (!ret) { + ret = ::new (buf) T(std::forward<TArgs>(args)...); + + try { + AtExit(Destroyer<T>, ret, P); + } catch (...) { + Destroyer<T>(ret); + + throw; + } + + AtomicSet(ptr, 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 T* ptr; + auto ret = AtomicGet(ptr); + + 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(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()); +} |