value_storage.hpp 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365
  1. /* Essentially an internal optional implementation :)
  2. (C) 2017-2019 Niall Douglas <http://www.nedproductions.biz/> (59 commits)
  3. File Created: June 2017
  4. Boost Software License - Version 1.0 - August 17th, 2003
  5. Permission is hereby granted, free of charge, to any person or organization
  6. obtaining a copy of the software and accompanying documentation covered by
  7. this license (the "Software") to use, reproduce, display, distribute,
  8. execute, and transmit the Software, and to prepare derivative works of the
  9. Software, and to permit third-parties to whom the Software is furnished to
  10. do so, all subject to the following:
  11. The copyright notices in the Software and this entire statement, including
  12. the above license grant, this restriction and the following disclaimer,
  13. must be included in all copies of the Software, in whole or in part, and
  14. all derivative works of the Software, unless such copies or derivative
  15. works are solely in the form of machine-executable object code generated by
  16. a source language processor.
  17. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  18. IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  19. FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
  20. SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
  21. FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
  22. ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
  23. DEALINGS IN THE SOFTWARE.
  24. */
  25. #ifndef BOOST_OUTCOME_VALUE_STORAGE_HPP
  26. #define BOOST_OUTCOME_VALUE_STORAGE_HPP
  27. #include "../config.hpp"
  28. BOOST_OUTCOME_V2_NAMESPACE_BEGIN
  29. namespace detail
  30. {
  31. using status_bitfield_type = uint32_t;
  32. // WARNING: These bits are not tracked by abi-dumper, but changing them will break ABI!
  33. static constexpr status_bitfield_type status_have_value = (1U << 0U);
  34. static constexpr status_bitfield_type status_have_error = (1U << 1U);
  35. static constexpr status_bitfield_type status_have_exception = (1U << 2U);
  36. static constexpr status_bitfield_type status_error_is_errno = (1U << 4U); // can errno be set from this error?
  37. // bit 7 unused
  38. // bits 8-15 unused
  39. // bits 16-31 used for user supplied 16 bit value
  40. static constexpr status_bitfield_type status_2byte_shift = 16;
  41. static constexpr status_bitfield_type status_2byte_mask = (0xffffU << status_2byte_shift);
  42. // Used if T is trivial
  43. template <class T> struct value_storage_trivial
  44. {
  45. using value_type = T;
  46. union {
  47. empty_type _empty;
  48. devoid<T> _value;
  49. };
  50. status_bitfield_type _status{0};
  51. constexpr value_storage_trivial() noexcept : _empty{} {}
  52. // Special from-void catchall constructor, always constructs default T irrespective of whether void is valued or not (can do no better if T cannot be copied)
  53. struct disable_void_catchall
  54. {
  55. };
  56. using void_value_storage_trivial = std::conditional_t<std::is_void<T>::value, disable_void_catchall, value_storage_trivial<void>>;
  57. explicit constexpr value_storage_trivial(const void_value_storage_trivial &o) noexcept(std::is_nothrow_default_constructible<value_type>::value)
  58. : _value()
  59. , _status(o._status)
  60. {
  61. }
  62. value_storage_trivial(const value_storage_trivial &) = default; // NOLINT
  63. value_storage_trivial(value_storage_trivial &&) = default; // NOLINT
  64. value_storage_trivial &operator=(const value_storage_trivial &) = default; // NOLINT
  65. value_storage_trivial &operator=(value_storage_trivial &&) = default; // NOLINT
  66. ~value_storage_trivial() = default;
  67. constexpr explicit value_storage_trivial(status_bitfield_type status)
  68. : _empty()
  69. , _status(status)
  70. {
  71. }
  72. template <class... Args>
  73. constexpr explicit value_storage_trivial(in_place_type_t<value_type> /*unused*/, Args &&... args) noexcept(std::is_nothrow_constructible<value_type, Args...>::value)
  74. : _value(static_cast<Args &&>(args)...)
  75. , _status(status_have_value)
  76. {
  77. }
  78. template <class U, class... Args>
  79. constexpr value_storage_trivial(in_place_type_t<value_type> /*unused*/, std::initializer_list<U> il, Args &&... args) noexcept(std::is_nothrow_constructible<value_type, std::initializer_list<U>, Args...>::value)
  80. : _value(il, static_cast<Args &&>(args)...)
  81. , _status(status_have_value)
  82. {
  83. }
  84. template <class U> static constexpr bool enable_converting_constructor = !std::is_same<std::decay_t<U>, value_type>::value && std::is_constructible<value_type, U>::value;
  85. BOOST_OUTCOME_TEMPLATE(class U)
  86. BOOST_OUTCOME_TREQUIRES(BOOST_OUTCOME_TPRED(enable_converting_constructor<U>))
  87. constexpr explicit value_storage_trivial(const value_storage_trivial<U> &o) noexcept(std::is_nothrow_constructible<value_type, U>::value)
  88. : value_storage_trivial(((o._status & status_have_value) != 0) ? value_storage_trivial(in_place_type<value_type>, o._value) : value_storage_trivial()) // NOLINT
  89. {
  90. _status = o._status;
  91. }
  92. BOOST_OUTCOME_TEMPLATE(class U)
  93. BOOST_OUTCOME_TREQUIRES(BOOST_OUTCOME_TPRED(enable_converting_constructor<U>))
  94. constexpr explicit value_storage_trivial(value_storage_trivial<U> &&o) noexcept(std::is_nothrow_constructible<value_type, U>::value)
  95. : value_storage_trivial(((o._status & status_have_value) != 0) ? value_storage_trivial(in_place_type<value_type>, static_cast<U &&>(o._value)) : value_storage_trivial()) // NOLINT
  96. {
  97. _status = o._status;
  98. }
  99. constexpr void swap(value_storage_trivial &o) noexcept
  100. {
  101. // storage is trivial, so just use assignment
  102. auto temp = static_cast<value_storage_trivial &&>(*this);
  103. *this = static_cast<value_storage_trivial &&>(o);
  104. o = static_cast<value_storage_trivial &&>(temp);
  105. }
  106. };
  107. // Used if T is non-trivial
  108. template <class T> struct value_storage_nontrivial
  109. {
  110. using value_type = T;
  111. union {
  112. empty_type _empty;
  113. value_type _value;
  114. };
  115. status_bitfield_type _status{0};
  116. value_storage_nontrivial() noexcept : _empty{} {}
  117. value_storage_nontrivial &operator=(const value_storage_nontrivial &) = default; // if reaches here, copy assignment is trivial
  118. value_storage_nontrivial &operator=(value_storage_nontrivial &&) = default; // NOLINT if reaches here, move assignment is trivial
  119. value_storage_nontrivial(value_storage_nontrivial &&o) noexcept(std::is_nothrow_move_constructible<value_type>::value) // NOLINT
  120. : _status(o._status)
  121. {
  122. if(this->_status & status_have_value)
  123. {
  124. this->_status &= ~status_have_value;
  125. new(&_value) value_type(static_cast<value_type &&>(o._value)); // NOLINT
  126. _status = o._status;
  127. }
  128. }
  129. value_storage_nontrivial(const value_storage_nontrivial &o) noexcept(std::is_nothrow_copy_constructible<value_type>::value)
  130. : _status(o._status)
  131. {
  132. if(this->_status & status_have_value)
  133. {
  134. this->_status &= ~status_have_value;
  135. new(&_value) value_type(o._value); // NOLINT
  136. _status = o._status;
  137. }
  138. }
  139. // Special from-void constructor, constructs default T if void valued
  140. explicit value_storage_nontrivial(const value_storage_trivial<void> &o) noexcept(std::is_nothrow_default_constructible<value_type>::value)
  141. : _status(o._status)
  142. {
  143. if(this->_status & status_have_value)
  144. {
  145. this->_status &= ~status_have_value;
  146. new(&_value) value_type; // NOLINT
  147. _status = o._status;
  148. }
  149. }
  150. explicit value_storage_nontrivial(status_bitfield_type status)
  151. : _empty()
  152. , _status(status)
  153. {
  154. }
  155. template <class... Args>
  156. explicit value_storage_nontrivial(in_place_type_t<value_type> /*unused*/, Args &&... args) noexcept(std::is_nothrow_constructible<value_type, Args...>::value)
  157. : _value(static_cast<Args &&>(args)...) // NOLINT
  158. , _status(status_have_value)
  159. {
  160. }
  161. template <class U, class... Args>
  162. value_storage_nontrivial(in_place_type_t<value_type> /*unused*/, std::initializer_list<U> il, Args &&... args) noexcept(std::is_nothrow_constructible<value_type, std::initializer_list<U>, Args...>::value)
  163. : _value(il, static_cast<Args &&>(args)...)
  164. , _status(status_have_value)
  165. {
  166. }
  167. template <class U> static constexpr bool enable_converting_constructor = !std::is_same<std::decay_t<U>, value_type>::value && std::is_constructible<value_type, U>::value;
  168. BOOST_OUTCOME_TEMPLATE(class U)
  169. BOOST_OUTCOME_TREQUIRES(BOOST_OUTCOME_TPRED(enable_converting_constructor<U>))
  170. constexpr explicit value_storage_nontrivial(const value_storage_nontrivial<U> &o) noexcept(std::is_nothrow_constructible<value_type, U>::value)
  171. : value_storage_nontrivial((o._status & status_have_value) != 0 ? value_storage_nontrivial(in_place_type<value_type>, o._value) : value_storage_nontrivial())
  172. {
  173. _status = o._status;
  174. }
  175. BOOST_OUTCOME_TEMPLATE(class U)
  176. BOOST_OUTCOME_TREQUIRES(BOOST_OUTCOME_TPRED(enable_converting_constructor<U>))
  177. constexpr explicit value_storage_nontrivial(const value_storage_trivial<U> &o) noexcept(std::is_nothrow_constructible<value_type, U>::value)
  178. : value_storage_nontrivial((o._status & status_have_value) != 0 ? value_storage_nontrivial(in_place_type<value_type>, o._value) : value_storage_nontrivial())
  179. {
  180. _status = o._status;
  181. }
  182. BOOST_OUTCOME_TEMPLATE(class U)
  183. BOOST_OUTCOME_TREQUIRES(BOOST_OUTCOME_TPRED(enable_converting_constructor<U>))
  184. constexpr explicit value_storage_nontrivial(value_storage_nontrivial<U> &&o) noexcept(std::is_nothrow_constructible<value_type, U>::value)
  185. : value_storage_nontrivial((o._status & status_have_value) != 0 ? value_storage_nontrivial(in_place_type<value_type>, static_cast<U &&>(o._value)) : value_storage_nontrivial())
  186. {
  187. _status = o._status;
  188. }
  189. BOOST_OUTCOME_TEMPLATE(class U)
  190. BOOST_OUTCOME_TREQUIRES(BOOST_OUTCOME_TPRED(enable_converting_constructor<U>))
  191. constexpr explicit value_storage_nontrivial(value_storage_trivial<U> &&o) noexcept(std::is_nothrow_constructible<value_type, U>::value)
  192. : value_storage_nontrivial((o._status & status_have_value) != 0 ? value_storage_nontrivial(in_place_type<value_type>, static_cast<U &&>(o._value)) : value_storage_nontrivial())
  193. {
  194. _status = o._status;
  195. }
  196. ~value_storage_nontrivial() noexcept(std::is_nothrow_destructible<T>::value)
  197. {
  198. if(this->_status & status_have_value)
  199. {
  200. this->_value.~value_type(); // NOLINT
  201. this->_status &= ~status_have_value;
  202. }
  203. }
  204. constexpr void swap(value_storage_nontrivial &o) noexcept(detail::is_nothrow_swappable<value_type>::value &&std::is_nothrow_move_constructible<value_type>::value)
  205. {
  206. using std::swap;
  207. if((_status & status_have_value) == 0 && (o._status & status_have_value) == 0)
  208. {
  209. swap(_status, o._status);
  210. return;
  211. }
  212. if((_status & status_have_value) != 0 && (o._status & status_have_value) != 0)
  213. {
  214. swap(_value, o._value); // NOLINT
  215. swap(_status, o._status);
  216. return;
  217. }
  218. // One must be empty and the other non-empty, so use move construction
  219. if((_status & status_have_value) != 0)
  220. {
  221. // Move construct me into other
  222. new(&o._value) value_type(static_cast<value_type &&>(_value)); // NOLINT
  223. this->_value.~value_type(); // NOLINT
  224. swap(_status, o._status);
  225. }
  226. else
  227. {
  228. // Move construct other into me
  229. new(&_value) value_type(static_cast<value_type &&>(o._value)); // NOLINT
  230. o._value.~value_type(); // NOLINT
  231. swap(_status, o._status);
  232. }
  233. }
  234. };
  235. template <class Base> struct value_storage_delete_copy_constructor : Base // NOLINT
  236. {
  237. using Base::Base;
  238. using value_type = typename Base::value_type;
  239. value_storage_delete_copy_constructor() = default;
  240. value_storage_delete_copy_constructor(const value_storage_delete_copy_constructor &) = delete;
  241. value_storage_delete_copy_constructor(value_storage_delete_copy_constructor &&) = default; // NOLINT
  242. };
  243. template <class Base> struct value_storage_delete_copy_assignment : Base // NOLINT
  244. {
  245. using Base::Base;
  246. using value_type = typename Base::value_type;
  247. value_storage_delete_copy_assignment() = default;
  248. value_storage_delete_copy_assignment(const value_storage_delete_copy_assignment &) = default;
  249. value_storage_delete_copy_assignment(value_storage_delete_copy_assignment &&) = default; // NOLINT
  250. value_storage_delete_copy_assignment &operator=(const value_storage_delete_copy_assignment &o) = delete;
  251. value_storage_delete_copy_assignment &operator=(value_storage_delete_copy_assignment &&o) = default; // NOLINT
  252. };
  253. template <class Base> struct value_storage_delete_move_assignment : Base // NOLINT
  254. {
  255. using Base::Base;
  256. using value_type = typename Base::value_type;
  257. value_storage_delete_move_assignment() = default;
  258. value_storage_delete_move_assignment(const value_storage_delete_move_assignment &) = default;
  259. value_storage_delete_move_assignment(value_storage_delete_move_assignment &&) = default; // NOLINT
  260. value_storage_delete_move_assignment &operator=(const value_storage_delete_move_assignment &o) = default;
  261. value_storage_delete_move_assignment &operator=(value_storage_delete_move_assignment &&o) = delete;
  262. };
  263. template <class Base> struct value_storage_delete_move_constructor : Base // NOLINT
  264. {
  265. using Base::Base;
  266. using value_type = typename Base::value_type;
  267. value_storage_delete_move_constructor() = default;
  268. value_storage_delete_move_constructor(const value_storage_delete_move_constructor &) = default;
  269. value_storage_delete_move_constructor(value_storage_delete_move_constructor &&) = delete;
  270. };
  271. template <class Base> struct value_storage_nontrivial_move_assignment : Base // NOLINT
  272. {
  273. using Base::Base;
  274. using value_type = typename Base::value_type;
  275. value_storage_nontrivial_move_assignment() = default;
  276. value_storage_nontrivial_move_assignment(const value_storage_nontrivial_move_assignment &) = default;
  277. value_storage_nontrivial_move_assignment(value_storage_nontrivial_move_assignment &&) = default; // NOLINT
  278. value_storage_nontrivial_move_assignment &operator=(const value_storage_nontrivial_move_assignment &o) = default;
  279. value_storage_nontrivial_move_assignment &operator=(value_storage_nontrivial_move_assignment &&o) noexcept(std::is_nothrow_move_assignable<value_type>::value) // NOLINT
  280. {
  281. if((this->_status & status_have_value) != 0 && (o._status & status_have_value) != 0)
  282. {
  283. this->_value = static_cast<value_type &&>(o._value); // NOLINT
  284. }
  285. else if((this->_status & status_have_value) != 0 && (o._status & status_have_value) == 0)
  286. {
  287. this->_value.~value_type(); // NOLINT
  288. }
  289. else if((this->_status & status_have_value) == 0 && (o._status & status_have_value) != 0)
  290. {
  291. new(&this->_value) value_type(static_cast<value_type &&>(o._value)); // NOLINT
  292. }
  293. this->_status = o._status;
  294. return *this;
  295. }
  296. };
  297. template <class Base> struct value_storage_nontrivial_copy_assignment : Base // NOLINT
  298. {
  299. using Base::Base;
  300. using value_type = typename Base::value_type;
  301. value_storage_nontrivial_copy_assignment() = default;
  302. value_storage_nontrivial_copy_assignment(const value_storage_nontrivial_copy_assignment &) = default;
  303. value_storage_nontrivial_copy_assignment(value_storage_nontrivial_copy_assignment &&) = default; // NOLINT
  304. value_storage_nontrivial_copy_assignment &operator=(value_storage_nontrivial_copy_assignment &&o) = default; // NOLINT
  305. value_storage_nontrivial_copy_assignment &operator=(const value_storage_nontrivial_copy_assignment &o) noexcept(std::is_nothrow_copy_assignable<value_type>::value)
  306. {
  307. if((this->_status & status_have_value) != 0 && (o._status & status_have_value) != 0)
  308. {
  309. this->_value = o._value; // NOLINT
  310. }
  311. else if((this->_status & status_have_value) != 0 && (o._status & status_have_value) == 0)
  312. {
  313. this->_value.~value_type(); // NOLINT
  314. }
  315. else if((this->_status & status_have_value) == 0 && (o._status & status_have_value) != 0)
  316. {
  317. new(&this->_value) value_type(o._value); // NOLINT
  318. }
  319. this->_status = o._status;
  320. return *this;
  321. }
  322. };
  323. // We don't actually need all of std::is_trivial<>, std::is_trivially_copyable<> is sufficient
  324. template <class T> using value_storage_select_trivality = std::conditional_t<std::is_trivially_copyable<devoid<T>>::value, value_storage_trivial<T>, value_storage_nontrivial<T>>;
  325. template <class T> using value_storage_select_move_constructor = std::conditional_t<std::is_move_constructible<devoid<T>>::value, value_storage_select_trivality<T>, value_storage_delete_move_constructor<value_storage_select_trivality<T>>>;
  326. template <class T> using value_storage_select_copy_constructor = std::conditional_t<std::is_copy_constructible<devoid<T>>::value, value_storage_select_move_constructor<T>, value_storage_delete_copy_constructor<value_storage_select_move_constructor<T>>>;
  327. template <class T>
  328. using value_storage_select_move_assignment = std::conditional_t<std::is_trivially_move_assignable<devoid<T>>::value, value_storage_select_copy_constructor<T>,
  329. std::conditional_t<std::is_move_assignable<devoid<T>>::value, value_storage_nontrivial_move_assignment<value_storage_select_copy_constructor<T>>, value_storage_delete_copy_assignment<value_storage_select_copy_constructor<T>>>>;
  330. template <class T>
  331. using value_storage_select_copy_assignment = std::conditional_t<std::is_trivially_copy_assignable<devoid<T>>::value, value_storage_select_move_assignment<T>,
  332. std::conditional_t<std::is_copy_assignable<devoid<T>>::value, value_storage_nontrivial_copy_assignment<value_storage_select_move_assignment<T>>, value_storage_delete_copy_assignment<value_storage_select_move_assignment<T>>>>;
  333. template <class T> using value_storage_select_impl = value_storage_select_copy_assignment<T>;
  334. #ifndef NDEBUG
  335. // Check is trivial in all ways except default constructibility
  336. // static_assert(std::is_trivial<value_storage_select_impl<int>>::value, "value_storage_select_impl<int> is not trivial!");
  337. // static_assert(std::is_trivially_default_constructible<value_storage_select_impl<int>>::value, "value_storage_select_impl<int> is not trivially default constructible!");
  338. static_assert(std::is_trivially_copyable<value_storage_select_impl<int>>::value, "value_storage_select_impl<int> is not trivially copyable!");
  339. static_assert(std::is_trivially_assignable<value_storage_select_impl<int>, value_storage_select_impl<int>>::value, "value_storage_select_impl<int> is not trivially assignable!");
  340. static_assert(std::is_trivially_destructible<value_storage_select_impl<int>>::value, "value_storage_select_impl<int> is not trivially destructible!");
  341. static_assert(std::is_trivially_copy_constructible<value_storage_select_impl<int>>::value, "value_storage_select_impl<int> is not trivially copy constructible!");
  342. static_assert(std::is_trivially_move_constructible<value_storage_select_impl<int>>::value, "value_storage_select_impl<int> is not trivially move constructible!");
  343. static_assert(std::is_trivially_copy_assignable<value_storage_select_impl<int>>::value, "value_storage_select_impl<int> is not trivially copy assignable!");
  344. static_assert(std::is_trivially_move_assignable<value_storage_select_impl<int>>::value, "value_storage_select_impl<int> is not trivially move assignable!");
  345. // Also check is standard layout
  346. static_assert(std::is_standard_layout<value_storage_select_impl<int>>::value, "value_storage_select_impl<int> is not a standard layout type!");
  347. #endif
  348. } // namespace detail
  349. BOOST_OUTCOME_V2_NAMESPACE_END
  350. #endif