result.hpp 17 KB

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