optional.hpp 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417
  1. /*!
  2. @file
  3. Defines `boost::hana::optional`.
  4. Copyright Louis Dionne 2013-2022
  5. Distributed under the Boost Software License, Version 1.0.
  6. (See accompanying file LICENSE.md or copy at http://boost.org/LICENSE_1_0.txt)
  7. */
  8. #ifndef BOOST_HANA_OPTIONAL_HPP
  9. #define BOOST_HANA_OPTIONAL_HPP
  10. #include <boost/hana/fwd/optional.hpp>
  11. #include <boost/hana/bool.hpp>
  12. #include <boost/hana/config.hpp>
  13. #include <boost/hana/core/tag_of.hpp>
  14. #include <boost/hana/detail/decay.hpp>
  15. #include <boost/hana/detail/operators/adl.hpp>
  16. #include <boost/hana/detail/operators/comparable.hpp>
  17. #include <boost/hana/detail/operators/monad.hpp>
  18. #include <boost/hana/detail/operators/orderable.hpp>
  19. #include <boost/hana/detail/wrong.hpp>
  20. #include <boost/hana/functional/partial.hpp>
  21. #include <boost/hana/fwd/any_of.hpp>
  22. #include <boost/hana/fwd/ap.hpp>
  23. #include <boost/hana/fwd/concat.hpp>
  24. #include <boost/hana/fwd/core/make.hpp>
  25. #include <boost/hana/fwd/empty.hpp>
  26. #include <boost/hana/fwd/equal.hpp>
  27. #include <boost/hana/fwd/find_if.hpp>
  28. #include <boost/hana/fwd/flatten.hpp>
  29. #include <boost/hana/fwd/less.hpp>
  30. #include <boost/hana/fwd/lift.hpp>
  31. #include <boost/hana/fwd/transform.hpp>
  32. #include <boost/hana/fwd/type.hpp>
  33. #include <boost/hana/fwd/unpack.hpp>
  34. #include <cstddef> // std::nullptr_t
  35. #include <type_traits>
  36. #include <utility>
  37. namespace boost { namespace hana {
  38. //////////////////////////////////////////////////////////////////////////
  39. // optional<>
  40. //////////////////////////////////////////////////////////////////////////
  41. namespace detail {
  42. template <typename T, typename = typename hana::tag_of<T>::type>
  43. struct nested_type { };
  44. template <typename T>
  45. struct nested_type<T, type_tag> { using type = typename T::type; };
  46. }
  47. template <typename T>
  48. struct optional<T> : detail::operators::adl<>, detail::nested_type<T> {
  49. // 5.3.1, Constructors
  50. constexpr optional() = default;
  51. constexpr optional(optional const&) = default;
  52. constexpr optional(optional&&) = default;
  53. constexpr optional(T const& t)
  54. : value_(t)
  55. { }
  56. constexpr optional(T&& t)
  57. : value_(static_cast<T&&>(t))
  58. { }
  59. // 5.3.3, Assignment
  60. constexpr optional& operator=(optional const&) = default;
  61. constexpr optional& operator=(optional&&) = default;
  62. // 5.3.5, Observers
  63. constexpr T const* operator->() const { return &value_; }
  64. constexpr T* operator->() { return &value_; }
  65. constexpr T& value() & { return value_; }
  66. constexpr T const& value() const& { return value_; }
  67. constexpr T&& value() && { return static_cast<T&&>(value_); }
  68. constexpr T const&& value() const&& { return static_cast<T const&&>(value_); }
  69. constexpr T& operator*() & { return value_; }
  70. constexpr T const& operator*() const& { return value_; }
  71. constexpr T&& operator*() && { return static_cast<T&&>(value_); }
  72. constexpr T const&& operator*() const&& { return static_cast<T const&&>(value_); }
  73. template <typename U> constexpr T& value_or(U&&) & { return value_; }
  74. template <typename U> constexpr T const& value_or(U&&) const& { return value_; }
  75. template <typename U> constexpr T&& value_or(U&&) && { return static_cast<T&&>(value_); }
  76. template <typename U> constexpr T const&& value_or(U&&) const&& { return static_cast<T const&&>(value_); }
  77. // We leave this public because it simplifies the implementation, but
  78. // this should be considered private by users.
  79. T value_;
  80. };
  81. //! @cond
  82. template <typename ...dummy>
  83. constexpr auto optional<>::value() const {
  84. static_assert(detail::wrong<dummy...>{},
  85. "hana::optional::value() requires a non-empty optional");
  86. }
  87. template <typename ...dummy>
  88. constexpr auto optional<>::operator*() const {
  89. static_assert(detail::wrong<dummy...>{},
  90. "hana::optional::operator* requires a non-empty optional");
  91. }
  92. template <typename U>
  93. constexpr U&& optional<>::value_or(U&& u) const {
  94. return static_cast<U&&>(u);
  95. }
  96. template <typename T>
  97. constexpr auto make_just_t::operator()(T&& t) const {
  98. return hana::optional<typename detail::decay<T>::type>(static_cast<T&&>(t));
  99. }
  100. //! @endcond
  101. template <typename ...T>
  102. struct tag_of<optional<T...>> {
  103. using type = optional_tag;
  104. };
  105. //////////////////////////////////////////////////////////////////////////
  106. // make<optional_tag>
  107. //////////////////////////////////////////////////////////////////////////
  108. template <>
  109. struct make_impl<optional_tag> {
  110. template <typename X>
  111. static constexpr auto apply(X&& x)
  112. { return hana::just(static_cast<X&&>(x)); }
  113. static constexpr auto apply()
  114. { return hana::nothing; }
  115. };
  116. //////////////////////////////////////////////////////////////////////////
  117. // Operators
  118. //////////////////////////////////////////////////////////////////////////
  119. namespace detail {
  120. template <>
  121. struct comparable_operators<optional_tag> {
  122. static constexpr bool value = true;
  123. };
  124. template <>
  125. struct orderable_operators<optional_tag> {
  126. static constexpr bool value = true;
  127. };
  128. template <>
  129. struct monad_operators<optional_tag> {
  130. static constexpr bool value = true;
  131. };
  132. }
  133. //////////////////////////////////////////////////////////////////////////
  134. // is_just and is_nothing
  135. //////////////////////////////////////////////////////////////////////////
  136. //! @cond
  137. template <typename ...T>
  138. constexpr auto is_just_t::operator()(optional<T...> const&) const
  139. { return hana::bool_c<sizeof...(T) != 0>; }
  140. template <typename ...T>
  141. constexpr auto is_nothing_t::operator()(optional<T...> const&) const
  142. { return hana::bool_c<sizeof...(T) == 0>; }
  143. //! @endcond
  144. //////////////////////////////////////////////////////////////////////////
  145. // sfinae
  146. //////////////////////////////////////////////////////////////////////////
  147. namespace detail {
  148. struct sfinae_impl {
  149. template <typename F, typename ...X, typename = decltype(
  150. std::declval<F>()(std::declval<X>()...)
  151. )>
  152. constexpr decltype(auto) operator()(int, F&& f, X&& ...x) const {
  153. using Return = decltype(static_cast<F&&>(f)(static_cast<X&&>(x)...));
  154. static_assert(!std::is_same<Return, void>::value,
  155. "hana::sfinae(f)(args...) requires f(args...) to be non-void");
  156. return hana::just(static_cast<F&&>(f)(static_cast<X&&>(x)...));
  157. }
  158. template <typename F, typename ...X>
  159. constexpr auto operator()(long, F&&, X&& ...) const
  160. { return hana::nothing; }
  161. };
  162. }
  163. //! @cond
  164. template <typename F>
  165. constexpr decltype(auto) sfinae_t::operator()(F&& f) const {
  166. return hana::partial(detail::sfinae_impl{}, int{},
  167. static_cast<F&&>(f));
  168. }
  169. //! @endcond
  170. //////////////////////////////////////////////////////////////////////////
  171. // Comparable
  172. //////////////////////////////////////////////////////////////////////////
  173. template <>
  174. struct equal_impl<optional_tag, optional_tag> {
  175. template <typename T, typename U>
  176. static constexpr auto apply(hana::optional<T> const& t, hana::optional<U> const& u)
  177. { return hana::equal(t.value_, u.value_); }
  178. static constexpr hana::true_ apply(hana::optional<> const&, hana::optional<> const&)
  179. { return {}; }
  180. template <typename T, typename U>
  181. static constexpr hana::false_ apply(T const&, U const&)
  182. { return {}; }
  183. };
  184. //////////////////////////////////////////////////////////////////////////
  185. // Orderable
  186. //////////////////////////////////////////////////////////////////////////
  187. template <>
  188. struct less_impl<optional_tag, optional_tag> {
  189. template <typename T>
  190. static constexpr hana::true_ apply(hana::optional<> const&, hana::optional<T> const&)
  191. { return {}; }
  192. static constexpr hana::false_ apply(hana::optional<> const&, hana::optional<> const&)
  193. { return {}; }
  194. template <typename T>
  195. static constexpr hana::false_ apply(hana::optional<T> const&, hana::optional<> const&)
  196. { return {}; }
  197. template <typename T, typename U>
  198. static constexpr auto apply(hana::optional<T> const& x, hana::optional<U> const& y)
  199. { return hana::less(x.value_, y.value_); }
  200. };
  201. //////////////////////////////////////////////////////////////////////////
  202. // Functor
  203. //////////////////////////////////////////////////////////////////////////
  204. template <>
  205. struct transform_impl<optional_tag> {
  206. template <typename F>
  207. static constexpr auto apply(optional<> const&, F&&)
  208. { return hana::nothing; }
  209. template <typename T, typename F>
  210. static constexpr auto apply(optional<T> const& opt, F&& f)
  211. { return hana::just(static_cast<F&&>(f)(opt.value_)); }
  212. template <typename T, typename F>
  213. static constexpr auto apply(optional<T>& opt, F&& f)
  214. { return hana::just(static_cast<F&&>(f)(opt.value_)); }
  215. template <typename T, typename F>
  216. static constexpr auto apply(optional<T>&& opt, F&& f)
  217. { return hana::just(static_cast<F&&>(f)(static_cast<T&&>(opt.value_))); }
  218. };
  219. //////////////////////////////////////////////////////////////////////////
  220. // Applicative
  221. //////////////////////////////////////////////////////////////////////////
  222. template <>
  223. struct lift_impl<optional_tag> {
  224. template <typename X>
  225. static constexpr auto apply(X&& x)
  226. { return hana::just(static_cast<X&&>(x)); }
  227. };
  228. template <>
  229. struct ap_impl<optional_tag> {
  230. template <typename F, typename X>
  231. static constexpr auto ap_helper(F&&, X&&, ...)
  232. { return hana::nothing; }
  233. template <typename F, typename X>
  234. static constexpr auto ap_helper(F&& f, X&& x, hana::true_, hana::true_)
  235. { return hana::just(static_cast<F&&>(f).value_(static_cast<X&&>(x).value_)); }
  236. template <typename F, typename X>
  237. static constexpr auto apply(F&& f, X&& x) {
  238. return ap_impl::ap_helper(static_cast<F&&>(f), static_cast<X&&>(x),
  239. hana::is_just(f), hana::is_just(x));
  240. }
  241. };
  242. //////////////////////////////////////////////////////////////////////////
  243. // Monad
  244. //////////////////////////////////////////////////////////////////////////
  245. template <>
  246. struct flatten_impl<optional_tag> {
  247. static constexpr auto apply(optional<> const&)
  248. { return hana::nothing; }
  249. static constexpr auto apply(optional<optional<>> const&)
  250. { return hana::nothing; }
  251. template <typename T>
  252. static constexpr auto apply(optional<optional<T>> const& opt)
  253. { return hana::just(opt.value_.value_); }
  254. template <typename T>
  255. static constexpr auto apply(optional<optional<T>>&& opt)
  256. { return hana::just(static_cast<T&&>(opt.value_.value_)); }
  257. };
  258. //////////////////////////////////////////////////////////////////////////
  259. // MonadPlus
  260. //////////////////////////////////////////////////////////////////////////
  261. template <>
  262. struct concat_impl<optional_tag> {
  263. template <typename Y>
  264. static constexpr auto apply(hana::optional<>&, Y&& y)
  265. { return static_cast<Y&&>(y); }
  266. template <typename Y>
  267. static constexpr auto apply(hana::optional<>&&, Y&& y)
  268. { return static_cast<Y&&>(y); }
  269. template <typename Y>
  270. static constexpr auto apply(hana::optional<> const&, Y&& y)
  271. { return static_cast<Y&&>(y); }
  272. template <typename X, typename Y>
  273. static constexpr auto apply(X&& x, Y&&)
  274. { return static_cast<X&&>(x); }
  275. };
  276. template <>
  277. struct empty_impl<optional_tag> {
  278. static constexpr auto apply()
  279. { return hana::nothing; }
  280. };
  281. //////////////////////////////////////////////////////////////////////////
  282. // Foldable
  283. //////////////////////////////////////////////////////////////////////////
  284. template <>
  285. struct unpack_impl<optional_tag> {
  286. template <typename T, typename F>
  287. static constexpr decltype(auto) apply(optional<T>&& opt, F&& f)
  288. { return static_cast<F&&>(f)(static_cast<T&&>(opt.value_)); }
  289. template <typename T, typename F>
  290. static constexpr decltype(auto) apply(optional<T> const& opt, F&& f)
  291. { return static_cast<F&&>(f)(opt.value_); }
  292. template <typename T, typename F>
  293. static constexpr decltype(auto) apply(optional<T>& opt, F&& f)
  294. { return static_cast<F&&>(f)(opt.value_); }
  295. template <typename F>
  296. static constexpr decltype(auto) apply(optional<> const&, F&& f)
  297. { return static_cast<F&&>(f)(); }
  298. };
  299. //////////////////////////////////////////////////////////////////////////
  300. // Searchable
  301. //////////////////////////////////////////////////////////////////////////
  302. namespace detail {
  303. template <bool>
  304. struct optional_find_if {
  305. template <typename T>
  306. static constexpr auto apply(T const&)
  307. { return hana::nothing; }
  308. };
  309. template <>
  310. struct optional_find_if<true> {
  311. template <typename T>
  312. static constexpr auto apply(T&& t)
  313. { return hana::just(static_cast<T&&>(t)); }
  314. };
  315. }
  316. template <>
  317. struct find_if_impl<optional_tag> {
  318. template <typename T, typename Pred>
  319. static constexpr auto apply(hana::optional<T> const& opt, Pred&& pred) {
  320. constexpr bool found = decltype(static_cast<Pred&&>(pred)(opt.value_))::value;
  321. return detail::optional_find_if<found>::apply(opt.value_);
  322. }
  323. template <typename T, typename Pred>
  324. static constexpr auto apply(hana::optional<T>& opt, Pred&& pred) {
  325. constexpr bool found = decltype(static_cast<Pred&&>(pred)(opt.value_))::value;
  326. return detail::optional_find_if<found>::apply(opt.value_);
  327. }
  328. template <typename T, typename Pred>
  329. static constexpr auto apply(hana::optional<T>&& opt, Pred&& pred) {
  330. constexpr bool found = decltype(
  331. static_cast<Pred&&>(pred)(static_cast<T&&>(opt.value_))
  332. )::value;
  333. return detail::optional_find_if<found>::apply(static_cast<T&&>(opt.value_));
  334. }
  335. template <typename Pred>
  336. static constexpr auto apply(hana::optional<> const&, Pred&&)
  337. { return hana::nothing; }
  338. };
  339. template <>
  340. struct any_of_impl<optional_tag> {
  341. template <typename T, typename Pred>
  342. static constexpr auto apply(hana::optional<T> const& opt, Pred&& pred)
  343. { return static_cast<Pred&&>(pred)(opt.value_); }
  344. template <typename Pred>
  345. static constexpr hana::false_ apply(hana::optional<> const&, Pred&&)
  346. { return {}; }
  347. };
  348. }} // end namespace boost::hana
  349. #endif // !BOOST_HANA_OPTIONAL_HPP