result.hpp 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486
  1. #ifndef BOOST_LEAF_RESULT_HPP_INCLUDED
  2. #define BOOST_LEAF_RESULT_HPP_INCLUDED
  3. /// Copyright (c) 2018-2021 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. #ifndef BOOST_LEAF_ENABLE_WARNINGS ///
  7. # if defined(_MSC_VER) ///
  8. # pragma warning(push,1) ///
  9. # elif defined(__clang__) ///
  10. # pragma clang system_header ///
  11. # elif (__GNUC__*100+__GNUC_MINOR__>301) ///
  12. # pragma GCC system_header ///
  13. # endif ///
  14. #endif ///
  15. #include <boost/leaf/error.hpp>
  16. #include <climits>
  17. namespace boost { namespace leaf {
  18. class bad_result:
  19. public std::exception,
  20. public error_id
  21. {
  22. char const * what() const noexcept final override
  23. {
  24. return "boost::leaf::bad_result";
  25. }
  26. public:
  27. explicit bad_result( error_id id ) noexcept:
  28. error_id(id)
  29. {
  30. BOOST_LEAF_ASSERT(value());
  31. }
  32. };
  33. ////////////////////////////////////////
  34. namespace leaf_detail
  35. {
  36. template <class T>
  37. struct stored
  38. {
  39. using type = T;
  40. using value_type = T;
  41. using value_type_const = T const;
  42. using value_cref = T const &;
  43. using value_ref = T &;
  44. using value_rv_cref = T const &&;
  45. using value_rv_ref = T &&;
  46. };
  47. template <class T>
  48. struct stored<T &>
  49. {
  50. using type = std::reference_wrapper<T>;
  51. using value_type_const = T;
  52. using value_type = T;
  53. using value_ref = T &;
  54. using value_cref = T &;
  55. using value_rv_ref = T &;
  56. using value_rv_cref = T &;
  57. };
  58. class result_discriminant
  59. {
  60. unsigned state_;
  61. public:
  62. enum kind_t
  63. {
  64. no_error = 0,
  65. err_id = 1,
  66. ctx_ptr = 2,
  67. val = 3
  68. };
  69. explicit result_discriminant( error_id id ) noexcept:
  70. state_(id.value())
  71. {
  72. BOOST_LEAF_ASSERT(state_==0 || (state_&3)==1);
  73. }
  74. struct kind_val { };
  75. explicit result_discriminant( kind_val ) noexcept:
  76. state_(val)
  77. {
  78. }
  79. struct kind_ctx_ptr { };
  80. explicit result_discriminant( kind_ctx_ptr ) noexcept:
  81. state_(ctx_ptr)
  82. {
  83. }
  84. kind_t kind() const noexcept
  85. {
  86. return kind_t(state_&3);
  87. }
  88. error_id get_error_id() const noexcept
  89. {
  90. BOOST_LEAF_ASSERT(kind()==no_error || kind()==err_id);
  91. return make_error_id(state_);
  92. }
  93. };
  94. }
  95. ////////////////////////////////////////
  96. template <class T>
  97. class result
  98. {
  99. template <class U>
  100. friend class result;
  101. using result_discriminant = leaf_detail::result_discriminant;
  102. struct error_result
  103. {
  104. error_result( error_result && ) = default;
  105. error_result( error_result const & ) = delete;
  106. error_result & operator=( error_result const & ) = delete;
  107. result & r_;
  108. error_result( result & r ) noexcept:
  109. r_(r)
  110. {
  111. }
  112. template <class U>
  113. operator result<U>() noexcept
  114. {
  115. switch(r_.what_.kind())
  116. {
  117. case result_discriminant::val:
  118. return result<U>(error_id());
  119. case result_discriminant::ctx_ptr:
  120. return result<U>(std::move(r_.ctx_));
  121. default:
  122. return result<U>(std::move(r_.what_));
  123. }
  124. }
  125. operator error_id() noexcept
  126. {
  127. switch(r_.what_.kind())
  128. {
  129. case result_discriminant::val:
  130. return error_id();
  131. case result_discriminant::ctx_ptr:
  132. {
  133. error_id captured_id = r_.ctx_->propagate_captured_errors();
  134. leaf_detail::id_factory<>::current_id = captured_id.value();
  135. return captured_id;
  136. }
  137. default:
  138. return r_.what_.get_error_id();
  139. }
  140. }
  141. };
  142. using stored_type = typename leaf_detail::stored<T>::type;
  143. using value_type = typename leaf_detail::stored<T>::value_type;
  144. using value_type_const = typename leaf_detail::stored<T>::value_type_const;
  145. using value_ref = typename leaf_detail::stored<T>::value_ref;
  146. using value_cref = typename leaf_detail::stored<T>::value_cref;
  147. using value_rv_ref = typename leaf_detail::stored<T>::value_rv_ref;
  148. using value_rv_cref = typename leaf_detail::stored<T>::value_rv_cref;
  149. union
  150. {
  151. stored_type stored_;
  152. context_ptr ctx_;
  153. };
  154. result_discriminant what_;
  155. void destroy() const noexcept
  156. {
  157. switch(this->what_.kind())
  158. {
  159. case result_discriminant::val:
  160. stored_.~stored_type();
  161. break;
  162. case result_discriminant::ctx_ptr:
  163. BOOST_LEAF_ASSERT(!ctx_ || ctx_->captured_id_);
  164. ctx_.~context_ptr();
  165. default:
  166. break;
  167. }
  168. }
  169. template <class U>
  170. result_discriminant move_from( result<U> && x ) noexcept
  171. {
  172. auto x_what = x.what_;
  173. switch(x_what.kind())
  174. {
  175. case result_discriminant::val:
  176. (void) new(&stored_) stored_type(std::move(x.stored_));
  177. break;
  178. case result_discriminant::ctx_ptr:
  179. BOOST_LEAF_ASSERT(!x.ctx_ || x.ctx_->captured_id_);
  180. (void) new(&ctx_) context_ptr(std::move(x.ctx_));
  181. default:
  182. break;
  183. }
  184. return x_what;
  185. }
  186. result( result_discriminant && what ) noexcept:
  187. what_(std::move(what))
  188. {
  189. BOOST_LEAF_ASSERT(what_.kind()==result_discriminant::err_id || what_.kind()==result_discriminant::no_error);
  190. }
  191. error_id get_error_id() const noexcept
  192. {
  193. BOOST_LEAF_ASSERT(what_.kind()!=result_discriminant::val);
  194. return what_.kind()==result_discriminant::ctx_ptr ? ctx_->captured_id_ : what_.get_error_id();
  195. }
  196. static int init_T_with_U( T && );
  197. protected:
  198. void enforce_value_state() const
  199. {
  200. if( what_.kind() != result_discriminant::val )
  201. ::boost::leaf::throw_exception(bad_result(get_error_id()));
  202. }
  203. public:
  204. result( result && x ) noexcept:
  205. what_(move_from(std::move(x)))
  206. {
  207. }
  208. template <class U>
  209. result( result<U> && x ) noexcept:
  210. what_(move_from(std::move(x)))
  211. {
  212. }
  213. result():
  214. stored_(stored_type()),
  215. what_(result_discriminant::kind_val{})
  216. {
  217. }
  218. result( value_type && v ) noexcept:
  219. stored_(std::forward<value_type>(v)),
  220. what_(result_discriminant::kind_val{})
  221. {
  222. }
  223. result( value_type const & v ):
  224. stored_(v),
  225. what_(result_discriminant::kind_val{})
  226. {
  227. }
  228. result( error_id err ) noexcept:
  229. what_(err)
  230. {
  231. }
  232. // SFINAE:
  233. // T can be initialized with a U, e.g. result<std::string>("literal").
  234. // Not using is_constructible on purpose, bug with
  235. // COMPILER=/usr/bin/clang++ CXXSTD=11 clang 3.3.
  236. template <class U>
  237. result( U && u, decltype(init_T_with_U(std::forward<U>(u))) * = 0 ):
  238. stored_(std::forward<U>(u)),
  239. what_(result_discriminant::kind_val{})
  240. {
  241. }
  242. result( std::error_code const & ec ) noexcept:
  243. what_(error_id(ec))
  244. {
  245. }
  246. template <class Enum>
  247. result( Enum e, typename std::enable_if<std::is_error_code_enum<Enum>::value, int>::type * = 0 ) noexcept:
  248. what_(error_id(e))
  249. {
  250. }
  251. result( context_ptr && ctx ) noexcept:
  252. ctx_(std::move(ctx)),
  253. what_(result_discriminant::kind_ctx_ptr{})
  254. {
  255. }
  256. ~result() noexcept
  257. {
  258. destroy();
  259. }
  260. result & operator=( result && x ) noexcept
  261. {
  262. destroy();
  263. what_ = move_from(std::move(x));
  264. return *this;
  265. }
  266. template <class U>
  267. result & operator=( result<U> && x ) noexcept
  268. {
  269. destroy();
  270. what_ = move_from(std::move(x));
  271. return *this;
  272. }
  273. explicit operator bool() const noexcept
  274. {
  275. return what_.kind() == result_discriminant::val;
  276. }
  277. value_cref value() const &
  278. {
  279. enforce_value_state();
  280. return stored_;
  281. }
  282. value_ref value() &
  283. {
  284. enforce_value_state();
  285. return stored_;
  286. }
  287. value_rv_cref value() const &&
  288. {
  289. enforce_value_state();
  290. return std::move(stored_);
  291. }
  292. value_rv_ref value() &&
  293. {
  294. enforce_value_state();
  295. return std::move(stored_);
  296. }
  297. value_cref operator*() const &
  298. {
  299. return value();
  300. }
  301. value_ref operator*() &
  302. {
  303. return value();
  304. }
  305. value_rv_cref operator*() const &&
  306. {
  307. return value();
  308. }
  309. value_rv_ref operator*() &&
  310. {
  311. return value();
  312. }
  313. value_type_const * operator->() const
  314. {
  315. return &value();
  316. }
  317. value_type * operator->()
  318. {
  319. return &value();
  320. }
  321. error_result error() noexcept
  322. {
  323. return error_result{*this};
  324. }
  325. template <class... Item>
  326. error_id load( Item && ... item ) noexcept
  327. {
  328. return error_id(error()).load(std::forward<Item>(item)...);
  329. }
  330. };
  331. ////////////////////////////////////////
  332. namespace leaf_detail
  333. {
  334. struct void_ { };
  335. }
  336. template <>
  337. class result<void>:
  338. result<leaf_detail::void_>
  339. {
  340. using result_discriminant = leaf_detail::result_discriminant;
  341. using void_ = leaf_detail::void_;
  342. using base = result<void_>;
  343. template <class U>
  344. friend class result;
  345. result( result_discriminant && what ) noexcept:
  346. base(std::move(what))
  347. {
  348. }
  349. public:
  350. using value_type = void;
  351. result( result && x ) noexcept:
  352. base(std::move(x))
  353. {
  354. }
  355. result() noexcept
  356. {
  357. }
  358. result( error_id err ) noexcept:
  359. base(err)
  360. {
  361. }
  362. result( std::error_code const & ec ) noexcept:
  363. base(ec)
  364. {
  365. }
  366. template <class Enum>
  367. result( Enum e, typename std::enable_if<std::is_error_code_enum<Enum>::value, Enum>::type * = 0 ) noexcept:
  368. base(e)
  369. {
  370. }
  371. result( context_ptr && ctx ) noexcept:
  372. base(std::move(ctx))
  373. {
  374. }
  375. ~result() noexcept
  376. {
  377. }
  378. void value() const
  379. {
  380. base::enforce_value_state();
  381. }
  382. using base::operator=;
  383. using base::operator bool;
  384. using base::get_error_id;
  385. using base::error;
  386. using base::load;
  387. };
  388. ////////////////////////////////////////
  389. template <class R>
  390. struct is_result_type;
  391. template <class T>
  392. struct is_result_type<result<T>>: std::true_type
  393. {
  394. };
  395. } }
  396. #if defined(_MSC_VER) && !defined(BOOST_LEAF_ENABLE_WARNINGS) ///
  397. #pragma warning(pop) ///
  398. #endif ///
  399. #endif