result.hpp 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730
  1. #ifndef BOOST_LEAF_RESULT_HPP_INCLUDED
  2. #define BOOST_LEAF_RESULT_HPP_INCLUDED
  3. // Copyright 2018-2024 Emil Dotchevski and Reverge Studios, Inc.
  4. // Distributed under the Boost Software License, Version 1.0. (See accompanying
  5. // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
  6. #include <boost/leaf/config.hpp>
  7. #include <boost/leaf/detail/print.hpp>
  8. #include <boost/leaf/detail/capture_list.hpp>
  9. #include <boost/leaf/exception.hpp>
  10. #include <climits>
  11. #include <functional>
  12. namespace boost { namespace leaf {
  13. namespace detail { class dynamic_allocator; }
  14. ////////////////////////////////////////
  15. class bad_result:
  16. public std::exception
  17. {
  18. char const * what() const noexcept final override
  19. {
  20. return "boost::leaf::bad_result";
  21. }
  22. };
  23. ////////////////////////////////////////
  24. namespace detail
  25. {
  26. template <class T, bool Printable = is_printable<T>::value>
  27. struct result_value_printer;
  28. template <class T>
  29. struct result_value_printer<T, true>
  30. {
  31. template <class CharT, class Traits>
  32. static void print( std::basic_ostream<CharT, Traits> & s, T const & x )
  33. {
  34. (void) (s << x);
  35. }
  36. };
  37. template <class T>
  38. struct result_value_printer<T, false>
  39. {
  40. template <class CharT, class Traits>
  41. static void print( std::basic_ostream<CharT, Traits> & s, T const & )
  42. {
  43. (void) (s << "{not printable}");
  44. }
  45. };
  46. template <class CharT, class Traits, class T>
  47. void print_result_value( std::basic_ostream<CharT, Traits> & s, T const & x )
  48. {
  49. result_value_printer<T>::print(s, x);
  50. }
  51. }
  52. ////////////////////////////////////////
  53. namespace detail
  54. {
  55. template <class T>
  56. struct stored
  57. {
  58. using type = T;
  59. using value_no_ref = T;
  60. using value_no_ref_const = T const;
  61. using value_cref = T const &;
  62. using value_ref = T &;
  63. using value_rv_cref = T const &&;
  64. using value_rv_ref = T &&;
  65. static value_no_ref_const * cptr( type const & v ) noexcept
  66. {
  67. return &v;
  68. }
  69. static value_no_ref * ptr( type & v ) noexcept
  70. {
  71. return &v;
  72. }
  73. };
  74. template <class T>
  75. struct stored<T &>
  76. {
  77. using type = std::reference_wrapper<T>;
  78. using value_no_ref = T;
  79. using value_no_ref_const = T;
  80. using value_ref = T &;
  81. using value_cref = T &;
  82. using value_rv_ref = T &;
  83. using value_rv_cref = T &;
  84. static value_no_ref_const * cptr( type const & v ) noexcept
  85. {
  86. return &v.get();
  87. }
  88. static value_no_ref * ptr( type const & v ) noexcept
  89. {
  90. return &v.get();
  91. }
  92. };
  93. class result_discriminant
  94. {
  95. int state_;
  96. public:
  97. enum kind_t
  98. {
  99. err_id_zero = 0,
  100. err_id = 1,
  101. err_id_capture_list = 2,
  102. val = 3
  103. };
  104. explicit result_discriminant( error_id id ) noexcept:
  105. state_(id.value())
  106. {
  107. BOOST_LEAF_ASSERT(state_ == 0 || (state_&3) == 1);
  108. BOOST_LEAF_ASSERT(kind() == err_id_zero || kind() == err_id);
  109. }
  110. #if BOOST_LEAF_CFG_CAPTURE
  111. explicit result_discriminant( int err_id, detail::capture_list const & ) noexcept:
  112. state_((err_id&~3) | 2)
  113. {
  114. BOOST_LEAF_ASSERT((err_id&3) == 1);
  115. BOOST_LEAF_ASSERT(kind() == err_id_capture_list);
  116. }
  117. #endif
  118. struct kind_val { };
  119. explicit result_discriminant( kind_val ) noexcept:
  120. state_(val)
  121. {
  122. BOOST_LEAF_ASSERT((state_&3) == 3);
  123. BOOST_LEAF_ASSERT(kind() == val);
  124. }
  125. kind_t kind() const noexcept
  126. {
  127. return kind_t(state_&3);
  128. }
  129. error_id get_error_id() const noexcept
  130. {
  131. BOOST_LEAF_ASSERT(kind() == err_id_zero || kind() == err_id || kind() == err_id_capture_list);
  132. return make_error_id(int((state_&~3)|1));
  133. }
  134. };
  135. }
  136. ////////////////////////////////////////
  137. template <class T>
  138. class BOOST_LEAF_SYMBOL_VISIBLE BOOST_LEAF_ATTRIBUTE_NODISCARD result
  139. {
  140. template <class U>
  141. friend class result;
  142. friend class detail::dynamic_allocator;
  143. #if BOOST_LEAF_CFG_CAPTURE
  144. using capture_list = detail::capture_list;
  145. #endif
  146. using result_discriminant = detail::result_discriminant;
  147. using stored_type = typename detail::stored<T>::type;
  148. using value_no_ref = typename detail::stored<T>::value_no_ref;
  149. using value_no_ref_const = typename detail::stored<T>::value_no_ref_const;
  150. using value_ref = typename detail::stored<T>::value_ref;
  151. using value_cref = typename detail::stored<T>::value_cref;
  152. using value_rv_ref = typename detail::stored<T>::value_rv_ref;
  153. using value_rv_cref = typename detail::stored<T>::value_rv_cref;
  154. union
  155. {
  156. stored_type stored_;
  157. #if BOOST_LEAF_CFG_CAPTURE
  158. mutable capture_list cap_;
  159. #endif
  160. };
  161. result_discriminant what_;
  162. struct error_result
  163. {
  164. error_result( error_result && ) = default;
  165. error_result( error_result const & ) = delete;
  166. error_result & operator=( error_result const & ) = delete;
  167. result & r_;
  168. error_result( result & r ) noexcept:
  169. r_(r)
  170. {
  171. }
  172. template <class U>
  173. operator result<U>() noexcept
  174. {
  175. result_discriminant const what = r_.what_;
  176. switch(auto k = what.kind())
  177. {
  178. case result_discriminant::val:
  179. return result<U>(error_id());
  180. case result_discriminant::err_id_capture_list:
  181. #if BOOST_LEAF_CFG_CAPTURE
  182. return result<U>(what.get_error_id().value(), std::move(r_.cap_));
  183. #else
  184. BOOST_LEAF_ASSERT(0); // Possible ODR violation.
  185. #endif
  186. default:
  187. BOOST_LEAF_ASSERT(k == result_discriminant::err_id);
  188. case result_discriminant::err_id_zero:
  189. return result<U>(what.get_error_id());
  190. }
  191. }
  192. operator error_id() const noexcept
  193. {
  194. result_discriminant const what = r_.what_;
  195. return what.kind() == result_discriminant::val?
  196. error_id() :
  197. what.get_error_id();
  198. }
  199. };
  200. void destroy() const noexcept
  201. {
  202. switch(auto k = this->what_.kind())
  203. {
  204. default:
  205. BOOST_LEAF_ASSERT(k == result_discriminant::err_id);
  206. case result_discriminant::err_id_zero:
  207. break;
  208. case result_discriminant::err_id_capture_list:
  209. #if BOOST_LEAF_CFG_CAPTURE
  210. cap_.~capture_list();
  211. #else
  212. BOOST_LEAF_ASSERT(0); // Possible ODR violation.
  213. #endif
  214. break;
  215. case result_discriminant::val:
  216. stored_.~stored_type();
  217. }
  218. }
  219. template <class U>
  220. result_discriminant move_from( result<U> && x ) noexcept
  221. {
  222. auto x_what = x.what_;
  223. switch(auto k = x_what.kind())
  224. {
  225. default:
  226. BOOST_LEAF_ASSERT(k == result_discriminant::err_id);
  227. case result_discriminant::err_id_zero:
  228. break;
  229. case result_discriminant::err_id_capture_list:
  230. #if BOOST_LEAF_CFG_CAPTURE
  231. (void) new(&cap_) capture_list(std::move(x.cap_));
  232. #else
  233. BOOST_LEAF_ASSERT(0); // Possible ODR violation.
  234. #endif
  235. break;
  236. case result_discriminant::val:
  237. (void) new(&stored_) stored_type(std::move(x.stored_));
  238. }
  239. return x_what;
  240. }
  241. error_id get_error_id() const noexcept
  242. {
  243. BOOST_LEAF_ASSERT(what_.kind() != result_discriminant::val);
  244. return what_.get_error_id();
  245. }
  246. stored_type const * get() const noexcept
  247. {
  248. return has_value() ? &stored_ : nullptr;
  249. }
  250. stored_type * get() noexcept
  251. {
  252. return has_value() ? &stored_ : nullptr;
  253. }
  254. protected:
  255. #if BOOST_LEAF_CFG_CAPTURE
  256. result( int err_id, detail::capture_list && cap ) noexcept:
  257. cap_(std::move(cap)),
  258. what_(err_id, cap)
  259. {
  260. }
  261. #endif
  262. void enforce_value_state() const
  263. {
  264. switch( what_.kind() )
  265. {
  266. case result_discriminant::err_id_capture_list:
  267. #if BOOST_LEAF_CFG_CAPTURE
  268. cap_.unload(what_.get_error_id().value());
  269. #else
  270. BOOST_LEAF_ASSERT(0); // Possible ODR violation.
  271. #endif
  272. case result_discriminant::err_id_zero:
  273. case result_discriminant::err_id:
  274. throw_exception(get_error_id(), bad_result{});
  275. case result_discriminant::val:
  276. break;
  277. }
  278. }
  279. template <class U>
  280. void move_assign( result<U> && x ) noexcept
  281. {
  282. destroy();
  283. what_ = move_from(std::move(x));
  284. }
  285. template <class CharT, class Traits>
  286. void print_error_result(std::basic_ostream<CharT, Traits> & os) const
  287. {
  288. result_discriminant const what = what_;
  289. BOOST_LEAF_ASSERT(what.kind() != result_discriminant::val);
  290. error_id const err_id = what.get_error_id();
  291. os << "Error serial #" << err_id;
  292. if( what.kind() == result_discriminant::err_id_capture_list )
  293. {
  294. #if BOOST_LEAF_CFG_CAPTURE
  295. char const * prefix = "\nCaptured:";
  296. cap_.print(os, err_id, prefix);
  297. os << "\n";
  298. #else
  299. BOOST_LEAF_ASSERT(0); // Possible ODR violation.
  300. #endif
  301. }
  302. }
  303. public:
  304. using value_type = T;
  305. // NOTE: Copy constructor implicitly deleted.
  306. result( result && x ) noexcept:
  307. what_(move_from(std::move(x)))
  308. {
  309. }
  310. template <class U, class = typename std::enable_if<std::is_convertible<U, T>::value>::type>
  311. result( result<U> && x ) noexcept:
  312. what_(move_from(std::move(x)))
  313. {
  314. }
  315. result():
  316. stored_(stored_type()),
  317. what_(result_discriminant::kind_val{})
  318. {
  319. }
  320. result( value_no_ref && v ) noexcept:
  321. stored_(std::forward<value_no_ref>(v)),
  322. what_(result_discriminant::kind_val{})
  323. {
  324. }
  325. result( value_no_ref const & v ):
  326. stored_(v),
  327. what_(result_discriminant::kind_val{})
  328. {
  329. }
  330. template<class... A, class = typename std::enable_if<std::is_constructible<T, A...>::value && sizeof...(A) >= 2>::type>
  331. result( A && ... a ) noexcept:
  332. stored_(std::forward<A>(a)...),
  333. what_(result_discriminant::kind_val{})
  334. {
  335. }
  336. result( error_id err ) noexcept:
  337. what_(err)
  338. {
  339. }
  340. #if defined(BOOST_STRICT_CONFIG) || !defined(__clang__)
  341. // This should be the default implementation, but std::is_convertible
  342. // breaks under COMPILER=/usr/bin/clang++ CXXSTD=11 clang 3.3.
  343. // On the other hand, the workaround exposes a rather severe bug in
  344. //__GNUC__ under 11: https://github.com/boostorg/leaf/issues/25.
  345. // SFINAE: T can be initialized with an A, e.g. result<std::string>("literal").
  346. template<class A, class = typename std::enable_if<std::is_constructible<T, A>::value && std::is_convertible<A, T>::value>::type>
  347. result( A && a ) noexcept:
  348. stored_(std::forward<A>(a)),
  349. what_(result_discriminant::kind_val{})
  350. {
  351. }
  352. #else
  353. private:
  354. static int init_T_with_A( T && );
  355. public:
  356. // SFINAE: T can be initialized with an A, e.g. result<std::string>("literal").
  357. template <class A>
  358. result( A && a, decltype(init_T_with_A(std::forward<A>(a))) * = nullptr ):
  359. stored_(std::forward<A>(a)),
  360. what_(result_discriminant::kind_val{})
  361. {
  362. }
  363. #endif
  364. #if BOOST_LEAF_CFG_STD_SYSTEM_ERROR
  365. result( std::error_code const & ec ) noexcept:
  366. what_(error_id(ec))
  367. {
  368. }
  369. template <class Enum, class = typename std::enable_if<std::is_error_code_enum<Enum>::value, int>::type>
  370. result( Enum e ) noexcept:
  371. what_(error_id(e))
  372. {
  373. }
  374. #endif
  375. ~result() noexcept
  376. {
  377. destroy();
  378. }
  379. // NOTE: Assignment operator implicitly deleted.
  380. result & operator=( result && x ) noexcept
  381. {
  382. move_assign(std::move(x));
  383. return *this;
  384. }
  385. template <class U, class = typename std::enable_if<std::is_convertible<U, T>::value>::type>
  386. result & operator=( result<U> && x ) noexcept
  387. {
  388. move_assign(std::move(x));
  389. return *this;
  390. }
  391. bool has_value() const noexcept
  392. {
  393. return what_.kind() == result_discriminant::val;
  394. }
  395. bool has_error() const noexcept
  396. {
  397. return !has_value();
  398. }
  399. explicit operator bool() const noexcept
  400. {
  401. return has_value();
  402. }
  403. #ifdef BOOST_LEAF_NO_CXX11_REF_QUALIFIERS
  404. value_cref value() const
  405. {
  406. enforce_value_state();
  407. return stored_;
  408. }
  409. value_ref value()
  410. {
  411. enforce_value_state();
  412. return stored_;
  413. }
  414. #else
  415. value_cref value() const &
  416. {
  417. enforce_value_state();
  418. return stored_;
  419. }
  420. value_ref value() &
  421. {
  422. enforce_value_state();
  423. return stored_;
  424. }
  425. value_rv_cref value() const &&
  426. {
  427. enforce_value_state();
  428. return std::move(stored_);
  429. }
  430. value_rv_ref value() &&
  431. {
  432. enforce_value_state();
  433. return std::move(stored_);
  434. }
  435. #endif
  436. value_no_ref_const * operator->() const noexcept
  437. {
  438. return has_value() ? detail::stored<T>::cptr(stored_) : nullptr;
  439. }
  440. value_no_ref * operator->() noexcept
  441. {
  442. return has_value() ? detail::stored<T>::ptr(stored_) : nullptr;
  443. }
  444. #ifdef BOOST_LEAF_NO_CXX11_REF_QUALIFIERS
  445. value_cref operator*() const noexcept
  446. {
  447. auto p = get();
  448. BOOST_LEAF_ASSERT(p != nullptr);
  449. return *p;
  450. }
  451. value_ref operator*() noexcept
  452. {
  453. auto p = get();
  454. BOOST_LEAF_ASSERT(p != nullptr);
  455. return *p;
  456. }
  457. #else
  458. value_cref operator*() const & noexcept
  459. {
  460. auto p = get();
  461. BOOST_LEAF_ASSERT(p != nullptr);
  462. return *p;
  463. }
  464. value_ref operator*() & noexcept
  465. {
  466. auto p = get();
  467. BOOST_LEAF_ASSERT(p != nullptr);
  468. return *p;
  469. }
  470. value_rv_cref operator*() const && noexcept
  471. {
  472. auto p = get();
  473. BOOST_LEAF_ASSERT(p != nullptr);
  474. return std::move(*p);
  475. }
  476. value_rv_ref operator*() && noexcept
  477. {
  478. auto p = get();
  479. BOOST_LEAF_ASSERT(p != nullptr);
  480. return std::move(*p);
  481. }
  482. #endif
  483. error_result error() noexcept
  484. {
  485. return error_result{*this};
  486. }
  487. template <class... Item>
  488. error_id load( Item && ... item ) noexcept
  489. {
  490. return error_id(error()).load(std::forward<Item>(item)...);
  491. }
  492. void unload()
  493. {
  494. #if BOOST_LEAF_CFG_CAPTURE
  495. if( what_.kind() == result_discriminant::err_id_capture_list )
  496. cap_.unload(what_.get_error_id().value());
  497. #endif
  498. }
  499. template <class CharT, class Traits>
  500. friend std::ostream & operator<<( std::basic_ostream<CharT, Traits> & os, result const & r )
  501. {
  502. if( r.what_.kind() == result_discriminant::val )
  503. detail::print_result_value(os, r.value());
  504. else
  505. r.print_error_result(os);
  506. return os;
  507. }
  508. };
  509. ////////////////////////////////////////
  510. namespace detail
  511. {
  512. struct void_ { };
  513. }
  514. template <>
  515. class BOOST_LEAF_SYMBOL_VISIBLE BOOST_LEAF_ATTRIBUTE_NODISCARD result<void>:
  516. result<detail::void_>
  517. {
  518. template <class U>
  519. friend class result;
  520. friend class detail::dynamic_allocator;
  521. using result_discriminant = detail::result_discriminant;
  522. using void_ = detail::void_;
  523. using base = result<void_>;
  524. #if BOOST_LEAF_CFG_CAPTURE
  525. result( int err_id, detail::capture_list && cap ) noexcept:
  526. base(err_id, std::move(cap))
  527. {
  528. }
  529. #endif
  530. public:
  531. using value_type = void;
  532. // NOTE: Copy constructor implicitly deleted.
  533. result( result && x ) noexcept:
  534. base(std::move(x))
  535. {
  536. }
  537. result() noexcept
  538. {
  539. }
  540. result( error_id err ) noexcept:
  541. base(err)
  542. {
  543. }
  544. #if BOOST_LEAF_CFG_STD_SYSTEM_ERROR
  545. result( std::error_code const & ec ) noexcept:
  546. base(ec)
  547. {
  548. }
  549. template <class Enum, class = typename std::enable_if<std::is_error_code_enum<Enum>::value, int>::type>
  550. result( Enum e ) noexcept:
  551. base(e)
  552. {
  553. }
  554. #endif
  555. ~result() noexcept
  556. {
  557. }
  558. // NOTE: Assignment operator implicitly deleted.
  559. result & operator=( result && x ) noexcept
  560. {
  561. base::move_assign(std::move(x));
  562. return *this;
  563. }
  564. void value() const
  565. {
  566. base::enforce_value_state();
  567. }
  568. void const * operator->() const noexcept
  569. {
  570. return base::operator->();
  571. }
  572. void * operator->() noexcept
  573. {
  574. return base::operator->();
  575. }
  576. void operator*() const noexcept
  577. {
  578. BOOST_LEAF_ASSERT(has_value());
  579. }
  580. template <class CharT, class Traits>
  581. friend std::ostream & operator<<( std::basic_ostream<CharT, Traits> & os, result const & r )
  582. {
  583. if( r )
  584. os << "No error";
  585. else
  586. r.print_error_result(os);
  587. return os;
  588. }
  589. using base::operator=;
  590. using base::operator bool;
  591. using base::get_error_id;
  592. using base::error;
  593. using base::load;
  594. using base::unload;
  595. };
  596. ////////////////////////////////////////
  597. template <class R>
  598. struct is_result_type;
  599. template <class T>
  600. struct is_result_type<result<T>>: std::true_type
  601. {
  602. };
  603. } }
  604. #endif // BOOST_LEAF_RESULT_HPP_INCLUDED