singleton.h 3.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137
  1. #pragma once
  2. #include <util/system/atexit.h>
  3. #include <util/system/compiler.h>
  4. #include <atomic>
  5. #include <new>
  6. #include <utility>
  7. template <class T>
  8. struct TSingletonTraits {
  9. static constexpr size_t Priority = 65536;
  10. };
  11. namespace NPrivate {
  12. void FillWithTrash(void* ptr, size_t len);
  13. void LockRecursive(std::atomic<size_t>& lock) noexcept;
  14. void UnlockRecursive(std::atomic<size_t>& lock) noexcept;
  15. template <class T>
  16. void Destroyer(void* ptr) {
  17. ((T*)ptr)->~T();
  18. FillWithTrash(ptr, sizeof(T));
  19. }
  20. template <class T, size_t P, class... TArgs>
  21. Y_NO_INLINE T* SingletonBase(std::atomic<T*>& ptr, TArgs&&... args) {
  22. alignas(T) static char buf[sizeof(T)];
  23. static std::atomic<size_t> lock;
  24. LockRecursive(lock);
  25. auto ret = ptr.load();
  26. try {
  27. if (!ret) {
  28. ret = ::new (buf) T(std::forward<TArgs>(args)...);
  29. try {
  30. AtExit(Destroyer<T>, ret, P);
  31. } catch (...) {
  32. Destroyer<T>(ret);
  33. throw;
  34. }
  35. ptr.store(ret);
  36. }
  37. } catch (...) {
  38. UnlockRecursive(lock);
  39. throw;
  40. }
  41. UnlockRecursive(lock);
  42. return ret;
  43. }
  44. template <class T, size_t P, class... TArgs>
  45. T* SingletonInt(TArgs&&... args) {
  46. static_assert(sizeof(T) < 32000, "use HugeSingleton instead");
  47. static std::atomic<T*> ptr;
  48. auto ret = ptr.load();
  49. if (Y_UNLIKELY(!ret)) {
  50. ret = SingletonBase<T, P>(ptr, std::forward<TArgs>(args)...);
  51. }
  52. return ret;
  53. }
  54. template <class T>
  55. class TDefault {
  56. public:
  57. template <class... TArgs>
  58. inline TDefault(TArgs&&... args)
  59. : T_(std::forward<TArgs>(args)...)
  60. {
  61. }
  62. inline const T* Get() const noexcept {
  63. return &T_;
  64. }
  65. private:
  66. T T_;
  67. };
  68. template <class T>
  69. struct THeapStore {
  70. template <class... TArgs>
  71. inline THeapStore(TArgs&&... args)
  72. : D(new T(std::forward<TArgs>(args)...))
  73. {
  74. }
  75. inline ~THeapStore() {
  76. delete D;
  77. }
  78. T* D;
  79. };
  80. } // namespace NPrivate
  81. #define Y_DECLARE_SINGLETON_FRIEND() \
  82. template <class T, size_t P, class... TArgs> \
  83. friend T* ::NPrivate::SingletonInt(TArgs&&...); \
  84. template <class T, size_t P, class... TArgs> \
  85. friend T* ::NPrivate::SingletonBase(std::atomic<T*>&, TArgs&&...);
  86. template <class T, class... TArgs>
  87. Y_RETURNS_NONNULL T* Singleton(TArgs&&... args) {
  88. return ::NPrivate::SingletonInt<T, TSingletonTraits<T>::Priority>(std::forward<TArgs>(args)...);
  89. }
  90. template <class T, class... TArgs>
  91. Y_RETURNS_NONNULL T* HugeSingleton(TArgs&&... args) {
  92. return Singleton<::NPrivate::THeapStore<T>>(std::forward<TArgs>(args)...)->D;
  93. }
  94. template <class T, size_t P, class... TArgs>
  95. Y_RETURNS_NONNULL T* SingletonWithPriority(TArgs&&... args) {
  96. return ::NPrivate::SingletonInt<T, P>(std::forward<TArgs>(args)...);
  97. }
  98. template <class T, size_t P, class... TArgs>
  99. Y_RETURNS_NONNULL T* HugeSingletonWithPriority(TArgs&&... args) {
  100. return SingletonWithPriority<::NPrivate::THeapStore<T>, P>(std::forward<TArgs>(args)...)->D;
  101. }
  102. template <class T>
  103. const T& Default() {
  104. return *(::NPrivate::SingletonInt<typename ::NPrivate::TDefault<T>, TSingletonTraits<T>::Priority>()->Get());
  105. }