1 /*! 2 @file 3 Defines `boost::hana::find_if`. 4 5 @copyright Louis Dionne 2013-2017 6 @copyright Jason Rice 2017 7 Distributed under the Boost Software License, Version 1.0. 8 (See accompanying file LICENSE.md or copy at http://boost.org/LICENSE_1_0.txt) 9 */ 10 11 #ifndef BOOST_HANA_FIND_IF_HPP 12 #define BOOST_HANA_FIND_IF_HPP 13 14 #include <boost/hana/fwd/find_if.hpp> 15 16 #include <boost/hana/accessors.hpp> 17 #include <boost/hana/at.hpp> 18 #include <boost/hana/bool.hpp> 19 #include <boost/hana/concept/iterable.hpp> 20 #include <boost/hana/concept/searchable.hpp> 21 #include <boost/hana/concept/struct.hpp> 22 #include <boost/hana/config.hpp> 23 #include <boost/hana/core/dispatch.hpp> 24 #include <boost/hana/first.hpp> 25 #include <boost/hana/functional/compose.hpp> 26 #include <boost/hana/index_if.hpp> 27 #include <boost/hana/second.hpp> 28 #include <boost/hana/transform.hpp> 29 30 #include <cstddef> 31 #include <utility> 32 33 34 BOOST_HANA_NAMESPACE_BEGIN 35 //! @cond 36 template <typename Xs, typename Pred> operator ()(Xs && xs,Pred && pred) const37 constexpr auto find_if_t::operator()(Xs&& xs, Pred&& pred) const { 38 using S = typename hana::tag_of<Xs>::type; 39 using FindIf = BOOST_HANA_DISPATCH_IF(find_if_impl<S>, 40 hana::Searchable<S>::value 41 ); 42 43 #ifndef BOOST_HANA_CONFIG_DISABLE_CONCEPT_CHECKS 44 static_assert(hana::Searchable<S>::value, 45 "hana::find_if(xs, pred) requires 'xs' to be a Searchable"); 46 #endif 47 48 return FindIf::apply(static_cast<Xs&&>(xs), static_cast<Pred&&>(pred)); 49 } 50 //! @endcond 51 52 template <typename S, bool condition> 53 struct find_if_impl<S, when<condition>> : default_ { 54 template <typename ...Args> 55 static constexpr auto apply(Args&& ...) = delete; 56 }; 57 58 namespace detail { 59 template <typename Xs> 60 struct partial_at { 61 Xs const& xs; 62 63 template <typename I> operator ()detail::partial_at64 constexpr decltype(auto) operator()(I i) const { 65 return hana::at(xs, i); 66 } 67 }; 68 } 69 70 template <typename Tag> 71 struct find_if_impl<Tag, when<Iterable<Tag>::value>> { 72 template <typename Xs, typename Pred> applyfind_if_impl73 static constexpr auto apply(Xs&& xs, Pred&& pred) { 74 using Result = decltype(hana::index_if( 75 static_cast<Xs&&>(xs), static_cast<Pred&&>(pred))); 76 77 return hana::transform(Result{}, 78 detail::partial_at<std::decay_t<Xs>>{static_cast<Xs&&>(xs)}); 79 } 80 }; 81 82 template <typename T, std::size_t N> 83 struct find_if_impl<T[N]> { 84 template <typename Xs> find_if_helperfind_if_impl85 static constexpr auto find_if_helper(Xs&&, hana::false_) 86 { return hana::nothing; } 87 88 template <typename Xs> find_if_helperfind_if_impl89 static constexpr auto find_if_helper(Xs&& xs, hana::true_) 90 { return hana::just(static_cast<Xs&&>(xs)[0]); } 91 92 template <typename Xs, typename Pred> applyfind_if_impl93 static constexpr auto apply(Xs&& xs, Pred&& pred) { 94 return find_if_helper(static_cast<Xs&&>(xs), 95 hana::bool_c<decltype( 96 static_cast<Pred&&>(pred)(static_cast<Xs&&>(xs)[0]) 97 )::value> 98 ); 99 } 100 }; 101 102 namespace struct_detail { 103 template <typename X> 104 struct get_member { 105 X x; 106 template <typename Member> operator ()struct_detail::get_member107 constexpr decltype(auto) operator()(Member&& member) && { 108 return hana::second(static_cast<Member&&>(member))( 109 static_cast<X&&>(x) 110 ); 111 } 112 }; 113 } 114 115 template <typename S> 116 struct find_if_impl<S, when<hana::Struct<S>::value>> { 117 template <typename X, typename Pred> applyfind_if_impl118 static constexpr decltype(auto) apply(X&& x, Pred&& pred) { 119 return hana::transform( 120 hana::find_if(hana::accessors<S>(), 121 hana::compose(static_cast<Pred&&>(pred), hana::first) 122 ), 123 struct_detail::get_member<X>{static_cast<X&&>(x)} 124 ); 125 } 126 }; 127 BOOST_HANA_NAMESPACE_END 128 129 #endif // !BOOST_HANA_FIND_IF_HPP 130