result.hpp 14 KB

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