// Copyright (C) 2020 T. Zachary Laine // // Distributed under the Boost Software License, Version 1.0. (See // accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) #ifndef BOOST_PARSER_DETAIL_HL_HPP #define BOOST_PARSER_DETAIL_HL_HPP #include #include #include #include #include namespace boost { namespace parser { namespace detail::hl { // Boost.Hana lite. These functions work with boost::hana::tuple and // std::tuple. struct forward { template decltype(auto) operator()(T && t) { return (T &&) t; } }; template constexpr auto make_tuple(Args &&... args) { #if BOOST_PARSER_USE_STD_TUPLE return std::make_tuple((Args &&) args...); #else return hana::make_tuple((Args &&) args...); #endif } template constexpr auto make_pair(T && t, U && u) { return hl::make_tuple((T &&) t, (U &&) u); } template constexpr auto concat(Tuple1 const & t1, Tuple2 const & t2) { #if BOOST_PARSER_USE_STD_TUPLE return std::tuple_cat(t1, t2); #else // Hana's concat does not seem to do what it says on the tin. // Concatenating (int, string) with (double, int) yields (int, string, // double). I maybe don't understand it well enough. return hana::insert_range(t1, hana::size(t1), t2); #endif } // apply template constexpr auto apply_impl(F && f, Tuple && t, std::integer_sequence) -> decltype(((F &&) f)(parser::get((Tuple &&) t, llong{})...)) { return ((F &&) f)(parser::get((Tuple &&) t, llong{})...); } template< typename F, typename Tuple, typename Enable = std::enable_if_t>>{}>> constexpr auto apply(F && f, Tuple && t) -> decltype(hl::apply_impl( (F &&) f, (Tuple &&) t, std::make_integer_sequence>{})) { return hl::apply_impl( (F &&) f, (Tuple &&) t, std::make_integer_sequence>{}); } // for_each template constexpr void for_each_impl( Tuple const & t, F && f, std::integer_sequence) { int _[] = {0, (f(parser::get(t, llong{})), 0)...}; (void)_; } template< typename F, typename Tuple, std::size_t... I, typename Enable = std::enable_if_t>> constexpr void for_each_impl(Tuple && t, F && f, std::integer_sequence) { int _[] = {0, (f(std::move(parser::get(t, llong{}))), 0)...}; (void)_; } template constexpr void for_each(tuple && t, F && f) { hl::for_each_impl( std::move(t), (F &&) f, std::make_integer_sequence()); } template constexpr void for_each(tuple const & t, F && f) { hl::for_each_impl( t, (F &&) f, std::make_integer_sequence()); } // transform template constexpr auto transform_impl( Tuple const & t, F && f, std::integer_sequence) { return tuple< std::decay_t{})))>...>{ f(parser::get(t, llong{}))...}; } template< int offset, typename F, typename Tuple, std::size_t... I, typename Enable = std::enable_if_t>> auto constexpr transform_impl( Tuple && t, F && f, std::integer_sequence) { return tuple{}))))>...>{ f(std::move(parser::get(t, llong{})))...}; } template constexpr auto transform(tuple && t, F && f) { return hl::transform_impl<0>( std::move(t), (F &&) f, std::make_integer_sequence()); } template constexpr auto transform(tuple const & t, F && f) { return hl::transform_impl<0>( t, (F &&) f, std::make_integer_sequence()); } // fold_left template struct fold_left_dispatch { template constexpr static auto call(tuple const & t, State && s, F const & f) { return fold_left_dispatch::call( t, f((State &&) s, parser::get(t, llong{})), f); } }; template struct fold_left_dispatch { template constexpr static auto call(tuple const & t, State && s, F const & f) { return (State &&) s; } }; template constexpr auto fold_left(tuple const & t, State && s, F const & f) { return hl::fold_left_dispatch<0, sizeof...(Args)>::call( t, (State &&) s, (F &&) f); } // size template constexpr auto size(tuple const & t) { return llong{}; } template constexpr auto size_minus_one(tuple const & t) { return llong{}; } // contains template using comparable = decltype(std::declval() == std::declval()); struct typesafe_equals { template constexpr bool operator()(T const & t, U const & u) { if constexpr (detail::is_detected_v) { return t == u; } else { return false; } } }; template constexpr bool contains_impl( Tuple const & t, T const & x, std::integer_sequence) { typesafe_equals eq; (void)eq; return (eq(parser::get(t, llong{}), x) || ...); } template constexpr bool contains(tuple const & t, T const & x) { return contains_impl( t, x, std::make_integer_sequence()); } // front, back template constexpr decltype(auto) front(tuple const & t) { return parser::get(t, llong<0>{}); } template constexpr decltype(auto) back(tuple const & t) { return parser::get(t, llong{}); } // drop_front template constexpr auto drop_front(tuple && t) { return hl::transform_impl<1>( std::move(t), forward{}, std::make_integer_sequence()); } template constexpr auto drop_front(tuple const & t) { return hl::transform_impl<1>( t, forward{}, std::make_integer_sequence()); } // drop_back template constexpr auto drop_back(tuple && t) { return hl::transform_impl<0>( std::move(t), forward{}, std::make_integer_sequence()); } template constexpr auto drop_back(tuple const & t) { return hl::transform_impl<0>( t, forward{}, std::make_integer_sequence()); } // first, second template constexpr decltype(auto) first(tuple const & t) { return parser::get(t, llong<0>{}); } template constexpr decltype(auto) second(tuple const & t) { return parser::get(t, llong<1>{}); } // zip template constexpr decltype(auto) make_zip_elem(Tuples const &... ts) { return hl::make_tuple(parser::get(ts, llong{})...); } template constexpr auto zip_impl(std::index_sequence, Tuples const &... ts) { return hl::make_tuple(hl::make_zip_elem(ts...)...); } template struct tuplesize; template struct tuplesize> { constexpr static std::size_t value = sizeof...(Args); }; template constexpr auto zip(Tuple const & t, Tuples const &... ts) { return hl::zip_impl( std::make_integer_sequence< std::size_t, tuplesize>::value>(), t, ts...); } // append template constexpr auto append(tuple && t, T && x) { #if BOOST_PARSER_USE_STD_TUPLE return std::tuple_cat(std::move(t), std::make_tuple((T &&) x)); #else return hana::append(std::move(t), (T &&) x); #endif } template constexpr auto append(tuple const & t, T && x) { #if BOOST_PARSER_USE_STD_TUPLE return std::tuple_cat(t, std::make_tuple((T &&) x)); #else return hana::append(t, (T &&) x); #endif } // prepend template constexpr auto prepend(tuple && t, T && x) { #if BOOST_PARSER_USE_STD_TUPLE return std::tuple_cat(std::make_tuple((T &&) x), std::move(t)); #else return hana::prepend(std::move(t), (T &&) x); #endif } template constexpr auto prepend(tuple const & t, T && x) { #if BOOST_PARSER_USE_STD_TUPLE return std::tuple_cat(std::make_tuple((T &&) x), t); #else return hana::prepend(t, (T &&) x); #endif } }}} #endif