1 /*!
2 @file
3 Defines `boost::hana::optional`.
4 
5 @copyright Louis Dionne 2013-2017
6 Distributed under the Boost Software License, Version 1.0.
7 (See accompanying file LICENSE.md or copy at http://boost.org/LICENSE_1_0.txt)
8  */
9 
10 #ifndef BOOST_HANA_OPTIONAL_HPP
11 #define BOOST_HANA_OPTIONAL_HPP
12 
13 #include <boost/hana/fwd/optional.hpp>
14 
15 #include <boost/hana/bool.hpp>
16 #include <boost/hana/config.hpp>
17 #include <boost/hana/core/tag_of.hpp>
18 #include <boost/hana/detail/decay.hpp>
19 #include <boost/hana/detail/operators/adl.hpp>
20 #include <boost/hana/detail/operators/comparable.hpp>
21 #include <boost/hana/detail/operators/monad.hpp>
22 #include <boost/hana/detail/operators/orderable.hpp>
23 #include <boost/hana/detail/wrong.hpp>
24 #include <boost/hana/functional/partial.hpp>
25 #include <boost/hana/fwd/any_of.hpp>
26 #include <boost/hana/fwd/ap.hpp>
27 #include <boost/hana/fwd/concat.hpp>
28 #include <boost/hana/fwd/core/make.hpp>
29 #include <boost/hana/fwd/empty.hpp>
30 #include <boost/hana/fwd/equal.hpp>
31 #include <boost/hana/fwd/find_if.hpp>
32 #include <boost/hana/fwd/flatten.hpp>
33 #include <boost/hana/fwd/less.hpp>
34 #include <boost/hana/fwd/lift.hpp>
35 #include <boost/hana/fwd/transform.hpp>
36 #include <boost/hana/fwd/type.hpp>
37 #include <boost/hana/fwd/unpack.hpp>
38 
39 #include <cstddef> // std::nullptr_t
40 #include <type_traits>
41 #include <utility>
42 
43 
44 BOOST_HANA_NAMESPACE_BEGIN
45     //////////////////////////////////////////////////////////////////////////
46     // optional<>
47     //////////////////////////////////////////////////////////////////////////
48     namespace detail {
49         template <typename T, typename = typename hana::tag_of<T>::type>
50         struct nested_type { };
51 
52         template <typename T>
53         struct nested_type<T, type_tag> { using type = typename T::type; };
54     }
55 
56     template <typename T>
57     struct optional<T> : detail::operators::adl<>, detail::nested_type<T> {
58         // 5.3.1, Constructors
59         constexpr optional() = default;
60         constexpr optional(optional const&) = default;
61         constexpr optional(optional&&) = default;
62 
optionaloptional63         constexpr optional(T const& t)
64             : value_(t)
65         { }
66 
optionaloptional67         constexpr optional(T&& t)
68             : value_(static_cast<T&&>(t))
69         { }
70 
71         // 5.3.3, Assignment
72         constexpr optional& operator=(optional const&) = default;
73         constexpr optional& operator=(optional&&) = default;
74 
75         // 5.3.5, Observers
operator ->optional76         constexpr T const* operator->() const { return &value_; }
operator ->optional77         constexpr T* operator->() { return &value_; }
78 
valueoptional79         constexpr T&        value() & { return value_; }
valueoptional80         constexpr T const&  value() const& { return value_; }
valueoptional81         constexpr T&&       value() && { return static_cast<T&&>(value_); }
valueoptional82         constexpr T const&& value() const&& { return static_cast<T const&&>(value_); }
83 
operator *optional84         constexpr T&        operator*() & { return value_; }
operator *optional85         constexpr T const&  operator*() const& { return value_; }
operator *optional86         constexpr T&&       operator*() && { return static_cast<T&&>(value_); }
operator *optional87         constexpr T const&& operator*() const&& { return static_cast<T const&&>(value_); }
88 
value_oroptional89         template <typename U> constexpr T&        value_or(U&&) & { return value_; }
value_oroptional90         template <typename U> constexpr T const&  value_or(U&&) const& { return value_; }
value_oroptional91         template <typename U> constexpr T&&       value_or(U&&) && { return static_cast<T&&>(value_); }
value_oroptional92         template <typename U> constexpr T const&& value_or(U&&) const&& { return static_cast<T const&&>(value_); }
93 
94         // We leave this public because it simplifies the implementation, but
95         // this should be considered private by users.
96         T value_;
97     };
98 
99     //! @cond
100     template <typename ...dummy>
value() const101     constexpr auto optional<>::value() const {
102         static_assert(detail::wrong<dummy...>{},
103         "hana::optional::value() requires a non-empty optional");
104     }
105 
106     template <typename ...dummy>
operator *() const107     constexpr auto optional<>::operator*() const {
108         static_assert(detail::wrong<dummy...>{},
109         "hana::optional::operator* requires a non-empty optional");
110     }
111 
112     template <typename U>
value_or(U && u) const113     constexpr U&& optional<>::value_or(U&& u) const {
114         return static_cast<U&&>(u);
115     }
116 
117     template <typename T>
operator ()(T && t) const118     constexpr auto make_just_t::operator()(T&& t) const {
119         return hana::optional<typename detail::decay<T>::type>(static_cast<T&&>(t));
120     }
121     //! @endcond
122 
123     template <typename ...T>
124     struct tag_of<optional<T...>> {
125         using type = optional_tag;
126     };
127 
128     //////////////////////////////////////////////////////////////////////////
129     // make<optional_tag>
130     //////////////////////////////////////////////////////////////////////////
131     template <>
132     struct make_impl<optional_tag> {
133         template <typename X>
applymake_impl134         static constexpr auto apply(X&& x)
135         { return hana::just(static_cast<X&&>(x)); }
136 
applymake_impl137         static constexpr auto apply()
138         { return hana::nothing; }
139     };
140 
141     //////////////////////////////////////////////////////////////////////////
142     // Operators
143     //////////////////////////////////////////////////////////////////////////
144     namespace detail {
145         template <>
146         struct comparable_operators<optional_tag> {
147             static constexpr bool value = true;
148         };
149         template <>
150         struct orderable_operators<optional_tag> {
151             static constexpr bool value = true;
152         };
153         template <>
154         struct monad_operators<optional_tag> {
155             static constexpr bool value = true;
156         };
157     }
158 
159     //////////////////////////////////////////////////////////////////////////
160     // is_just and is_nothing
161     //////////////////////////////////////////////////////////////////////////
162     //! @cond
163     template <typename ...T>
operator ()(optional<T...> const &) const164     constexpr auto is_just_t::operator()(optional<T...> const&) const
165     { return hana::bool_c<sizeof...(T) != 0>; }
166 
167     template <typename ...T>
operator ()(optional<T...> const &) const168     constexpr auto is_nothing_t::operator()(optional<T...> const&) const
169     { return hana::bool_c<sizeof...(T) == 0>; }
170     //! @endcond
171 
172     //////////////////////////////////////////////////////////////////////////
173     // sfinae
174     //////////////////////////////////////////////////////////////////////////
175     namespace detail {
176         struct sfinae_impl {
177             template <typename F, typename ...X, typename = decltype(
178                 std::declval<F>()(std::declval<X>()...)
179             )>
operator ()detail::sfinae_impl180             constexpr decltype(auto) operator()(int, F&& f, X&& ...x) const {
181                 using Return = decltype(static_cast<F&&>(f)(static_cast<X&&>(x)...));
182                 static_assert(!std::is_same<Return, void>::value,
183                 "hana::sfinae(f)(args...) requires f(args...) to be non-void");
184 
185                 return hana::just(static_cast<F&&>(f)(static_cast<X&&>(x)...));
186             }
187 
188             template <typename F, typename ...X>
operator ()detail::sfinae_impl189             constexpr auto operator()(long, F&&, X&& ...) const
190             { return hana::nothing; }
191         };
192     }
193 
194     //! @cond
195     template <typename F>
operator ()(F && f) const196     constexpr decltype(auto) sfinae_t::operator()(F&& f) const {
197         return hana::partial(detail::sfinae_impl{}, int{},
198                              static_cast<F&&>(f));
199     }
200     //! @endcond
201 
202     //////////////////////////////////////////////////////////////////////////
203     // Comparable
204     //////////////////////////////////////////////////////////////////////////
205     template <>
206     struct equal_impl<optional_tag, optional_tag> {
207         template <typename T, typename U>
applyequal_impl208         static constexpr auto apply(hana::optional<T> const& t, hana::optional<U> const& u)
209         { return hana::equal(t.value_, u.value_); }
210 
applyequal_impl211         static constexpr hana::true_ apply(hana::optional<> const&, hana::optional<> const&)
212         { return {}; }
213 
214         template <typename T, typename U>
applyequal_impl215         static constexpr hana::false_ apply(T const&, U const&)
216         { return {}; }
217     };
218 
219     //////////////////////////////////////////////////////////////////////////
220     // Orderable
221     //////////////////////////////////////////////////////////////////////////
222     template <>
223     struct less_impl<optional_tag, optional_tag> {
224         template <typename T>
applyless_impl225         static constexpr hana::true_ apply(hana::optional<> const&, hana::optional<T> const&)
226         { return {}; }
227 
applyless_impl228         static constexpr hana::false_ apply(hana::optional<> const&, hana::optional<> const&)
229         { return {}; }
230 
231         template <typename T>
applyless_impl232         static constexpr hana::false_ apply(hana::optional<T> const&, hana::optional<> const&)
233         { return {}; }
234 
235         template <typename T, typename U>
applyless_impl236         static constexpr auto apply(hana::optional<T> const& x, hana::optional<U> const& y)
237         { return hana::less(x.value_, y.value_); }
238     };
239 
240     //////////////////////////////////////////////////////////////////////////
241     // Functor
242     //////////////////////////////////////////////////////////////////////////
243     template <>
244     struct transform_impl<optional_tag> {
245         template <typename F>
applytransform_impl246         static constexpr auto apply(optional<> const&, F&&)
247         { return hana::nothing; }
248 
249         template <typename T, typename F>
applytransform_impl250         static constexpr auto apply(optional<T> const& opt, F&& f)
251         { return hana::just(static_cast<F&&>(f)(opt.value_)); }
252 
253         template <typename T, typename F>
applytransform_impl254         static constexpr auto apply(optional<T>& opt, F&& f)
255         { return hana::just(static_cast<F&&>(f)(opt.value_)); }
256 
257         template <typename T, typename F>
applytransform_impl258         static constexpr auto apply(optional<T>&& opt, F&& f)
259         { return hana::just(static_cast<F&&>(f)(static_cast<T&&>(opt.value_))); }
260     };
261 
262     //////////////////////////////////////////////////////////////////////////
263     // Applicative
264     //////////////////////////////////////////////////////////////////////////
265     template <>
266     struct lift_impl<optional_tag> {
267         template <typename X>
applylift_impl268         static constexpr auto apply(X&& x)
269         { return hana::just(static_cast<X&&>(x)); }
270     };
271 
272     template <>
273     struct ap_impl<optional_tag> {
274         template <typename F, typename X>
ap_helperap_impl275         static constexpr auto ap_helper(F&&, X&&, ...)
276         { return hana::nothing; }
277 
278         template <typename F, typename X>
ap_helperap_impl279         static constexpr auto ap_helper(F&& f, X&& x, hana::true_, hana::true_)
280         { return hana::just(static_cast<F&&>(f).value_(static_cast<X&&>(x).value_)); }
281 
282         template <typename F, typename X>
applyap_impl283         static constexpr auto apply(F&& f, X&& x) {
284             return ap_impl::ap_helper(static_cast<F&&>(f), static_cast<X&&>(x),
285                                       hana::is_just(f), hana::is_just(x));
286         }
287     };
288 
289     //////////////////////////////////////////////////////////////////////////
290     // Monad
291     //////////////////////////////////////////////////////////////////////////
292     template <>
293     struct flatten_impl<optional_tag> {
applyflatten_impl294         static constexpr auto apply(optional<> const&)
295         { return hana::nothing; }
296 
applyflatten_impl297         static constexpr auto apply(optional<optional<>> const&)
298         { return hana::nothing; }
299 
300         template <typename T>
applyflatten_impl301         static constexpr auto apply(optional<optional<T>> const& opt)
302         { return hana::just(opt.value_.value_); }
303 
304         template <typename T>
applyflatten_impl305         static constexpr auto apply(optional<optional<T>>&& opt)
306         { return hana::just(static_cast<T&&>(opt.value_.value_)); }
307     };
308 
309     //////////////////////////////////////////////////////////////////////////
310     // MonadPlus
311     //////////////////////////////////////////////////////////////////////////
312     template <>
313     struct concat_impl<optional_tag> {
314         template <typename Y>
applyconcat_impl315         static constexpr auto apply(hana::optional<>&, Y&& y)
316         { return static_cast<Y&&>(y); }
317 
318         template <typename Y>
applyconcat_impl319         static constexpr auto apply(hana::optional<>&&, Y&& y)
320         { return static_cast<Y&&>(y); }
321 
322         template <typename Y>
applyconcat_impl323         static constexpr auto apply(hana::optional<> const&, Y&& y)
324         { return static_cast<Y&&>(y); }
325 
326         template <typename X, typename Y>
applyconcat_impl327         static constexpr auto apply(X&& x, Y&&)
328         { return static_cast<X&&>(x); }
329     };
330 
331     template <>
332     struct empty_impl<optional_tag> {
applyempty_impl333         static constexpr auto apply()
334         { return hana::nothing; }
335     };
336 
337     //////////////////////////////////////////////////////////////////////////
338     // Foldable
339     //////////////////////////////////////////////////////////////////////////
340     template <>
341     struct unpack_impl<optional_tag> {
342         template <typename T, typename F>
applyunpack_impl343         static constexpr decltype(auto) apply(optional<T>&& opt, F&& f)
344         { return static_cast<F&&>(f)(static_cast<T&&>(opt.value_)); }
345 
346         template <typename T, typename F>
applyunpack_impl347         static constexpr decltype(auto) apply(optional<T> const& opt, F&& f)
348         { return static_cast<F&&>(f)(opt.value_); }
349 
350         template <typename T, typename F>
applyunpack_impl351         static constexpr decltype(auto) apply(optional<T>& opt, F&& f)
352         { return static_cast<F&&>(f)(opt.value_); }
353 
354         template <typename F>
applyunpack_impl355         static constexpr decltype(auto) apply(optional<> const&, F&& f)
356         { return static_cast<F&&>(f)(); }
357     };
358 
359     //////////////////////////////////////////////////////////////////////////
360     // Searchable
361     //////////////////////////////////////////////////////////////////////////
362     namespace detail {
363         template <bool>
364         struct optional_find_if {
365             template <typename T>
applydetail::optional_find_if366             static constexpr auto apply(T const&)
367             { return hana::nothing; }
368         };
369 
370         template <>
371         struct optional_find_if<true> {
372             template <typename T>
applydetail::optional_find_if373             static constexpr auto apply(T&& t)
374             { return hana::just(static_cast<T&&>(t)); }
375         };
376     }
377 
378     template <>
379     struct find_if_impl<optional_tag> {
380         template <typename T, typename Pred>
applyfind_if_impl381         static constexpr auto apply(hana::optional<T> const& opt, Pred&& pred) {
382             constexpr bool found = decltype(static_cast<Pred&&>(pred)(opt.value_))::value;
383             return detail::optional_find_if<found>::apply(opt.value_);
384         }
385 
386         template <typename T, typename Pred>
applyfind_if_impl387         static constexpr auto apply(hana::optional<T>& opt, Pred&& pred) {
388             constexpr bool found = decltype(static_cast<Pred&&>(pred)(opt.value_))::value;
389             return detail::optional_find_if<found>::apply(opt.value_);
390         }
391 
392         template <typename T, typename Pred>
applyfind_if_impl393         static constexpr auto apply(hana::optional<T>&& opt, Pred&& pred) {
394             constexpr bool found = decltype(
395                 static_cast<Pred&&>(pred)(static_cast<T&&>(opt.value_))
396             )::value;
397             return detail::optional_find_if<found>::apply(static_cast<T&&>(opt.value_));
398         }
399 
400         template <typename Pred>
applyfind_if_impl401         static constexpr auto apply(hana::optional<> const&, Pred&&)
402         { return hana::nothing; }
403     };
404 
405     template <>
406     struct any_of_impl<optional_tag> {
407         template <typename T, typename Pred>
applyany_of_impl408         static constexpr auto apply(hana::optional<T> const& opt, Pred&& pred)
409         { return static_cast<Pred&&>(pred)(opt.value_); }
410 
411         template <typename Pred>
applyany_of_impl412         static constexpr hana::false_ apply(hana::optional<> const&, Pred&&)
413         { return {}; }
414     };
415 BOOST_HANA_NAMESPACE_END
416 
417 #endif // !BOOST_HANA_OPTIONAL_HPP
418