singleton.h 3.3 KB

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