boost/parser/detail/hl.hpp
// 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 <boost/parser/config.hpp> #include <boost/parser/tuple.hpp> #include <boost/parser/detail/detection.hpp> #include <type_traits> #include <utility> namespace boost { namespace parser { namespace detail::hl { // Boost.Hana lite. These functions work with boost::hana::tuple and // std::tuple. struct forward { template<typename T> decltype(auto) operator()(T && t) { return (T &&) t; } }; template<typename... Args> 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<typename T, typename U> constexpr auto make_pair(T && t, U && u) { return hl::make_tuple((T &&) t, (U &&) u); } template<typename Tuple1, typename Tuple2> 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<typename F, typename Tuple, std::size_t... I> constexpr auto apply_impl(F && f, Tuple && t, std::integer_sequence<std::size_t, I...>) -> decltype(((F &&) f)(parser::get((Tuple &&) t, llong<I>{})...)) { return ((F &&) f)(parser::get((Tuple &&) t, llong<I>{})...); } template< typename F, typename Tuple, typename Enable = std::enable_if_t<detail::is_tuple< std::remove_cv_t<std::remove_reference_t<Tuple>>>{}>> constexpr auto apply(F && f, Tuple && t) -> decltype(hl::apply_impl( (F &&) f, (Tuple &&) t, std::make_integer_sequence<std::size_t, tuple_size_<Tuple>>{})) { return hl::apply_impl( (F &&) f, (Tuple &&) t, std::make_integer_sequence<std::size_t, tuple_size_<Tuple>>{}); } // for_each template<typename F, typename Tuple, std::size_t... I> constexpr void for_each_impl( Tuple const & t, F && f, std::integer_sequence<std::size_t, I...>) { int _[] = {0, (f(parser::get(t, llong<I>{})), 0)...}; (void)_; } template< typename F, typename Tuple, std::size_t... I, typename Enable = std::enable_if_t<!std::is_reference_v<Tuple>>> constexpr void for_each_impl(Tuple && t, F && f, std::integer_sequence<std::size_t, I...>) { int _[] = {0, (f(std::move(parser::get(t, llong<I>{}))), 0)...}; (void)_; } template<typename F, typename... Args> constexpr void for_each(tuple<Args...> && t, F && f) { hl::for_each_impl( std::move(t), (F &&) f, std::make_integer_sequence<std::size_t, sizeof...(Args)>()); } template<typename F, typename... Args> constexpr void for_each(tuple<Args...> const & t, F && f) { hl::for_each_impl( t, (F &&) f, std::make_integer_sequence<std::size_t, sizeof...(Args)>()); } // transform template<int offset, typename F, typename Tuple, std::size_t... I> constexpr auto transform_impl( Tuple const & t, F && f, std::integer_sequence<std::size_t, I...>) { return tuple< std::decay_t<decltype(f(parser::get(t, llong<I + offset>{})))>...>{ f(parser::get(t, llong<I + offset>{}))...}; } template< int offset, typename F, typename Tuple, std::size_t... I, typename Enable = std::enable_if_t<!std::is_reference_v<Tuple>>> auto constexpr transform_impl( Tuple && t, F && f, std::integer_sequence<std::size_t, I...>) { return tuple<std::decay_t<decltype( f(std::move(parser::get(t, llong<I + offset>{}))))>...>{ f(std::move(parser::get(t, llong<I + offset>{})))...}; } template<typename F, typename... Args> constexpr auto transform(tuple<Args...> && t, F && f) { return hl::transform_impl<0>( std::move(t), (F &&) f, std::make_integer_sequence<std::size_t, sizeof...(Args)>()); } template<typename F, typename... Args> constexpr auto transform(tuple<Args...> const & t, F && f) { return hl::transform_impl<0>( t, (F &&) f, std::make_integer_sequence<std::size_t, sizeof...(Args)>()); } // fold_left template<std::size_t I, std::size_t N> struct fold_left_dispatch { template<typename F, typename State, typename... Args> constexpr static auto call(tuple<Args...> const & t, State && s, F const & f) { return fold_left_dispatch<I + 1, N>::call( t, f((State &&) s, parser::get(t, llong<I>{})), f); } }; template<std::size_t I> struct fold_left_dispatch<I, I> { template<typename F, typename State, typename... Args> constexpr static auto call(tuple<Args...> const & t, State && s, F const & f) { return (State &&) s; } }; template<typename F, typename State, typename... Args> constexpr auto fold_left(tuple<Args...> const & t, State && s, F const & f) { return hl::fold_left_dispatch<0, sizeof...(Args)>::call( t, (State &&) s, (F &&) f); } // size template<typename... Args> constexpr auto size(tuple<Args...> const & t) { return llong<sizeof...(Args)>{}; } template<typename... Args> constexpr auto size_minus_one(tuple<Args...> const & t) { return llong<sizeof...(Args) - 1>{}; } // contains template<typename T, typename U> using comparable = decltype(std::declval<T>() == std::declval<U>()); struct typesafe_equals { template<typename T, typename U> constexpr bool operator()(T const & t, U const & u) { if constexpr (detail::is_detected_v<comparable, T, U>) { return t == u; } else { return false; } } }; template<typename T, typename Tuple, std::size_t... I> constexpr bool contains_impl( Tuple const & t, T const & x, std::integer_sequence<std::size_t, I...>) { typesafe_equals eq; (void)eq; return (eq(parser::get(t, llong<I>{}), x) || ...); } template<typename T, typename... Args> constexpr bool contains(tuple<Args...> const & t, T const & x) { return contains_impl( t, x, std::make_integer_sequence<std::size_t, sizeof...(Args)>()); } // front, back template<typename Arg, typename... Args> constexpr decltype(auto) front(tuple<Arg, Args...> const & t) { return parser::get(t, llong<0>{}); } template<typename Arg, typename... Args> constexpr decltype(auto) back(tuple<Arg, Args...> const & t) { return parser::get(t, llong<sizeof...(Args)>{}); } // drop_front template<typename Arg, typename... Args> constexpr auto drop_front(tuple<Arg, Args...> && t) { return hl::transform_impl<1>( std::move(t), forward{}, std::make_integer_sequence<std::size_t, sizeof...(Args)>()); } template<typename Arg, typename... Args> constexpr auto drop_front(tuple<Arg, Args...> const & t) { return hl::transform_impl<1>( t, forward{}, std::make_integer_sequence<std::size_t, sizeof...(Args)>()); } // drop_back template<typename Arg, typename... Args> constexpr auto drop_back(tuple<Arg, Args...> && t) { return hl::transform_impl<0>( std::move(t), forward{}, std::make_integer_sequence<std::size_t, sizeof...(Args)>()); } template<typename Arg, typename... Args> constexpr auto drop_back(tuple<Arg, Args...> const & t) { return hl::transform_impl<0>( t, forward{}, std::make_integer_sequence<std::size_t, sizeof...(Args)>()); } // first, second template<typename T, typename U> constexpr decltype(auto) first(tuple<T, U> const & t) { return parser::get(t, llong<0>{}); } template<typename T, typename U> constexpr decltype(auto) second(tuple<T, U> const & t) { return parser::get(t, llong<1>{}); } // zip template<std::size_t I, typename... Tuples> constexpr decltype(auto) make_zip_elem(Tuples const &... ts) { return hl::make_tuple(parser::get(ts, llong<I>{})...); } template<std::size_t... I, typename... Tuples> constexpr auto zip_impl(std::index_sequence<I...>, Tuples const &... ts) { return hl::make_tuple(hl::make_zip_elem<I>(ts...)...); } template<typename T> struct tuplesize; template<typename... Args> struct tuplesize<tuple<Args...>> { constexpr static std::size_t value = sizeof...(Args); }; template<typename Tuple, typename... Tuples> constexpr auto zip(Tuple const & t, Tuples const &... ts) { return hl::zip_impl( std::make_integer_sequence< std::size_t, tuplesize<std::remove_reference_t<Tuple>>::value>(), t, ts...); } // append template<typename... Args, typename T> constexpr auto append(tuple<Args...> && 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<typename... Args, typename T> constexpr auto append(tuple<Args...> 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<typename... Args, typename T> constexpr auto prepend(tuple<Args...> && 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<typename... Args, typename T> constexpr auto prepend(tuple<Args...> 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