// Copyright (C) 2020 T. Zachary Laine // Copyright Louis Dionne 2013-2017 // // 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_TUPLE_HPP #define BOOST_PARSER_TUPLE_HPP #include #include #if BOOST_PARSER_USE_STD_TUPLE #include #else // Silence very verbose warnings about std::is_pod/std::is_literal being // deprecated. #if defined(__GNUC__) || defined(__clang__) # pragma GCC diagnostic push # pragma GCC diagnostic ignored "-Wdeprecated-declarations" # pragma GCC diagnostic ignored "-Wunused-value" #endif #include #if defined(__GNUC__) || defined(__clang__) # pragma GCC diagnostic pop #endif #endif namespace boost { namespace parser { namespace detail { // to_int() and parse_llong() taken from boost/hana/bool.hpp. constexpr int to_int(char c) { int result = 0; if (c >= 'A' && c <= 'F') { result = static_cast(c) - static_cast('A') + 10; } else if (c >= 'a' && c <= 'f') { result = static_cast(c) - static_cast('a') + 10; } else { result = static_cast(c) - static_cast('0'); } return result; } template constexpr long long parse_llong(const char (&arr)[N]) { long long base = 10; std::size_t offset = 0; if constexpr (N > 2) { bool starts_with_zero = arr[0] == '0'; bool is_hex = starts_with_zero && arr[1] == 'x'; bool is_binary = starts_with_zero && arr[1] == 'b'; if (is_hex) { // 0xDEADBEEF (hexadecimal) base = 16; offset = 2; } else if (is_binary) { // 0b101011101 (binary) base = 2; offset = 2; } else if (starts_with_zero) { // 012345 (octal) base = 8; offset = 1; } } long long number = 0; long long multiplier = 1; for (std::size_t i = 0; i < N - offset; ++i) { char c = arr[N - 1 - i]; if (c != '\'') { // skip digit separators number += to_int(c) * multiplier; multiplier *= base; } } return number; } } /** The tuple template alias used within Boost.Parser. This will be `boost::hana::tuple` if `BOOST_PARSER_USE_HANA_TUPLE` is defined, and `std::tuple` otherwise. */ #if BOOST_PARSER_USE_STD_TUPLE template using tuple = std::tuple; #else template using tuple = hana::tuple; #endif /** A template alias that is `boost::hana::integral_constant` if `BOOST_PARSER_USE_HANA_TUPLE` is defined, and `std::integral_constant` otherwise. */ #if BOOST_PARSER_USE_STD_TUPLE template using integral_constant = std::integral_constant; #else template using integral_constant = hana::integral_constant; #endif /** An accessor that returns a reference to the `I`-th data member of an aggregate struct or `boost::parser::tuple`. */ template constexpr decltype(auto) get(T && x, integral_constant i); /** A template alias that is `boost::hana::llong` if `BOOST_PARSER_USE_HANA_TUPLE` is defined, and `std::integral_constant` otherwise. */ template using llong = integral_constant; namespace literals { /** A literal that can be used to concisely name `parser::llong` integral constants. */ template constexpr auto operator""_c() { constexpr long long n = detail::parse_llong({chars...}); return llong{}; } } namespace detail { /** A tuple accessor that returns a reference to the `I`-th element. */ template constexpr decltype(auto) tuple_get(tuple const & t, integral_constant) { #if BOOST_PARSER_USE_STD_TUPLE return std::get(t); #else return hana::at_c(t); #endif } /** A tuple accessor that returns a reference to the `I`-th element. */ template constexpr decltype(auto) tuple_get(tuple & t, integral_constant) { #if BOOST_PARSER_USE_STD_TUPLE return std::get(t); #else return hana::at_c(t); #endif } /** A tuple accessor that returns a reference to the `I`-th element. */ template constexpr decltype(auto) tuple_get(tuple && t, integral_constant) { #if BOOST_PARSER_USE_STD_TUPLE return std::move(std::get(t)); #else return std::move(hana::at_c(t)); #endif } template struct ce_int { constexpr static int value = N; }; struct whatever { int _; template operator T() const && noexcept { // Yuck. std::remove_reference_t * ptr = nullptr; ptr += 1; // warning mitigation return *ptr; } }; template constexpr auto constructible_expr_impl(std::integer_sequence) -> decltype(T{whatever{Is}...}, ce_int<1>{}); template using constructible_expr = decltype(detail::constructible_expr_impl( std::make_integer_sequence())); template constexpr int struct_arity_impl(std::integer_sequence) { return ( detected_or_t, constructible_expr, T, ce_int>:: value + ... + 0); } // This often mistakenly returns 1 when you give it a struct with // private/protected members, because of copy/move construction. // Fortunately, we don't care -- we never assign from tuples of size // 1. template constexpr int struct_arity_v = detail::struct_arity_impl(std::make_integer_sequence< int, BOOST_PARSER_MAX_AGGREGATE_SIZE>()) - 1; template constexpr int tuple_size_ = -1; template constexpr int tuple_size_> = sizeof...(Elems); template auto assign_tuple_to_aggregate( T & x, Tuple tup, std::integer_sequence) -> decltype(x = T{parser::get(std::move(tup), llong{})...}); template auto tuple_to_aggregate(Tuple && tup, std::integer_sequence) -> decltype(T{std::move(parser::get(tup, llong{}))...}) { return T{std::move(parser::get(tup, llong{}))...}; } template using tuple_to_aggregate_expr = decltype(detail::assign_tuple_to_aggregate( std::declval(), std::declval(), std::make_integer_sequence>())); template constexpr bool is_struct_assignable_v = struct_arity_v == tuple_size_ ? is_detected_v : false; template struct tie_aggregate_impl { template static constexpr auto call(T & x) { static_assert( sizeof(T) && false, "It looks like you're trying to use a struct larger than " "the limit."); } }; template constexpr auto tie_aggregate(T & x) { static_assert(!std::is_union_v); return tie_aggregate_impl>::call(x); } template auto aggregate_to_tuple( Tuple & tup, Tie tie, std::integer_sequence) -> decltype(( (parser::get(tup, llong{}) = std::move(parser::get(tie, llong{}))), ..., (void)0)) { return ( (parser::get(tup, llong{}) = std::move(parser::get(tie, llong{}))), ..., (void)0); } template using aggregate_to_tuple_expr = decltype(detail::aggregate_to_tuple( std::declval(), detail::tie_aggregate(std::declval()), std::make_integer_sequence>())); template constexpr bool is_tuple_assignable_impl() { if constexpr ( std::is_aggregate_v && struct_arity_v == tuple_size_) { return is_detected_v; } else { return false; } } template constexpr bool is_tuple_assignable_v = is_tuple_assignable_impl(); template struct is_tuple : std::false_type {}; template struct is_tuple> : std::true_type {}; } template constexpr decltype(auto) get(T && x, integral_constant i) { using just_t = std::decay_t; if constexpr (detail::is_tuple::value) { return detail::tuple_get((T &&) x, i); } else if constexpr (std::is_aggregate_v) { auto tup = detail::tie_aggregate(x); return detail::tuple_get(tup, i); } else { static_assert( sizeof(T) != sizeof(T), "boost::parser::get() is only defined for boost::parser::tuple " "and aggregate structs."); } } }} #include #endif