You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

238 lines
4.3 KiB

1 year ago
  1. #pragma once
  2. #include <type_traits>
  3. #include <assert.h>
  4. #include <stdexcept>
  5. struct in_place_t
  6. {
  7. explicit in_place_t() = default;
  8. };
  9. template<typename BaseType> class optional
  10. {
  11. using Storage = typename std::aligned_storage<sizeof(BaseType), std::alignment_of<BaseType>::value>::type;
  12. Storage m_storage;
  13. bool m_valid = false;
  14. public:
  15. typedef optional<BaseType> self_type;
  16. optional() = default;
  17. ~optional()
  18. {
  19. reset();
  20. }
  21. optional(const optional& src) : m_valid(src.m_valid)
  22. {
  23. if (src.m_valid)
  24. {
  25. new(&m_storage) BaseType(*src);
  26. }
  27. }
  28. optional(optional&& src) : m_valid(src.m_valid)
  29. {
  30. if (src.m_valid)
  31. {
  32. new(&m_storage) BaseType(std::move(*src));
  33. }
  34. }
  35. template<typename U = BaseType, typename =
  36. typename std::enable_if<
  37. std::is_constructible<BaseType, U&&>::value &&
  38. !(std::is_same<typename std::decay<U>::type, self_type>::value)
  39. >::type
  40. >
  41. optional(U&& value) : m_valid(true)
  42. {
  43. new(&m_storage) BaseType(std::forward<U>(value));
  44. }
  45. template<typename... Args, typename = typename std::enable_if<std::is_constructible<BaseType, Args...>::value>::type>
  46. explicit optional(in_place_t tag, Args&&... args) : m_valid(true)
  47. {
  48. new(&m_storage) BaseType(std::forward<Args>(args)...);
  49. }
  50. optional& operator = (optional&& src) noexcept
  51. {
  52. if (src.m_valid)
  53. {
  54. if (m_valid)
  55. {
  56. **this = std::move(*src);
  57. }
  58. else
  59. {
  60. new(&m_storage) BaseType(std::move(*src));
  61. m_valid = true;
  62. }
  63. }
  64. else if (m_valid)
  65. {
  66. reinterpret_cast<BaseType*>(&m_storage)->~BaseType();
  67. m_valid = false;
  68. }
  69. return *this;
  70. }
  71. optional& operator = (const optional& src)
  72. {
  73. if (src.m_valid)
  74. {
  75. if (m_valid)
  76. {
  77. **this = *src;
  78. }
  79. else
  80. {
  81. new(&m_storage) BaseType(*src);
  82. m_valid = true;
  83. }
  84. }
  85. else if (m_valid)
  86. {
  87. reinterpret_cast<BaseType*>(&m_storage)->~BaseType();
  88. m_valid = false;
  89. }
  90. return *this;
  91. }
  92. template<typename U = BaseType, typename =
  93. typename std::enable_if<
  94. !std::is_same<typename std::decay<U>::type, self_type>::value &&
  95. std::is_constructible<BaseType, U>::value &&
  96. std::is_assignable<BaseType&, U>::value
  97. >::type>
  98. optional& operator = (U&& value)
  99. {
  100. if (m_valid)
  101. {
  102. **this = std::forward<U>(value);
  103. }
  104. else
  105. {
  106. new(&m_storage) BaseType(std::forward<U>(value));
  107. m_valid = true;
  108. }
  109. return *this;
  110. }
  111. void reset()
  112. {
  113. if (m_valid)
  114. {
  115. (**this).BaseType::~BaseType();
  116. m_valid = false;
  117. }
  118. }
  119. constexpr explicit operator bool() const
  120. {
  121. return m_valid;
  122. }
  123. constexpr bool has_value() const
  124. {
  125. return m_valid;
  126. }
  127. constexpr bool valid() const
  128. {
  129. return has_value();
  130. }
  131. BaseType& operator * () &
  132. {
  133. assert(m_valid);
  134. return *reinterpret_cast<BaseType*>(&m_storage);
  135. }
  136. const BaseType& operator * () const &
  137. {
  138. assert(m_valid);
  139. return *reinterpret_cast<const BaseType*>(&m_storage);
  140. }
  141. BaseType&& operator * () &&
  142. {
  143. assert(m_valid);
  144. return std::move(*reinterpret_cast<BaseType*>(&m_storage));
  145. }
  146. const BaseType&& operator * () const &&
  147. {
  148. assert(m_valid);
  149. return std::move(*reinterpret_cast<BaseType*>(&m_storage));
  150. }
  151. BaseType* operator -> ()
  152. {
  153. assert(m_valid);
  154. return reinterpret_cast<BaseType*>(&m_storage);
  155. }
  156. const BaseType* operator -> () const
  157. {
  158. assert(m_valid);
  159. return reinterpret_cast<const BaseType*>(&m_storage);
  160. }
  161. BaseType& value()
  162. {
  163. if (!has_value())
  164. {
  165. throw std::logic_error("bad_optional_access");
  166. }
  167. return **this;
  168. }
  169. const BaseType& value() const
  170. {
  171. if (!has_value())
  172. {
  173. throw std::logic_error("bad_optional_access");
  174. }
  175. return **this;
  176. }
  177. template<typename U> BaseType value_or(U&& default_value) &&
  178. {
  179. return has_value() ? std::move(**this) : static_cast<BaseType>(std::forward<U>(default_value));
  180. }
  181. template<typename U> const BaseType value_or(U&& default_value) const &
  182. {
  183. return has_value() ? **this : static_cast<BaseType>(std::forward<U>(default_value));
  184. }
  185. template<typename... Args> BaseType& emplace(Args&&... args)
  186. {
  187. reset();
  188. new(&m_storage) BaseType(std::forward<Args>(args)...);
  189. m_valid = true;
  190. return **this;
  191. }
  192. };
  193. template<typename T> optional<typename std::decay<T>::type> make_optional(T&& val)
  194. {
  195. return optional<typename std::decay<T>::type>(std::forward<T>(val));
  196. }
  197. template<typename T, typename... Args> optional<T> make_optional(Args&&... args)
  198. {
  199. return optional<T>(in_place_t{}, std::forward<Args>(args)...);
  200. }