value_storage.hpp 59 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284
  1. /* Essentially an internal optional implementation :)
  2. (C) 2017-2025 Niall Douglas <http://www.nedproductions.biz/> (24 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_EXPORT_BEGIN
  29. namespace detail
  30. {
  31. // Helpers for move assigning to empty storage
  32. template <class T, bool isCopyOrMoveConstructible = std::is_copy_constructible<T>::value || std::is_move_constructible<T>::value,
  33. bool isDefaultConstructibleAndCopyOrMoveAssignable =
  34. std::is_default_constructible<T>::value && (std::is_copy_assignable<T>::value || std::is_move_assignable<T>::value)>
  35. struct move_assign_to_empty;
  36. // Prefer to use move or copy construction
  37. template <class T> struct move_assign_to_empty<T, true, false>
  38. {
  39. move_assign_to_empty(T *dest, T *o) noexcept(std::is_nothrow_move_constructible<T>::value) { new(dest) T(static_cast<T &&>(*o)); }
  40. };
  41. template <class T> struct move_assign_to_empty<T, true, true>
  42. {
  43. move_assign_to_empty(T *dest, T *o) noexcept(std::is_nothrow_move_constructible<T>::value) { new(dest) T(static_cast<T &&>(*o)); }
  44. };
  45. // But fall back on default construction and move assign if necessary
  46. template <class T> struct move_assign_to_empty<T, false, true>
  47. {
  48. move_assign_to_empty(T *dest, T *o) noexcept(std::is_nothrow_default_constructible<T>::value && std::is_nothrow_move_assignable<T>::value)
  49. {
  50. new(dest) T;
  51. *dest = static_cast<T &&>(*o);
  52. }
  53. };
  54. // Void does nothing
  55. template <> struct move_assign_to_empty<void, false, false>
  56. {
  57. move_assign_to_empty(void *, void *) noexcept { /* nothing to assign */ }
  58. };
  59. template <> struct move_assign_to_empty<const void, false, false>
  60. {
  61. move_assign_to_empty(const void *, const void *) noexcept { /* nothing to assign */ }
  62. };
  63. // Helpers for copy assigning to empty storage
  64. template <class T, bool isCopyConstructible = std::is_copy_constructible<T>::value,
  65. bool isDefaultConstructibleAndCopyAssignable = std::is_default_constructible<T>::value && std::is_copy_assignable<T>::value>
  66. struct copy_assign_to_empty;
  67. // Prefer to use copy construction
  68. template <class T> struct copy_assign_to_empty<T, true, false>
  69. {
  70. copy_assign_to_empty(T *dest, const T *o) noexcept(std::is_nothrow_copy_constructible<T>::value) { new(dest) T(*o); }
  71. };
  72. template <class T> struct copy_assign_to_empty<T, true, true>
  73. {
  74. copy_assign_to_empty(T *dest, const T *o) noexcept(std::is_nothrow_copy_constructible<T>::value) { new(dest) T(*o); }
  75. };
  76. // But fall back on default construction and copy assign if necessary
  77. template <class T> struct copy_assign_to_empty<T, false, true>
  78. {
  79. copy_assign_to_empty(T *dest, const T *o) noexcept(std::is_nothrow_default_constructible<T>::value && std::is_nothrow_copy_assignable<T>::value)
  80. {
  81. new(dest) T;
  82. *dest = *o;
  83. }
  84. };
  85. // Void does nothing
  86. template <> struct copy_assign_to_empty<void, false, false>
  87. {
  88. copy_assign_to_empty(void *, void *) noexcept { /* nothing to assign */ }
  89. };
  90. template <> struct copy_assign_to_empty<const void, false, false>
  91. {
  92. copy_assign_to_empty(const void *, const void *) noexcept { /* nothing to assign */ }
  93. };
  94. template <class T, bool nothrow> struct strong_swap_impl
  95. {
  96. constexpr strong_swap_impl(bool &allgood, T &a, T &b)
  97. {
  98. allgood = true;
  99. using std::swap;
  100. swap(a, b);
  101. }
  102. };
  103. template <class T, bool nothrow> struct strong_placement_impl
  104. {
  105. template <class F> constexpr strong_placement_impl(bool &allgood, T *a, T *b, F &&f)
  106. {
  107. allgood = true;
  108. new(a) T(static_cast<T &&>(*b));
  109. b->~T();
  110. f();
  111. }
  112. };
  113. #ifndef BOOST_NO_EXCEPTIONS
  114. template <class T> struct strong_swap_impl<T, false>
  115. {
  116. strong_swap_impl(bool &allgood, T &a, T &b)
  117. {
  118. allgood = true;
  119. T v(static_cast<T &&>(a));
  120. try
  121. {
  122. a = static_cast<T &&>(b);
  123. }
  124. catch(...)
  125. {
  126. // Try to put back a
  127. try
  128. {
  129. a = static_cast<T &&>(v);
  130. // fall through as all good
  131. }
  132. catch(...)
  133. {
  134. // failed to completely restore
  135. allgood = false;
  136. // throw away second exception
  137. }
  138. throw; // rethrow original exception
  139. }
  140. // b has been moved to a, try to move v to b
  141. try
  142. {
  143. b = static_cast<T &&>(v);
  144. }
  145. catch(...)
  146. {
  147. // Try to restore a to b, and v to a
  148. try
  149. {
  150. b = static_cast<T &&>(a);
  151. a = static_cast<T &&>(v);
  152. // fall through as all good
  153. }
  154. catch(...)
  155. {
  156. // failed to completely restore
  157. allgood = false;
  158. // throw away second exception
  159. }
  160. throw; // rethrow original exception
  161. }
  162. }
  163. };
  164. template <class T> struct strong_placement_impl<T, false>
  165. {
  166. template <class F> strong_placement_impl(bool &allgood, T *a, T *b, F &&f)
  167. {
  168. new(a) T(static_cast<T &&>(*b));
  169. try
  170. {
  171. b->~T();
  172. f();
  173. }
  174. catch(...)
  175. {
  176. // Try to put back a, but only if we are still good
  177. if(allgood)
  178. {
  179. try
  180. {
  181. new(b) T(static_cast<T &&>(*a));
  182. // fall through as all good
  183. }
  184. catch(...)
  185. {
  186. // failed to completely restore
  187. allgood = false;
  188. // throw away second exception
  189. }
  190. throw; // rethrow original exception
  191. }
  192. }
  193. }
  194. };
  195. #endif
  196. } // namespace detail
  197. /*!
  198. */
  199. BOOST_OUTCOME_TEMPLATE(class T)
  200. BOOST_OUTCOME_TREQUIRES(BOOST_OUTCOME_TPRED(std::is_move_constructible<T>::value &&std::is_move_assignable<T>::value))
  201. constexpr inline void strong_swap(bool &allgood, T &a, T &b) noexcept(detail::is_nothrow_swappable<T>::value)
  202. {
  203. detail::strong_swap_impl<T, detail::is_nothrow_swappable<T>::value>(allgood, a, b);
  204. }
  205. /*!
  206. */
  207. BOOST_OUTCOME_TEMPLATE(class T, class F)
  208. BOOST_OUTCOME_TREQUIRES(BOOST_OUTCOME_TPRED(std::is_move_constructible<T>::value &&std::is_move_assignable<T>::value))
  209. constexpr inline void strong_placement(bool &allgood, T *a, T *b, F &&f) noexcept(std::is_nothrow_move_constructible<T>::value)
  210. {
  211. detail::strong_placement_impl<T, std::is_nothrow_move_constructible<T>::value>(allgood, a, b, static_cast<F &&>(f));
  212. }
  213. namespace detail
  214. {
  215. template <class T>
  216. constexpr
  217. #ifdef _MSC_VER
  218. __declspec(noreturn)
  219. #elif defined(__GNUC__) || defined(__clang__)
  220. __attribute__((noreturn))
  221. #endif
  222. void
  223. make_ub(T && /*unused*/)
  224. {
  225. BOOST_OUTCOME_ASSERT(false); // NOLINT
  226. #if defined(__GNUC__) || defined(__clang__)
  227. __builtin_unreachable();
  228. #elif defined(_MSC_VER)
  229. __assume(0);
  230. #endif
  231. }
  232. /* Outcome v1 used a C bitfield whose values were tracked by compiler optimisers nicely,
  233. but that produces ICEs when used in constexpr.
  234. Outcome v2.0-v2.1 used a 32 bit integer and manually set and cleared bits. Unfortunately
  235. only GCC's optimiser tracks bit values during constant folding, and only per byte, and
  236. even then unreliably. https://wg21.link/P1886 "Error speed benchmarking" showed just how
  237. poorly clang and MSVC fails to optimise outcome-using code, if you manually set bits.
  238. Outcome v2.2 therefore uses an enum with fixed values, and constexpr manipulation functions
  239. to change the value to one of the enum's values. This is stupid to look at in source code,
  240. but it make clang's optimiser do the right thing, so it's worth it.
  241. */
  242. enum class status : uint16_t
  243. {
  244. // WARNING: These bits are not tracked by abi-dumper, but changing them will break ABI!
  245. // bits 0-5 in use.
  246. none = 0,
  247. have_value = (1U << 0U),
  248. have_error = (1U << 1U),
  249. have_exception = (2U << 1U),
  250. have_error_exception = (3U << 1U),
  251. // failed to complete a strong swap
  252. have_lost_consistency = (1U << 3U),
  253. have_value_lost_consistency = (1U << 0U) | (1U << 3U),
  254. have_error_lost_consistency = (1U << 1U) | (1U << 3U),
  255. have_exception_lost_consistency = (2U << 1U) | (1U << 3U),
  256. have_error_exception_lost_consistency = (3U << 1U) | (1U << 3U),
  257. // can errno be set from this error?
  258. have_error_is_errno = (1U << 4U),
  259. have_error_error_is_errno = (1U << 1U) | (1U << 4U),
  260. have_error_exception_error_is_errno = (3U << 1U) | (1U << 4U),
  261. have_error_lost_consistency_error_is_errno = (1U << 1U) | (1U << 3U) | (1U << 4U),
  262. have_error_exception_lost_consistency_error_is_errno = (3U << 1U) | (1U << 3U) | (1U << 4U),
  263. // value has been moved from
  264. have_moved_from = (1U << 5U),
  265. have_value_moved_from = (1U << 0U) | (1U << 5U),
  266. have_error_moved_from = (1U << 1U) | (1U << 5U),
  267. have_exception_moved_from = (2U << 1U) | (1U << 5U),
  268. have_error_exception_moved_from = (3U << 1U) | (1U << 5U),
  269. have_value_lost_consistency_moved_from = (1U << 0U) | (1U << 3U) | (1U << 5U),
  270. have_error_lost_consistency_moved_from = (1U << 1U) | (1U << 3U) | (1U << 5U),
  271. have_exception_lost_consistency_moved_from = (2U << 1U) | (1U << 3U) | (1U << 5U),
  272. have_error_exception_lost_consistency_moved_from = (3U << 1U) | (1U << 3U) | (1U << 5U),
  273. have_error_is_errno_moved_from = (1U << 4U) | (1U << 5U),
  274. have_error_error_is_errno_moved_from = (1U << 1U) | (1U << 4U) | (1U << 5U),
  275. have_error_exception_error_is_errno_moved_from = (3U << 1U) | (1U << 4U) | (1U << 5U),
  276. have_error_lost_consistency_error_is_errno_moved_from = (1U << 1U) | (1U << 3U) | (1U << 4U) | (1U << 5U),
  277. have_error_exception_lost_consistency_error_is_errno_moved_from = (3U << 1U) | (1U << 3U) | (1U << 4U) | (1U << 5U),
  278. };
  279. struct status_bitfield_type
  280. {
  281. status status_value{status::none};
  282. uint16_t spare_storage_value{0}; // hooks::spare_storage()
  283. constexpr status_bitfield_type() = default;
  284. constexpr status_bitfield_type(status v) noexcept
  285. : status_value(v)
  286. {
  287. } // NOLINT
  288. constexpr status_bitfield_type(status v, uint16_t s) noexcept
  289. : status_value(v)
  290. , spare_storage_value(s)
  291. {
  292. }
  293. constexpr status_bitfield_type(const status_bitfield_type &) = default;
  294. constexpr status_bitfield_type(status_bitfield_type &&) = default;
  295. constexpr status_bitfield_type &operator=(const status_bitfield_type &) = default;
  296. constexpr status_bitfield_type &operator=(status_bitfield_type &&) = default;
  297. //~status_bitfield_type() = default; // Do NOT uncomment this, it breaks older clangs!
  298. constexpr bool have_value() const noexcept { return (static_cast<uint16_t>(status_value) & static_cast<uint16_t>(status::have_value)) != 0; }
  299. constexpr bool have_error() const noexcept { return (static_cast<uint16_t>(status_value) & static_cast<uint16_t>(status::have_error)) != 0; }
  300. constexpr bool have_exception() const noexcept { return (static_cast<uint16_t>(status_value) & static_cast<uint16_t>(status::have_exception)) != 0; }
  301. constexpr bool have_lost_consistency() const noexcept
  302. {
  303. return (static_cast<uint16_t>(status_value) & static_cast<uint16_t>(status::have_lost_consistency)) != 0;
  304. }
  305. constexpr bool have_error_is_errno() const noexcept
  306. {
  307. return (static_cast<uint16_t>(status_value) & static_cast<uint16_t>(status::have_error_is_errno)) != 0;
  308. }
  309. constexpr bool have_moved_from() const noexcept { return (static_cast<uint16_t>(status_value) & static_cast<uint16_t>(status::have_moved_from)) != 0; }
  310. constexpr status_bitfield_type &set_have_value(bool v) noexcept
  311. {
  312. status_value = static_cast<status>(v ? (static_cast<uint16_t>(status_value) | static_cast<uint16_t>(status::have_value)) :
  313. (static_cast<uint16_t>(status_value) & ~static_cast<uint16_t>(status::have_value)));
  314. return *this;
  315. }
  316. constexpr status_bitfield_type &set_have_error(bool v) noexcept
  317. {
  318. status_value = static_cast<status>(v ? (static_cast<uint16_t>(status_value) | static_cast<uint16_t>(status::have_error)) :
  319. (static_cast<uint16_t>(status_value) & ~static_cast<uint16_t>(status::have_error)));
  320. return *this;
  321. }
  322. constexpr status_bitfield_type &set_have_exception(bool v) noexcept
  323. {
  324. status_value = static_cast<status>(v ? (static_cast<uint16_t>(status_value) | static_cast<uint16_t>(status::have_exception)) :
  325. (static_cast<uint16_t>(status_value) & ~static_cast<uint16_t>(status::have_exception)));
  326. return *this;
  327. }
  328. constexpr status_bitfield_type &set_have_error_is_errno(bool v) noexcept
  329. {
  330. status_value = static_cast<status>(v ? (static_cast<uint16_t>(status_value) | static_cast<uint16_t>(status::have_error_is_errno)) :
  331. (static_cast<uint16_t>(status_value) & ~static_cast<uint16_t>(status::have_error_is_errno)));
  332. return *this;
  333. }
  334. constexpr status_bitfield_type &set_have_lost_consistency(bool v) noexcept
  335. {
  336. status_value = static_cast<status>(v ? (static_cast<uint16_t>(status_value) | static_cast<uint16_t>(status::have_lost_consistency)) :
  337. (static_cast<uint16_t>(status_value) & ~static_cast<uint16_t>(status::have_lost_consistency)));
  338. return *this;
  339. }
  340. constexpr status_bitfield_type &set_have_moved_from(bool v) noexcept
  341. {
  342. status_value = static_cast<status>(v ? (static_cast<uint16_t>(status_value) | static_cast<uint16_t>(status::have_moved_from)) :
  343. (static_cast<uint16_t>(status_value) & ~static_cast<uint16_t>(status::have_moved_from)));
  344. return *this;
  345. }
  346. };
  347. #if !defined(NDEBUG)
  348. // Check is trivial in all ways except default constructibility
  349. static_assert(sizeof(status_bitfield_type) == 4, "status_bitfield_type is not sized 4 bytes!");
  350. static_assert(std::is_trivially_copyable<status_bitfield_type>::value, "status_bitfield_type is not trivially copyable!");
  351. static_assert(std::is_trivially_assignable<status_bitfield_type, status_bitfield_type>::value, "status_bitfield_type is not trivially assignable!");
  352. static_assert(std::is_trivially_destructible<status_bitfield_type>::value, "status_bitfield_type is not trivially destructible!");
  353. static_assert(std::is_trivially_copy_constructible<status_bitfield_type>::value, "status_bitfield_type is not trivially copy constructible!");
  354. static_assert(std::is_trivially_move_constructible<status_bitfield_type>::value, "status_bitfield_type is not trivially move constructible!");
  355. static_assert(std::is_trivially_copy_assignable<status_bitfield_type>::value, "status_bitfield_type is not trivially copy assignable!");
  356. static_assert(std::is_trivially_move_assignable<status_bitfield_type>::value, "status_bitfield_type is not trivially move assignable!");
  357. // Also check is standard layout
  358. static_assert(std::is_standard_layout<status_bitfield_type>::value, "status_bitfield_type is not a standard layout type!");
  359. #endif
  360. template <class State> constexpr inline void _set_error_is_errno(State & /*unused*/) {}
  361. #ifdef _MSC_VER
  362. #pragma warning(push)
  363. #pragma warning(disable : 4127) // conditional expression is constant
  364. #pragma warning(disable : 4624) // destructor was implicitly defined as deleted
  365. #endif
  366. // Used if both T and E are trivial
  367. template <class T, class E> struct value_storage_trivial
  368. {
  369. using value_type = T;
  370. using error_type = E;
  371. // Disable in place construction if they are the same type
  372. struct disable_in_place_value_type
  373. {
  374. };
  375. struct disable_in_place_error_type
  376. {
  377. };
  378. using _value_type = std::conditional_t<std::is_same<value_type, error_type>::value, disable_in_place_value_type, value_type>;
  379. using _error_type = std::conditional_t<std::is_same<value_type, error_type>::value, disable_in_place_error_type, error_type>;
  380. using _value_type_ = devoid<value_type>;
  381. using _error_type_ = devoid<error_type>;
  382. union
  383. {
  384. empty_type _empty;
  385. _value_type_ _value;
  386. _error_type_ _error;
  387. };
  388. status_bitfield_type _status;
  389. constexpr value_storage_trivial() noexcept
  390. : _empty{}
  391. {
  392. }
  393. value_storage_trivial(const value_storage_trivial &) = default; // NOLINT
  394. value_storage_trivial(value_storage_trivial &&) = default; // NOLINT
  395. value_storage_trivial &operator=(const value_storage_trivial &) = default; // NOLINT
  396. value_storage_trivial &operator=(value_storage_trivial &&) = default; // NOLINT
  397. ~value_storage_trivial() = default;
  398. constexpr explicit value_storage_trivial(status_bitfield_type status)
  399. : _empty()
  400. , _status(status)
  401. {
  402. }
  403. template <class... Args>
  404. constexpr explicit value_storage_trivial(in_place_type_t<_value_type> /*unused*/,
  405. Args &&...args) noexcept(detail::is_nothrow_constructible<_value_type_, Args...>)
  406. : _value(static_cast<Args &&>(args)...)
  407. , _status(status::have_value)
  408. {
  409. }
  410. template <class U, class... Args>
  411. constexpr value_storage_trivial(in_place_type_t<_value_type> /*unused*/, std::initializer_list<U> il,
  412. Args &&...args) noexcept(detail::is_nothrow_constructible<_value_type_, std::initializer_list<U>, Args...>)
  413. : _value(il, static_cast<Args &&>(args)...)
  414. , _status(status::have_value)
  415. {
  416. }
  417. template <class... Args>
  418. constexpr explicit value_storage_trivial(in_place_type_t<_error_type> /*unused*/,
  419. Args &&...args) noexcept(detail::is_nothrow_constructible<_error_type_, Args...>)
  420. : _error(static_cast<Args &&>(args)...)
  421. , _status(status::have_error)
  422. {
  423. _set_error_is_errno(*this);
  424. }
  425. template <class U, class... Args>
  426. constexpr value_storage_trivial(in_place_type_t<_error_type> /*unused*/, std::initializer_list<U> il,
  427. Args &&...args) noexcept(detail::is_nothrow_constructible<_error_type_, std::initializer_list<U>, Args...>)
  428. : _error(il, static_cast<Args &&>(args)...)
  429. , _status(status::have_error)
  430. {
  431. _set_error_is_errno(*this);
  432. }
  433. struct nonvoid_converting_constructor_tag
  434. {
  435. };
  436. template <class U, class V>
  437. static constexpr bool enable_nonvoid_converting_constructor =
  438. !(std::is_same<std::decay_t<U>, value_type>::value && std::is_same<std::decay_t<V>, error_type>::value) //
  439. && detail::is_constructible<value_type, U> && detail::is_constructible<error_type, V>;
  440. BOOST_OUTCOME_TEMPLATE(class U, class V)
  441. BOOST_OUTCOME_TREQUIRES(BOOST_OUTCOME_TPRED(enable_nonvoid_converting_constructor<U, V>))
  442. constexpr explicit value_storage_trivial(const value_storage_trivial<U, V> &o,
  443. nonvoid_converting_constructor_tag /*unused*/ = {}) noexcept(detail::is_nothrow_constructible<_value_type_, U> &&
  444. detail::is_nothrow_constructible<_error_type_, V>)
  445. : value_storage_trivial(o._status.have_value() ?
  446. value_storage_trivial(in_place_type<value_type>, o._value) :
  447. (o._status.have_error() ? value_storage_trivial(in_place_type<error_type>, o._error) : value_storage_trivial())) // NOLINT
  448. {
  449. _status = o._status;
  450. }
  451. BOOST_OUTCOME_TEMPLATE(class U, class V)
  452. BOOST_OUTCOME_TREQUIRES(BOOST_OUTCOME_TPRED(enable_nonvoid_converting_constructor<U, V>))
  453. constexpr explicit value_storage_trivial(value_storage_trivial<U, V> &&o,
  454. nonvoid_converting_constructor_tag /*unused*/ = {}) noexcept(detail::is_nothrow_constructible<_value_type_, U> &&
  455. detail::is_nothrow_constructible<_error_type_, V>)
  456. : value_storage_trivial(
  457. o._status.have_value() ?
  458. value_storage_trivial(in_place_type<value_type>, static_cast<U &&>(o._value)) :
  459. (o._status.have_error() ? value_storage_trivial(in_place_type<error_type>, static_cast<V &&>(o._error)) : value_storage_trivial())) // NOLINT
  460. {
  461. _status = o._status;
  462. }
  463. struct void_value_converting_constructor_tag
  464. {
  465. };
  466. template <class V>
  467. static constexpr bool enable_void_value_converting_constructor =
  468. std::is_default_constructible<value_type>::value && detail::is_constructible<error_type, V>;
  469. BOOST_OUTCOME_TEMPLATE(class V)
  470. BOOST_OUTCOME_TREQUIRES(BOOST_OUTCOME_TPRED(enable_void_value_converting_constructor<V>))
  471. constexpr explicit value_storage_trivial(const value_storage_trivial<void, V> &o, void_value_converting_constructor_tag /*unused*/ = {}) noexcept(
  472. std::is_nothrow_default_constructible<_value_type_>::value && detail::is_nothrow_constructible<_error_type_, V>)
  473. : value_storage_trivial(o._status.have_value() ?
  474. value_storage_trivial(in_place_type<value_type>) :
  475. (o._status.have_error() ? value_storage_trivial(in_place_type<error_type>, o._error) : value_storage_trivial())) // NOLINT
  476. {
  477. _status = o._status;
  478. }
  479. BOOST_OUTCOME_TEMPLATE(class V)
  480. BOOST_OUTCOME_TREQUIRES(BOOST_OUTCOME_TPRED(enable_void_value_converting_constructor<V>))
  481. constexpr explicit value_storage_trivial(value_storage_trivial<void, V> &&o, void_value_converting_constructor_tag /*unused*/ = {}) noexcept(
  482. std::is_nothrow_default_constructible<_value_type_>::value && detail::is_nothrow_constructible<_error_type_, V>)
  483. : value_storage_trivial(
  484. o._status.have_value() ?
  485. value_storage_trivial(in_place_type<value_type>) :
  486. (o._status.have_error() ? value_storage_trivial(in_place_type<error_type>, static_cast<V &&>(o._error)) : value_storage_trivial())) // NOLINT
  487. {
  488. _status = o._status;
  489. }
  490. struct void_error_converting_constructor_tag
  491. {
  492. };
  493. template <class U>
  494. static constexpr bool enable_void_error_converting_constructor =
  495. std::is_default_constructible<error_type>::value && detail::is_constructible<value_type, U>;
  496. BOOST_OUTCOME_TEMPLATE(class U)
  497. BOOST_OUTCOME_TREQUIRES(BOOST_OUTCOME_TPRED(enable_void_error_converting_constructor<U>))
  498. constexpr explicit value_storage_trivial(const value_storage_trivial<U, void> &o, void_error_converting_constructor_tag /*unused*/ = {}) noexcept(
  499. detail::is_nothrow_constructible<_value_type_, U> && std::is_nothrow_default_constructible<_error_type_>::value)
  500. : value_storage_trivial(o._status.have_value() ?
  501. value_storage_trivial(in_place_type<value_type>, o._value) :
  502. (o._status.have_error() ? value_storage_trivial(in_place_type<error_type>) : value_storage_trivial())) // NOLINT
  503. {
  504. _status = o._status;
  505. }
  506. BOOST_OUTCOME_TEMPLATE(class U)
  507. BOOST_OUTCOME_TREQUIRES(BOOST_OUTCOME_TPRED(enable_void_error_converting_constructor<U>))
  508. constexpr explicit value_storage_trivial(value_storage_trivial<U, void> &&o, void_error_converting_constructor_tag /*unused*/ = {}) noexcept(
  509. detail::is_nothrow_constructible<_value_type_, U> && std::is_nothrow_default_constructible<_error_type_>::value)
  510. : value_storage_trivial(o._status.have_value() ?
  511. value_storage_trivial(in_place_type<value_type>, static_cast<U &&>(o._value)) :
  512. (o._status.have_error() ? value_storage_trivial(in_place_type<error_type>) : value_storage_trivial())) // NOLINT
  513. {
  514. _status = o._status;
  515. }
  516. constexpr void swap(value_storage_trivial &o) noexcept
  517. {
  518. // storage is trivial, so just use assignment
  519. auto temp = static_cast<value_storage_trivial &&>(*this);
  520. *this = static_cast<value_storage_trivial &&>(o);
  521. o = static_cast<value_storage_trivial &&>(temp);
  522. }
  523. };
  524. /* Used if T or E is non-trivial. The additional constexpr is injected in C++ 20 to enable Outcome to
  525. work in constexpr evaluation contexts in C++ 20 where non-trivial constexpr destructors are now allowed.
  526. */
  527. template <class T, class E> struct value_storage_nontrivial
  528. {
  529. using value_type = T;
  530. using error_type = E;
  531. struct disable_in_place_value_type
  532. {
  533. };
  534. struct disable_in_place_error_type
  535. {
  536. };
  537. using _value_type = std::conditional_t<std::is_same<value_type, error_type>::value, disable_in_place_value_type, value_type>;
  538. using _error_type = std::conditional_t<std::is_same<value_type, error_type>::value, disable_in_place_error_type, error_type>;
  539. using _value_type_ = devoid<value_type>;
  540. using _error_type_ = devoid<error_type>;
  541. union
  542. {
  543. empty_type _empty1;
  544. _value_type_ _value;
  545. };
  546. status_bitfield_type _status;
  547. union
  548. {
  549. empty_type _empty2;
  550. _error_type_ _error;
  551. };
  552. #if __cplusplus >= 202000L || _HAS_CXX20
  553. constexpr
  554. #endif
  555. value_storage_nontrivial() noexcept
  556. : _empty1{}
  557. , _empty2{}
  558. {
  559. }
  560. value_storage_nontrivial &operator=(const value_storage_nontrivial &) = default; // if reaches here, copy assignment is trivial
  561. value_storage_nontrivial &operator=(value_storage_nontrivial &&) = default; // NOLINT if reaches here, move assignment is trivial
  562. #if __cplusplus >= 202000L || _HAS_CXX20
  563. constexpr
  564. #endif
  565. value_storage_nontrivial(value_storage_nontrivial &&o) noexcept(std::is_nothrow_move_constructible<_value_type_>::value &&
  566. std::is_nothrow_move_constructible<_error_type_>::value) // NOLINT
  567. {
  568. if(o._status.have_value())
  569. {
  570. new(BOOST_OUTCOME_ADDRESS_OF(_value)) _value_type_(static_cast<_value_type_ &&>(o._value)); // NOLINT
  571. }
  572. else if(o._status.have_error())
  573. {
  574. new(BOOST_OUTCOME_ADDRESS_OF(_error)) _error_type_(static_cast<_error_type_ &&>(o._error)); // NOLINT
  575. }
  576. _status = o._status;
  577. o._status.set_have_moved_from(true);
  578. }
  579. #if __cplusplus >= 202000L || _HAS_CXX20
  580. constexpr
  581. #endif
  582. value_storage_nontrivial(const value_storage_nontrivial &o) noexcept(std::is_nothrow_copy_constructible<_value_type_>::value &&
  583. std::is_nothrow_copy_constructible<_error_type_>::value)
  584. {
  585. if(o._status.have_value())
  586. {
  587. new(BOOST_OUTCOME_ADDRESS_OF(_value)) _value_type_(o._value); // NOLINT
  588. }
  589. else if(o._status.have_error())
  590. {
  591. new(BOOST_OUTCOME_ADDRESS_OF(_error)) _error_type_(o._error); // NOLINT
  592. }
  593. _status = o._status;
  594. }
  595. #if __cplusplus >= 202000L || _HAS_CXX20
  596. constexpr
  597. #endif
  598. explicit value_storage_nontrivial(status_bitfield_type status)
  599. : _empty1()
  600. , _status(status)
  601. , _empty2()
  602. {
  603. }
  604. template <class... Args>
  605. constexpr explicit value_storage_nontrivial(in_place_type_t<_value_type> /*unused*/,
  606. Args &&...args) noexcept(detail::is_nothrow_constructible<_value_type_, Args...>)
  607. : _value(static_cast<Args &&>(args)...) // NOLINT
  608. , _status(status::have_value)
  609. {
  610. }
  611. template <class U, class... Args>
  612. constexpr value_storage_nontrivial(in_place_type_t<_value_type> /*unused*/, std::initializer_list<U> il,
  613. Args &&...args) noexcept(detail::is_nothrow_constructible<_value_type_, std::initializer_list<U>, Args...>)
  614. : _value(il, static_cast<Args &&>(args)...)
  615. , _status(status::have_value)
  616. {
  617. }
  618. template <class... Args>
  619. constexpr explicit value_storage_nontrivial(in_place_type_t<_error_type> /*unused*/,
  620. Args &&...args) noexcept(detail::is_nothrow_constructible<_error_type_, Args...>)
  621. : _status(status::have_error)
  622. , _error(static_cast<Args &&>(args)...) // NOLINT
  623. {
  624. _set_error_is_errno(*this);
  625. }
  626. template <class U, class... Args>
  627. constexpr value_storage_nontrivial(in_place_type_t<_error_type> /*unused*/, std::initializer_list<U> il,
  628. Args &&...args) noexcept(detail::is_nothrow_constructible<_error_type_, std::initializer_list<U>, Args...>)
  629. : _status(status::have_error)
  630. , _error(il, static_cast<Args &&>(args)...)
  631. {
  632. _set_error_is_errno(*this);
  633. }
  634. struct nonvoid_converting_constructor_tag
  635. {
  636. };
  637. template <class U, class V>
  638. static constexpr bool enable_nonvoid_converting_constructor =
  639. !(std::is_same<std::decay_t<U>, value_type>::value && std::is_same<std::decay_t<V>, error_type>::value) //
  640. && detail::is_constructible<value_type, U> && detail::is_constructible<error_type, V>;
  641. BOOST_OUTCOME_TEMPLATE(class U, class V)
  642. BOOST_OUTCOME_TREQUIRES(BOOST_OUTCOME_TPRED(enable_nonvoid_converting_constructor<U, V>))
  643. constexpr explicit value_storage_nontrivial(const value_storage_trivial<U, V> &o, nonvoid_converting_constructor_tag /*unused*/ = {}) noexcept(
  644. detail::is_nothrow_constructible<_value_type_, U> && detail::is_nothrow_constructible<_error_type_, V>)
  645. : value_storage_nontrivial(o._status.have_value() ?
  646. value_storage_nontrivial(in_place_type<value_type>, o._value) :
  647. (o._status.have_error() ? value_storage_nontrivial(in_place_type<error_type>, o._error) : value_storage_nontrivial()))
  648. {
  649. _status = o._status;
  650. }
  651. BOOST_OUTCOME_TEMPLATE(class U, class V)
  652. BOOST_OUTCOME_TREQUIRES(BOOST_OUTCOME_TPRED(enable_nonvoid_converting_constructor<U, V>))
  653. constexpr explicit value_storage_nontrivial(value_storage_trivial<U, V> &&o, nonvoid_converting_constructor_tag /*unused*/ = {}) noexcept(
  654. detail::is_nothrow_constructible<_value_type_, U> && detail::is_nothrow_constructible<_error_type_, V>)
  655. : value_storage_nontrivial(
  656. o._status.have_value() ?
  657. value_storage_nontrivial(in_place_type<value_type>, static_cast<U &&>(o._value)) :
  658. (o._status.have_error() ? value_storage_nontrivial(in_place_type<error_type>, static_cast<V &&>(o._error)) : value_storage_nontrivial()))
  659. {
  660. _status = o._status;
  661. }
  662. BOOST_OUTCOME_TEMPLATE(class U, class V)
  663. BOOST_OUTCOME_TREQUIRES(BOOST_OUTCOME_TPRED(enable_nonvoid_converting_constructor<U, V>))
  664. constexpr explicit value_storage_nontrivial(const value_storage_nontrivial<U, V> &o, nonvoid_converting_constructor_tag /*unused*/ = {}) noexcept(
  665. detail::is_nothrow_constructible<_value_type_, U> && detail::is_nothrow_constructible<_error_type_, V>)
  666. : value_storage_nontrivial(o._status.have_value() ?
  667. value_storage_nontrivial(in_place_type<value_type>, o._value) :
  668. (o._status.have_error() ? value_storage_nontrivial(in_place_type<error_type>, o._error) : value_storage_nontrivial()))
  669. {
  670. _status = o._status;
  671. }
  672. BOOST_OUTCOME_TEMPLATE(class U, class V)
  673. BOOST_OUTCOME_TREQUIRES(BOOST_OUTCOME_TPRED(enable_nonvoid_converting_constructor<U, V>))
  674. constexpr explicit value_storage_nontrivial(value_storage_nontrivial<U, V> &&o, nonvoid_converting_constructor_tag /*unused*/ = {}) noexcept(
  675. detail::is_nothrow_constructible<_value_type_, U> && detail::is_nothrow_constructible<_error_type_, V>)
  676. : value_storage_nontrivial(
  677. o._status.have_value() ?
  678. value_storage_nontrivial(in_place_type<value_type>, static_cast<U &&>(o._value)) :
  679. (o._status.have_error() ? value_storage_nontrivial(in_place_type<error_type>, static_cast<V &&>(o._error)) : value_storage_nontrivial()))
  680. {
  681. _status = o._status;
  682. }
  683. struct void_value_converting_constructor_tag
  684. {
  685. };
  686. template <class V>
  687. static constexpr bool enable_void_value_converting_constructor =
  688. std::is_default_constructible<value_type>::value && detail::is_constructible<error_type, V>;
  689. BOOST_OUTCOME_TEMPLATE(class V)
  690. BOOST_OUTCOME_TREQUIRES(BOOST_OUTCOME_TPRED(enable_void_value_converting_constructor<V>))
  691. constexpr explicit value_storage_nontrivial(const value_storage_trivial<void, V> &o, void_value_converting_constructor_tag /*unused*/ = {}) noexcept(
  692. std::is_nothrow_default_constructible<_value_type_>::value && detail::is_nothrow_constructible<_error_type_, V>)
  693. {
  694. if(o._status.have_value())
  695. {
  696. new(BOOST_OUTCOME_ADDRESS_OF(_value)) _value_type_(); // NOLINT
  697. }
  698. else if(o._status.have_error())
  699. {
  700. new(BOOST_OUTCOME_ADDRESS_OF(_error)) _error_type_(o._error); // NOLINT
  701. }
  702. _status = o._status;
  703. }
  704. BOOST_OUTCOME_TEMPLATE(class V)
  705. BOOST_OUTCOME_TREQUIRES(BOOST_OUTCOME_TPRED(enable_void_value_converting_constructor<V>))
  706. constexpr explicit value_storage_nontrivial(value_storage_trivial<void, V> &&o, void_value_converting_constructor_tag /*unused*/ = {}) noexcept(
  707. std::is_nothrow_default_constructible<_value_type_>::value && detail::is_nothrow_constructible<_error_type_, V>)
  708. {
  709. if(o._status.have_value())
  710. {
  711. new(BOOST_OUTCOME_ADDRESS_OF(_value)) _value_type_(); // NOLINT
  712. }
  713. else if(o._status.have_error())
  714. {
  715. new(BOOST_OUTCOME_ADDRESS_OF(_error)) _error_type_(static_cast<_error_type_ &&>(o._error)); // NOLINT
  716. }
  717. _status = o._status;
  718. o._status.set_have_moved_from(true);
  719. }
  720. struct void_error_converting_constructor_tag
  721. {
  722. };
  723. template <class U>
  724. static constexpr bool enable_void_error_converting_constructor =
  725. std::is_default_constructible<error_type>::value && detail::is_constructible<value_type, U>;
  726. BOOST_OUTCOME_TEMPLATE(class U)
  727. BOOST_OUTCOME_TREQUIRES(BOOST_OUTCOME_TPRED(enable_void_error_converting_constructor<U>))
  728. constexpr explicit value_storage_nontrivial(const value_storage_trivial<U, void> &o, void_error_converting_constructor_tag /*unused*/ = {}) noexcept(
  729. detail::is_nothrow_constructible<_value_type_, U> && std::is_nothrow_default_constructible<_error_type_>::value)
  730. {
  731. if(o._status.have_value())
  732. {
  733. new(BOOST_OUTCOME_ADDRESS_OF(_value)) _value_type_(o._value); // NOLINT
  734. }
  735. else if(o._status.have_error())
  736. {
  737. new(BOOST_OUTCOME_ADDRESS_OF(_error)) _error_type_(); // NOLINT
  738. }
  739. _status = o._status;
  740. }
  741. BOOST_OUTCOME_TEMPLATE(class U)
  742. BOOST_OUTCOME_TREQUIRES(BOOST_OUTCOME_TPRED(enable_void_error_converting_constructor<U>))
  743. constexpr explicit value_storage_nontrivial(value_storage_trivial<U, void> &&o, void_error_converting_constructor_tag /*unused*/ = {}) noexcept(
  744. detail::is_nothrow_constructible<_value_type_, U> && std::is_nothrow_default_constructible<_error_type_>::value)
  745. {
  746. if(o._status.have_value())
  747. {
  748. new(BOOST_OUTCOME_ADDRESS_OF(_value)) _value_type_(static_cast<_value_type_ &&>(o._value)); // NOLINT
  749. }
  750. else if(o._status.have_error())
  751. {
  752. new(BOOST_OUTCOME_ADDRESS_OF(_error)) _error_type_(); // NOLINT
  753. }
  754. _status = o._status;
  755. o._status.set_have_moved_from(true);
  756. }
  757. #if __cplusplus >= 202000L || _HAS_CXX20
  758. constexpr
  759. #endif
  760. ~value_storage_nontrivial() noexcept(std::is_nothrow_destructible<_value_type_>::value && std::is_nothrow_destructible<_error_type_>::value)
  761. {
  762. if(this->_status.have_value())
  763. {
  764. if(!trait::is_move_bitcopying<value_type>::value || !this->_status.have_moved_from())
  765. {
  766. this->_value.~_value_type_(); // NOLINT
  767. }
  768. this->_status.set_have_value(false);
  769. }
  770. else if(this->_status.have_error())
  771. {
  772. if(!trait::is_move_bitcopying<error_type>::value || !this->_status.have_moved_from())
  773. {
  774. this->_error.~_error_type_(); // NOLINT
  775. }
  776. this->_status.set_have_error(false);
  777. }
  778. }
  779. #if __cplusplus >= 202000L || _HAS_CXX20
  780. constexpr
  781. #endif
  782. void
  783. swap(value_storage_nontrivial &o) noexcept(detail::is_nothrow_swappable<_value_type_>::value && detail::is_nothrow_swappable<_error_type_>::value)
  784. {
  785. using std::swap;
  786. // empty/empty
  787. if(!_status.have_value() && !o._status.have_value() && !_status.have_error() && !o._status.have_error())
  788. {
  789. swap(_status, o._status);
  790. return;
  791. }
  792. // value/value
  793. if(_status.have_value() && o._status.have_value())
  794. {
  795. struct some_type
  796. {
  797. status_bitfield_type &a, &b;
  798. bool all_good{false};
  799. ~some_type()
  800. {
  801. if(!this->all_good)
  802. {
  803. // We lost one of the values
  804. this->a.set_have_lost_consistency(true);
  805. this->b.set_have_lost_consistency(true);
  806. }
  807. }
  808. } some_type_value{_status, o._status};
  809. strong_swap(some_type_value.all_good, _value, o._value);
  810. swap(_status, o._status);
  811. return;
  812. }
  813. // error/error
  814. if(_status.have_error() && o._status.have_error())
  815. {
  816. struct some_type
  817. {
  818. status_bitfield_type &a, &b;
  819. bool all_good{false};
  820. ~some_type()
  821. {
  822. if(!this->all_good)
  823. {
  824. // We lost one of the values
  825. this->a.set_have_lost_consistency(true);
  826. this->b.set_have_lost_consistency(true);
  827. }
  828. }
  829. } some_type_value{_status, o._status};
  830. strong_swap(some_type_value.all_good, _error, o._error);
  831. swap(_status, o._status);
  832. return;
  833. }
  834. // Could be value/empty, error/empty, etc
  835. if(_status.have_value() && !o._status.have_error())
  836. {
  837. // Move construct me into other
  838. new(BOOST_OUTCOME_ADDRESS_OF(o._value)) _value_type_(static_cast<_value_type_ &&>(_value)); // NOLINT
  839. if(!trait::is_move_bitcopying<value_type>::value)
  840. {
  841. this->_value.~value_type(); // NOLINT
  842. }
  843. swap(_status, o._status);
  844. return;
  845. }
  846. if(o._status.have_value() && !_status.have_error())
  847. {
  848. // Move construct other into me
  849. new(BOOST_OUTCOME_ADDRESS_OF(_value)) _value_type_(static_cast<_value_type_ &&>(o._value)); // NOLINT
  850. if(!trait::is_move_bitcopying<value_type>::value)
  851. {
  852. o._value.~value_type(); // NOLINT
  853. }
  854. swap(_status, o._status);
  855. return;
  856. }
  857. if(_status.have_error() && !o._status.have_value())
  858. {
  859. // Move construct me into other
  860. new(BOOST_OUTCOME_ADDRESS_OF(o._error)) _error_type_(static_cast<_error_type_ &&>(_error)); // NOLINT
  861. if(!trait::is_move_bitcopying<error_type>::value)
  862. {
  863. this->_error.~error_type(); // NOLINT
  864. }
  865. swap(_status, o._status);
  866. return;
  867. }
  868. if(o._status.have_error() && !_status.have_value())
  869. {
  870. // Move construct other into me
  871. new(BOOST_OUTCOME_ADDRESS_OF(_error)) _error_type_(static_cast<_error_type_ &&>(o._error)); // NOLINT
  872. if(!trait::is_move_bitcopying<error_type>::value)
  873. {
  874. o._error.~error_type(); // NOLINT
  875. }
  876. swap(_status, o._status);
  877. return;
  878. }
  879. // It can now only be value/error, or error/value
  880. struct some_type
  881. {
  882. status_bitfield_type &a, &b;
  883. _value_type_ *value, *o_value;
  884. _error_type_ *error, *o_error;
  885. bool all_good{true};
  886. ~some_type()
  887. {
  888. if(!this->all_good)
  889. {
  890. // We lost one of the values
  891. this->a.set_have_lost_consistency(true);
  892. this->b.set_have_lost_consistency(true);
  893. }
  894. }
  895. } some_type_value{_status, o._status, BOOST_OUTCOME_ADDRESS_OF(_value), BOOST_OUTCOME_ADDRESS_OF(o._value), BOOST_OUTCOME_ADDRESS_OF(_error), BOOST_OUTCOME_ADDRESS_OF(o._error)};
  896. if(_status.have_value() && o._status.have_error())
  897. {
  898. strong_placement(some_type_value.all_good, some_type_value.o_value, some_type_value.value, [&some_type_value] { //
  899. strong_placement(some_type_value.all_good, some_type_value.error, some_type_value.o_error, [&some_type_value] { //
  900. swap(some_type_value.a, some_type_value.b); //
  901. });
  902. });
  903. return;
  904. }
  905. if(_status.have_error() && o._status.have_value())
  906. {
  907. strong_placement(some_type_value.all_good, some_type_value.o_error, some_type_value.error, [&some_type_value] { //
  908. strong_placement(some_type_value.all_good, some_type_value.value, some_type_value.o_value, [&some_type_value] { //
  909. swap(some_type_value.a, some_type_value.b); //
  910. });
  911. });
  912. return;
  913. }
  914. // Should never reach here
  915. make_ub(_value);
  916. }
  917. };
  918. template <class Base> struct value_storage_delete_copy_constructor : Base // NOLINT
  919. {
  920. using Base::Base;
  921. using value_type = typename Base::value_type;
  922. using error_type = typename Base::error_type;
  923. value_storage_delete_copy_constructor() = default;
  924. value_storage_delete_copy_constructor(const value_storage_delete_copy_constructor &) = delete;
  925. value_storage_delete_copy_constructor(value_storage_delete_copy_constructor &&) = default; // NOLINT
  926. value_storage_delete_copy_constructor &operator=(const value_storage_delete_copy_constructor &o) = default;
  927. value_storage_delete_copy_constructor &operator=(value_storage_delete_copy_constructor &&o) = default; // NOLINT
  928. ~value_storage_delete_copy_constructor() = default;
  929. };
  930. template <class Base> struct value_storage_delete_copy_assignment : Base // NOLINT
  931. {
  932. using Base::Base;
  933. using value_type = typename Base::value_type;
  934. using error_type = typename Base::error_type;
  935. value_storage_delete_copy_assignment() = default;
  936. value_storage_delete_copy_assignment(const value_storage_delete_copy_assignment &) = default;
  937. value_storage_delete_copy_assignment(value_storage_delete_copy_assignment &&) = default; // NOLINT
  938. value_storage_delete_copy_assignment &operator=(const value_storage_delete_copy_assignment &o) = delete;
  939. value_storage_delete_copy_assignment &operator=(value_storage_delete_copy_assignment &&o) = default; // NOLINT
  940. ~value_storage_delete_copy_assignment() = default;
  941. };
  942. template <class Base> struct value_storage_delete_move_assignment : Base // NOLINT
  943. {
  944. using Base::Base;
  945. using value_type = typename Base::value_type;
  946. using error_type = typename Base::error_type;
  947. value_storage_delete_move_assignment() = default;
  948. value_storage_delete_move_assignment(const value_storage_delete_move_assignment &) = default;
  949. value_storage_delete_move_assignment(value_storage_delete_move_assignment &&) = default; // NOLINT
  950. value_storage_delete_move_assignment &operator=(const value_storage_delete_move_assignment &o) = default;
  951. value_storage_delete_move_assignment &operator=(value_storage_delete_move_assignment &&o) = delete;
  952. ~value_storage_delete_move_assignment() = default;
  953. };
  954. template <class Base> struct value_storage_delete_move_constructor : Base // NOLINT
  955. {
  956. using Base::Base;
  957. using value_type = typename Base::value_type;
  958. using error_type = typename Base::error_type;
  959. value_storage_delete_move_constructor() = default;
  960. value_storage_delete_move_constructor(const value_storage_delete_move_constructor &) = default;
  961. value_storage_delete_move_constructor(value_storage_delete_move_constructor &&) = delete;
  962. value_storage_delete_move_constructor &operator=(const value_storage_delete_move_constructor &o) = default;
  963. value_storage_delete_move_constructor &operator=(value_storage_delete_move_constructor &&o) = default;
  964. ~value_storage_delete_move_constructor() = default;
  965. };
  966. template <class Base> struct value_storage_nontrivial_move_assignment : Base // NOLINT
  967. {
  968. using Base::Base;
  969. using value_type = typename Base::value_type;
  970. using error_type = typename Base::error_type;
  971. value_storage_nontrivial_move_assignment() = default;
  972. value_storage_nontrivial_move_assignment(const value_storage_nontrivial_move_assignment &) = default;
  973. value_storage_nontrivial_move_assignment(value_storage_nontrivial_move_assignment &&) = default; // NOLINT
  974. value_storage_nontrivial_move_assignment &operator=(const value_storage_nontrivial_move_assignment &o) = default;
  975. ~value_storage_nontrivial_move_assignment() = default;
  976. #if __cplusplus >= 202000L || _HAS_CXX20
  977. constexpr
  978. #endif
  979. value_storage_nontrivial_move_assignment &
  980. operator=(value_storage_nontrivial_move_assignment &&o) noexcept(std::is_nothrow_move_assignable<value_type>::value &&
  981. std::is_nothrow_move_assignable<error_type>::value &&
  982. noexcept(move_assign_to_empty<value_type>(static_cast<value_type *>(nullptr),
  983. static_cast<value_type *>(nullptr))) &&
  984. noexcept(move_assign_to_empty<error_type>(static_cast<error_type *>(nullptr),
  985. static_cast<error_type *>(nullptr)))) // NOLINT
  986. {
  987. using _value_type_ = typename Base::_value_type_;
  988. using _error_type_ = typename Base::_error_type_;
  989. if(!this->_status.have_value() && !this->_status.have_error() && !o._status.have_value() && !o._status.have_error())
  990. {
  991. this->_status = o._status;
  992. o._status.set_have_moved_from(true);
  993. return *this;
  994. }
  995. if(this->_status.have_value() && o._status.have_value())
  996. {
  997. this->_value = static_cast<_value_type_ &&>(o._value); // NOLINT
  998. this->_status = o._status;
  999. o._status.set_have_moved_from(true);
  1000. return *this;
  1001. }
  1002. if(this->_status.have_error() && o._status.have_error())
  1003. {
  1004. this->_error = static_cast<_error_type_ &&>(o._error); // NOLINT
  1005. this->_status = o._status;
  1006. o._status.set_have_moved_from(true);
  1007. return *this;
  1008. }
  1009. if(this->_status.have_value() && !o._status.have_value() && !o._status.have_error())
  1010. {
  1011. if(!trait::is_move_bitcopying<value_type>::value || this->_status.have_moved_from())
  1012. {
  1013. this->_value.~_value_type_(); // NOLINT
  1014. }
  1015. this->_status = o._status;
  1016. o._status.set_have_moved_from(true);
  1017. return *this;
  1018. }
  1019. if(!this->_status.have_value() && !this->_status.have_error() && o._status.have_value())
  1020. {
  1021. move_assign_to_empty<_value_type_>(BOOST_OUTCOME_ADDRESS_OF(this->_value), BOOST_OUTCOME_ADDRESS_OF(o._value));
  1022. this->_status = o._status;
  1023. o._status.set_have_moved_from(true);
  1024. return *this;
  1025. }
  1026. if(this->_status.have_error() && !o._status.have_value() && !o._status.have_error())
  1027. {
  1028. if(!trait::is_move_bitcopying<error_type>::value || this->_status.have_moved_from())
  1029. {
  1030. this->_error.~_error_type_(); // NOLINT
  1031. }
  1032. this->_status = o._status;
  1033. o._status.set_have_moved_from(true);
  1034. return *this;
  1035. }
  1036. if(!this->_status.have_value() && !this->_status.have_error() && o._status.have_error())
  1037. {
  1038. move_assign_to_empty<_error_type_>(BOOST_OUTCOME_ADDRESS_OF(this->_error), BOOST_OUTCOME_ADDRESS_OF(o._error));
  1039. this->_status = o._status;
  1040. o._status.set_have_moved_from(true);
  1041. return *this;
  1042. }
  1043. if(this->_status.have_value() && o._status.have_error())
  1044. {
  1045. if(!trait::is_move_bitcopying<value_type>::value || this->_status.have_moved_from())
  1046. {
  1047. this->_value.~_value_type_(); // NOLINT
  1048. }
  1049. move_assign_to_empty<_error_type_>(BOOST_OUTCOME_ADDRESS_OF(this->_error), BOOST_OUTCOME_ADDRESS_OF(o._error));
  1050. this->_status = o._status;
  1051. o._status.set_have_moved_from(true);
  1052. return *this;
  1053. }
  1054. if(this->_status.have_error() && o._status.have_value())
  1055. {
  1056. if(!trait::is_move_bitcopying<error_type>::value || this->_status.have_moved_from())
  1057. {
  1058. this->_error.~_error_type_(); // NOLINT
  1059. }
  1060. move_assign_to_empty<_value_type_>(BOOST_OUTCOME_ADDRESS_OF(this->_value), BOOST_OUTCOME_ADDRESS_OF(o._value));
  1061. this->_status = o._status;
  1062. o._status.set_have_moved_from(true);
  1063. return *this;
  1064. }
  1065. // Should never reach here
  1066. make_ub(this->_value);
  1067. }
  1068. };
  1069. template <class Base> struct value_storage_nontrivial_copy_assignment : Base // NOLINT
  1070. {
  1071. using Base::Base;
  1072. using value_type = typename Base::value_type;
  1073. using error_type = typename Base::error_type;
  1074. value_storage_nontrivial_copy_assignment() = default;
  1075. value_storage_nontrivial_copy_assignment(const value_storage_nontrivial_copy_assignment &) = default;
  1076. value_storage_nontrivial_copy_assignment(value_storage_nontrivial_copy_assignment &&) = default; // NOLINT
  1077. value_storage_nontrivial_copy_assignment &operator=(value_storage_nontrivial_copy_assignment &&o) = default; // NOLINT
  1078. ~value_storage_nontrivial_copy_assignment() = default;
  1079. #if __cplusplus >= 202000L || _HAS_CXX20
  1080. constexpr
  1081. #endif
  1082. value_storage_nontrivial_copy_assignment &
  1083. operator=(const value_storage_nontrivial_copy_assignment &o) noexcept(
  1084. std::is_nothrow_copy_assignable<value_type>::value && std::is_nothrow_copy_assignable<error_type>::value &&
  1085. noexcept(copy_assign_to_empty<value_type>(static_cast<value_type *>(nullptr), static_cast<value_type *>(nullptr))) &&
  1086. noexcept(copy_assign_to_empty<error_type>(static_cast<error_type *>(nullptr), static_cast<error_type *>(nullptr))))
  1087. {
  1088. using _value_type_ = typename Base::_value_type_;
  1089. using _error_type_ = typename Base::_error_type_;
  1090. if(!this->_status.have_value() && !this->_status.have_error() && !o._status.have_value() && !o._status.have_error())
  1091. {
  1092. this->_status = o._status;
  1093. return *this;
  1094. }
  1095. if(this->_status.have_value() && o._status.have_value())
  1096. {
  1097. this->_value = o._value; // NOLINT
  1098. this->_status = o._status;
  1099. return *this;
  1100. }
  1101. if(this->_status.have_error() && o._status.have_error())
  1102. {
  1103. this->_error = o._error; // NOLINT
  1104. this->_status = o._status;
  1105. return *this;
  1106. }
  1107. if(this->_status.have_value() && !o._status.have_value() && !o._status.have_error())
  1108. {
  1109. if(!trait::is_move_bitcopying<value_type>::value || this->_status.have_moved_from())
  1110. {
  1111. this->_value.~_value_type_(); // NOLINT
  1112. }
  1113. this->_status = o._status;
  1114. return *this;
  1115. }
  1116. if(!this->_status.have_value() && !this->_status.have_error() && o._status.have_value())
  1117. {
  1118. copy_assign_to_empty<_value_type_>(BOOST_OUTCOME_ADDRESS_OF(this->_value), BOOST_OUTCOME_ADDRESS_OF(o._value));
  1119. this->_status = o._status;
  1120. return *this;
  1121. }
  1122. if(this->_status.have_error() && !o._status.have_value() && !o._status.have_error())
  1123. {
  1124. if(!trait::is_move_bitcopying<error_type>::value || this->_status.have_moved_from())
  1125. {
  1126. this->_error.~_error_type_(); // NOLINT
  1127. }
  1128. this->_status = o._status;
  1129. return *this;
  1130. }
  1131. if(!this->_status.have_value() && !this->_status.have_error() && o._status.have_error())
  1132. {
  1133. copy_assign_to_empty<_error_type_>(BOOST_OUTCOME_ADDRESS_OF(this->_error), BOOST_OUTCOME_ADDRESS_OF(o._error));
  1134. this->_status = o._status;
  1135. return *this;
  1136. }
  1137. if(this->_status.have_value() && o._status.have_error())
  1138. {
  1139. if(!trait::is_move_bitcopying<value_type>::value || this->_status.have_moved_from())
  1140. {
  1141. this->_value.~_value_type_(); // NOLINT
  1142. }
  1143. copy_assign_to_empty<_error_type_>(BOOST_OUTCOME_ADDRESS_OF(this->_error), BOOST_OUTCOME_ADDRESS_OF(o._error));
  1144. this->_status = o._status;
  1145. return *this;
  1146. }
  1147. if(this->_status.have_error() && o._status.have_value())
  1148. {
  1149. if(!trait::is_move_bitcopying<error_type>::value || this->_status.have_moved_from())
  1150. {
  1151. this->_error.~_error_type_(); // NOLINT
  1152. }
  1153. copy_assign_to_empty<_value_type_>(BOOST_OUTCOME_ADDRESS_OF(this->_value), BOOST_OUTCOME_ADDRESS_OF(o._value));
  1154. this->_status = o._status;
  1155. return *this;
  1156. }
  1157. // Should never reach here
  1158. make_ub(this->_value);
  1159. }
  1160. };
  1161. #ifdef _MSC_VER
  1162. #pragma warning(pop)
  1163. #endif
  1164. // is_trivially_copyable is true even if type is not copyable, so handle that here
  1165. template <class T> struct is_storage_trivial
  1166. {
  1167. static constexpr bool value = std::is_void<T>::value || (std::is_trivially_copy_constructible<T>::value && std::is_trivially_copyable<T>::value);
  1168. };
  1169. // work around libstdc++ 7 bug
  1170. template <> struct is_storage_trivial<void>
  1171. {
  1172. static constexpr bool value = true;
  1173. };
  1174. template <> struct is_storage_trivial<const void>
  1175. {
  1176. static constexpr bool value = true;
  1177. };
  1178. // Ability to do copy assigns needs more than just copy assignment
  1179. template <class T> struct is_copy_assignable
  1180. {
  1181. static constexpr bool value = std::is_copy_assignable<T>::value && (std::is_copy_constructible<T>::value || std::is_default_constructible<T>::value);
  1182. };
  1183. // Ability to do move assigns needs more than just move assignment
  1184. template <class T> struct is_move_assignable
  1185. {
  1186. static constexpr bool value = std::is_move_assignable<T>::value && (std::is_move_constructible<T>::value || std::is_default_constructible<T>::value);
  1187. };
  1188. template <class T, class E>
  1189. using value_storage_select_trivality =
  1190. std::conditional_t<is_storage_trivial<T>::value && is_storage_trivial<E>::value, value_storage_trivial<T, E>, value_storage_nontrivial<T, E>>;
  1191. template <class T, class E>
  1192. using value_storage_select_move_constructor =
  1193. std::conditional_t<std::is_move_constructible<devoid<T>>::value && std::is_move_constructible<devoid<E>>::value, value_storage_select_trivality<T, E>,
  1194. value_storage_delete_move_constructor<value_storage_select_trivality<T, E>>>;
  1195. template <class T, class E>
  1196. using value_storage_select_copy_constructor =
  1197. std::conditional_t<std::is_copy_constructible<devoid<T>>::value && std::is_copy_constructible<devoid<E>>::value, value_storage_select_move_constructor<T, E>,
  1198. value_storage_delete_copy_constructor<value_storage_select_move_constructor<T, E>>>;
  1199. template <class T, class E>
  1200. using value_storage_select_move_assignment =
  1201. std::conditional_t<std::is_trivially_move_assignable<devoid<T>>::value && std::is_trivially_move_assignable<devoid<E>>::value,
  1202. value_storage_select_copy_constructor<T, E>,
  1203. std::conditional_t<is_move_assignable<devoid<T>>::value && is_move_assignable<devoid<E>>::value,
  1204. value_storage_nontrivial_move_assignment<value_storage_select_copy_constructor<T, E>>,
  1205. value_storage_delete_move_assignment<value_storage_select_copy_constructor<T, E>>>>;
  1206. template <class T, class E>
  1207. using value_storage_select_copy_assignment =
  1208. std::conditional_t<std::is_trivially_copy_assignable<devoid<T>>::value && std::is_trivially_copy_assignable<devoid<E>>::value,
  1209. value_storage_select_move_assignment<T, E>,
  1210. std::conditional_t<is_copy_assignable<devoid<T>>::value && is_copy_assignable<devoid<E>>::value,
  1211. value_storage_nontrivial_copy_assignment<value_storage_select_move_assignment<T, E>>,
  1212. value_storage_delete_copy_assignment<value_storage_select_move_assignment<T, E>>>>;
  1213. template <class T, class E> using value_storage_select_impl = value_storage_select_copy_assignment<T, E>;
  1214. #ifndef NDEBUG
  1215. // Check is trivial in all ways except default constructibility
  1216. // static_assert(std::is_trivial<value_storage_select_impl<int, long>>::value, "value_storage_select_impl<int, long> is not trivial!");
  1217. // static_assert(std::is_trivially_default_constructible<value_storage_select_impl<int, long>>::value, "value_storage_select_impl<int, long> is not
  1218. // trivially default constructible!");
  1219. static_assert(std::is_trivially_copyable<value_storage_select_impl<int, long>>::value, "value_storage_select_impl<int, long> is not trivially copyable!");
  1220. static_assert(std::is_trivially_assignable<value_storage_select_impl<int, long>, value_storage_select_impl<int, long>>::value,
  1221. "value_storage_select_impl<int, long> is not trivially assignable!");
  1222. static_assert(std::is_trivially_destructible<value_storage_select_impl<int, long>>::value,
  1223. "value_storage_select_impl<int, long> is not trivially destructible!");
  1224. static_assert(std::is_trivially_copy_constructible<value_storage_select_impl<int, long>>::value,
  1225. "value_storage_select_impl<int, long> is not trivially copy constructible!");
  1226. static_assert(std::is_trivially_move_constructible<value_storage_select_impl<int, long>>::value,
  1227. "value_storage_select_impl<int, long> is not trivially move constructible!");
  1228. static_assert(std::is_trivially_copy_assignable<value_storage_select_impl<int, long>>::value,
  1229. "value_storage_select_impl<int, long> is not trivially copy assignable!");
  1230. static_assert(std::is_trivially_move_assignable<value_storage_select_impl<int, long>>::value,
  1231. "value_storage_select_impl<int, long> is not trivially move assignable!");
  1232. // Also check is standard layout
  1233. static_assert(std::is_standard_layout<value_storage_select_impl<int, long>>::value, "value_storage_select_impl<int, long> is not a standard layout type!");
  1234. #endif
  1235. } // namespace detail
  1236. BOOST_OUTCOME_V2_NAMESPACE_END
  1237. #endif