aboutsummaryrefslogtreecommitdiffstats
path: root/util/generic/singleton.h
diff options
context:
space:
mode:
authorDevtools Arcadia <arcadia-devtools@yandex-team.ru>2022-02-07 18:08:42 +0300
committerDevtools Arcadia <arcadia-devtools@mous.vla.yp-c.yandex.net>2022-02-07 18:08:42 +0300
commit1110808a9d39d4b808aef724c861a2e1a38d2a69 (patch)
treee26c9fed0de5d9873cce7e00bc214573dc2195b7 /util/generic/singleton.h
downloadydb-1110808a9d39d4b808aef724c861a2e1a38d2a69.tar.gz
intermediate changes
ref:cde9a383711a11544ce7e107a78147fb96cc4029
Diffstat (limited to 'util/generic/singleton.h')
-rw-r--r--util/generic/singleton.h136
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());
+}