123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136 |
- #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());
- }
|