maybe_traits.h 5.2 KB

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