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