diff options
Diffstat (limited to 'boost/hana/index_if.hpp')
-rw-r--r-- | boost/hana/index_if.hpp | 105 |
1 files changed, 105 insertions, 0 deletions
diff --git a/boost/hana/index_if.hpp b/boost/hana/index_if.hpp new file mode 100644 index 0000000000..93ec21c75c --- /dev/null +++ b/boost/hana/index_if.hpp @@ -0,0 +1,105 @@ +/*! +@file +Defines `boost::hana::index_if`. + +@copyright Louis Dionne 2013-2017 +@copyright Jason Rice 2017 +Distributed under the Boost Software License, Version 1.0. +(See accompanying file LICENSE.md or copy at http://boost.org/LICENSE_1_0.txt) + */ + +#ifndef BOOST_HANA_INDEX_IF_HPP +#define BOOST_HANA_INDEX_IF_HPP + +#include <boost/hana/concept/foldable.hpp> +#include <boost/hana/concept/iterable.hpp> +#include <boost/hana/config.hpp> +#include <boost/hana/detail/decay.hpp> +#include <boost/hana/detail/index_if.hpp> +#include <boost/hana/fwd/at.hpp> +#include <boost/hana/fwd/basic_tuple.hpp> +#include <boost/hana/fwd/index_if.hpp> +#include <boost/hana/integral_constant.hpp> +#include <boost/hana/length.hpp> +#include <boost/hana/optional.hpp> + +#include <cstddef> +#include <utility> + + +BOOST_HANA_NAMESPACE_BEGIN + //! @cond + template <typename Xs, typename Pred> + constexpr auto index_if_t::operator()(Xs&& xs, Pred&& pred) const { + using S = typename hana::tag_of<Xs>::type; + using IndexIf = BOOST_HANA_DISPATCH_IF(index_if_impl<S>, + hana::Iterable<S>::value + ); + + #ifndef BOOST_HANA_CONFIG_DISABLE_CONCEPT_CHECKS + static_assert(hana::Iterable<S>::value, + "hana::index_if(xs, pred) requires 'xs' to be a Iterable"); + #endif + + return IndexIf::apply(static_cast<Xs&&>(xs), static_cast<Pred&&>(pred)); + } + //! @endcond + + namespace detail { + template <std::size_t i, std::size_t N, bool Done> + struct iterate_while; + + template <std::size_t i, std::size_t N> + struct iterate_while<i, N, false> { + template <typename Xs, typename Pred> + using f = typename iterate_while<i + 1, N, + static_cast<bool>(detail::decay<decltype( + std::declval<Pred>()( + hana::at(std::declval<Xs>(), hana::size_c<i>)))>::type::value) + >::template f<Xs, Pred>; + }; + + template <std::size_t N> + struct iterate_while<N, N, false> { + template <typename Xs, typename Pred> + using f = hana::optional<>; + }; + + template <std::size_t i, std::size_t N> + struct iterate_while<i, N, true> { + template <typename Xs, typename Pred> + using f = hana::optional<hana::size_t<i - 1>>; + }; + } + + template <typename Tag> + struct index_if_impl<Tag, when<Foldable<Tag>::value>> { + template <typename Xs, typename Pred> + static constexpr auto apply(Xs const& xs, Pred const&) + -> typename detail::iterate_while<0, + decltype(hana::length(xs))::value, false> + ::template f<Xs, Pred> + { return {}; } + }; + + template <typename It> + struct index_if_impl<It, when<!Foldable<It>::value>> { + template <typename Xs, typename Pred> + static constexpr auto apply(Xs const&, Pred const&) + -> typename detail::iterate_while<hana::size_c<0>, + static_cast<std::size_t>(-1), false> + ::template f<Xs, Pred> + { return {}; } + }; + + // basic_tuple is implemented here to solve circular dependency issues. + template <> + struct index_if_impl<basic_tuple_tag> { + template <typename ...Xs, typename Pred> + static constexpr auto apply(basic_tuple<Xs...> const&, Pred const&) + -> typename detail::index_if<Pred, Xs...>::type + { return {}; } + }; +BOOST_HANA_NAMESPACE_END + +#endif // !BOOST_HANA_INDEX_IF_HPP |