value_storage.hpp 41 KB

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