maybe_traits.h 5.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185
  1. #pragma once
  2. #include <memory>
  3. #include <type_traits>
  4. #include <initializer_list>
  5. namespace NMaybe {
  6. struct TInPlace {};
  7. template <class T, bool = std::is_trivially_destructible<T>::value>
  8. struct TStorageBase {
  9. constexpr TStorageBase() noexcept
  10. : NullState_('\0')
  11. {
  12. }
  13. template <class... Args>
  14. constexpr TStorageBase(TInPlace, Args&&... args)
  15. : Data_(std::forward<Args>(args)...)
  16. , Defined_(true)
  17. {
  18. }
  19. constexpr TStorageBase(TStorageBase&&) = default;
  20. constexpr TStorageBase(const TStorageBase&) = default;
  21. ~TStorageBase() = default;
  22. TStorageBase& operator=(const TStorageBase&) = default;
  23. TStorageBase& operator=(TStorageBase&&) = default;
  24. union {
  25. char NullState_;
  26. T Data_;
  27. };
  28. bool Defined_ = false;
  29. };
  30. template <class T>
  31. struct TStorageBase<T, false> {
  32. constexpr TStorageBase() noexcept
  33. : NullState_('\0')
  34. {
  35. }
  36. template <class... Args>
  37. constexpr TStorageBase(TInPlace, Args&&... args)
  38. : Data_(std::forward<Args>(args)...)
  39. , Defined_(true)
  40. {
  41. }
  42. constexpr TStorageBase(TStorageBase&&) = default;
  43. constexpr TStorageBase(const TStorageBase&) = default;
  44. ~TStorageBase() {
  45. if (this->Defined_) {
  46. this->Data_.~T();
  47. }
  48. }
  49. TStorageBase& operator=(const TStorageBase&) = default;
  50. TStorageBase& operator=(TStorageBase&&) = default;
  51. union {
  52. char NullState_;
  53. T Data_;
  54. };
  55. bool Defined_ = false;
  56. };
  57. // -------------------- COPY CONSTRUCT --------------------
  58. template <class T, bool = std::is_trivially_copy_constructible<T>::value>
  59. struct TCopyBase: TStorageBase<T> {
  60. using TStorageBase<T>::TStorageBase;
  61. };
  62. template <class T>
  63. struct TCopyBase<T, false>: TStorageBase<T> {
  64. using TStorageBase<T>::TStorageBase;
  65. constexpr TCopyBase() = default;
  66. constexpr TCopyBase(const TCopyBase& rhs) {
  67. if (rhs.Defined_) {
  68. new (std::addressof(this->Data_)) T(rhs.Data_);
  69. this->Defined_ = true;
  70. }
  71. }
  72. constexpr TCopyBase(TCopyBase&&) = default;
  73. TCopyBase& operator=(const TCopyBase&) = default;
  74. TCopyBase& operator=(TCopyBase&&) = default;
  75. };
  76. // -------------------- MOVE CONSTRUCT --------------------
  77. template <class T, bool = std::is_trivially_move_constructible<T>::value>
  78. struct TMoveBase: TCopyBase<T> {
  79. using TCopyBase<T>::TCopyBase;
  80. };
  81. template <class T>
  82. struct TMoveBase<T, false>: TCopyBase<T> {
  83. using TCopyBase<T>::TCopyBase;
  84. constexpr TMoveBase() noexcept = default;
  85. constexpr TMoveBase(const TMoveBase&) = default;
  86. constexpr TMoveBase(TMoveBase&& rhs) noexcept(std::is_nothrow_move_constructible<T>::value) {
  87. if (rhs.Defined_) {
  88. new (std::addressof(this->Data_)) T(std::move(rhs.Data_));
  89. this->Defined_ = true;
  90. }
  91. }
  92. TMoveBase& operator=(const TMoveBase&) = default;
  93. TMoveBase& operator=(TMoveBase&&) = default;
  94. };
  95. // -------------------- COPY ASSIGN --------------------
  96. template <class T, bool = std::is_trivially_copy_assignable<T>::value>
  97. struct TCopyAssignBase: TMoveBase<T> {
  98. using TMoveBase<T>::TMoveBase;
  99. };
  100. template <class T>
  101. struct TCopyAssignBase<T, false>: TMoveBase<T> {
  102. using TMoveBase<T>::TMoveBase;
  103. constexpr TCopyAssignBase() noexcept = default;
  104. constexpr TCopyAssignBase(const TCopyAssignBase&) = default;
  105. constexpr TCopyAssignBase(TCopyAssignBase&&) = default;
  106. TCopyAssignBase& operator=(const TCopyAssignBase& rhs) {
  107. if (this->Defined_) {
  108. if (rhs.Defined_) {
  109. this->Data_ = rhs.Data_;
  110. } else {
  111. this->Data_.~T();
  112. this->Defined_ = false;
  113. }
  114. } else if (rhs.Defined_) {
  115. new (std::addressof(this->Data_)) T(rhs.Data_);
  116. this->Defined_ = true;
  117. }
  118. return *this;
  119. }
  120. TCopyAssignBase& operator=(TCopyAssignBase&&) = default;
  121. };
  122. // -------------------- MOVE ASSIGN --------------------
  123. template <class T, bool = std::is_trivially_move_assignable<T>::value>
  124. struct TMoveAssignBase: TCopyAssignBase<T> {
  125. using TCopyAssignBase<T>::TCopyAssignBase;
  126. };
  127. template <class T>
  128. struct TMoveAssignBase<T, false>: TCopyAssignBase<T> {
  129. using TCopyAssignBase<T>::TCopyAssignBase;
  130. constexpr TMoveAssignBase() noexcept = default;
  131. constexpr TMoveAssignBase(const TMoveAssignBase&) = default;
  132. constexpr TMoveAssignBase(TMoveAssignBase&&) = default;
  133. TMoveAssignBase& operator=(const TMoveAssignBase&) = default;
  134. TMoveAssignBase& operator=(TMoveAssignBase&& rhs) noexcept(
  135. std::is_nothrow_move_assignable<T>::value &&
  136. std::is_nothrow_move_constructible<T>::value)
  137. {
  138. if (this->Defined_) {
  139. if (rhs.Defined_) {
  140. this->Data_ = std::move(rhs.Data_);
  141. } else {
  142. this->Data_.~T();
  143. this->Defined_ = false;
  144. }
  145. } else if (rhs.Defined_) {
  146. new (std::addressof(this->Data_)) T(std::move(rhs.Data_));
  147. this->Defined_ = true;
  148. }
  149. return *this;
  150. }
  151. };
  152. } // namespace NMaybe
  153. template <class T>
  154. using TMaybeBase = NMaybe::TMoveAssignBase<T>;