// 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_TEXT_UNPACK_HPP #define BOOST_PARSER_DETAIL_TEXT_UNPACK_HPP #include #include #include namespace boost::parser::detail { namespace text { struct no_op_repacker { template T operator()(T x) const { return x; } }; namespace detail { // Using this custom template is quite a bit faster than using lambdas. // Unexpected. template< typename RepackedIterator, typename I, typename S, typename Then, bool Bidi> struct repacker { repacker() = default; #if !BOOST_PARSER_DETAIL_TEXT_USE_CONCEPTS template> #endif repacker(I first, S last, Then then) #if BOOST_PARSER_DETAIL_TEXT_USE_CONCEPTS requires Bidi #endif : first{first}, last{last}, then{then} {} #if !BOOST_PARSER_DETAIL_TEXT_USE_CONCEPTS template> #endif repacker(S last, Then then) #if BOOST_PARSER_DETAIL_TEXT_USE_CONCEPTS requires(!Bidi) #endif : last{last}, then{then} {} auto operator()(I it) const { if constexpr (Bidi) { return then(RepackedIterator(*first, it, last)); } else { return then(RepackedIterator(it, last)); } } std::optional first; [[no_unique_address]] S last; [[no_unique_address]] Then then; }; template constexpr auto unpack_iterator_and_sentinel_impl(I first, S last, Repack repack); template< format FromFormat, format ToFormat, typename I, typename S, typename ErrorHandler, typename Repack> constexpr auto unpack_iterator_and_sentinel_impl( utf_iterator first, utf_iterator last, Repack repack); template< format FromFormat, format ToFormat, typename I, typename S, typename ErrorHandler, typename Repack> constexpr auto unpack_iterator_and_sentinel_impl( utf_iterator first, S last, Repack repack); template constexpr auto unpack_iterator_and_sentinel(I first, S last, Repack repack) { return detail::unpack_iterator_and_sentinel_impl( first, last, repack); } struct unpack_iterator_and_sentinel_cpo { #if BOOST_PARSER_DETAIL_TEXT_USE_CONCEPTS template< utf_iter I, std::sentinel_for S, typename Repack = no_op_repacker> requires std::forward_iterator #else template #endif constexpr auto operator()(I first, S last, Repack repack = Repack()) const { return unpack_iterator_and_sentinel(first, last, repack); } }; } inline namespace cpo { inline constexpr detail::unpack_iterator_and_sentinel_cpo unpack_iterator_and_sentinel{}; } #if BOOST_PARSER_DETAIL_TEXT_USE_CONCEPTS template S, class Repack> #else template #endif struct unpack_result { static constexpr format format_tag = FormatTag; I first; [[no_unique_address]] S last; [[no_unique_address]] Repack repack; }; namespace detail { struct no_such_type {}; template constexpr auto unpack_iterator_and_sentinel_impl(I first, S last, Repack repack) { using value_type = detail::iter_value_t; if constexpr ( std::is_same_v #if defined(__cpp_char8_t) || std::is_same_v #endif ) { return unpack_result{ first, last, repack}; } else if constexpr ( #if defined(_MSC_VER) std::is_same_v || #endif std::is_same_v) { return unpack_result{ first, last, repack}; } else if constexpr ( #if !defined(_MSC_VER) std::is_same_v || #endif std::is_same_v) { return unpack_result{ first, last, repack}; } else { static_assert( std::is_same_v, "Unpacked iterator is not a utf_iter!"); return 0; } } } }} #include namespace boost::parser::detail { namespace text { namespace detail { template< format FromFormat, format ToFormat, typename I, typename S, typename ErrorHandler, typename Repack> constexpr auto unpack_iterator_and_sentinel_impl( utf_iterator first, utf_iterator last, Repack repack) { using iterator = utf_iterator; if constexpr ( #if BOOST_PARSER_DETAIL_TEXT_USE_CONCEPTS std::bidirectional_iterator #else std::is_base_of_v< std::bidirectional_iterator_tag, typename std::iterator_traits::iterator_category> #endif ) { return boost::parser::detail::text::unpack_iterator_and_sentinel( first.base(), last.base(), repacker< iterator, decltype(first.begin()), decltype(first.end()), Repack, true>(first.begin(), first.end(), repack)); } else { return boost::parser::detail::text::unpack_iterator_and_sentinel( first.base(), last.base(), repacker( first.end(), repack)); } } template< format FromFormat, format ToFormat, typename I, typename S, typename ErrorHandler, typename Repack> constexpr auto unpack_iterator_and_sentinel_impl( utf_iterator first, S last, Repack repack) { using iterator = utf_iterator; if constexpr ( #if BOOST_PARSER_DETAIL_TEXT_USE_CONCEPTS std::bidirectional_iterator #else std::is_base_of_v< std::bidirectional_iterator_tag, typename std::iterator_traits::iterator_category> #endif ) { return boost::parser::detail::text::unpack_iterator_and_sentinel( first.base(), last, repacker< iterator, decltype(first.begin()), decltype(first.end()), Repack, true>(first.begin(), first.end(), repack)); } else { return boost::parser::detail::text::unpack_iterator_and_sentinel( first.base(), last, repacker(last, repack)); } } }}} #endif