result.hpp 17 KB

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