boost/parser/detail/text/unpack.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_TEXT_UNPACK_HPP #define BOOST_PARSER_DETAIL_TEXT_UNPACK_HPP #include <boost/parser/detail/text/transcode_iterator_fwd.hpp> #include <type_traits> #include <optional> namespace boost::parser::detail { namespace text { struct no_op_repacker { template<class T> 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<bool Enable = Bidi, typename = std::enable_if_t<Enable>> #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<bool Enable = !Bidi, typename = std::enable_if_t<Enable>> #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<I> first; [[no_unique_address]] S last; [[no_unique_address]] Then then; }; template<typename I, typename S, typename Repack> 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<FromFormat, ToFormat, I, S, ErrorHandler> first, utf_iterator<FromFormat, ToFormat, I, S, ErrorHandler> 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<FromFormat, ToFormat, I, S, ErrorHandler> first, S last, Repack repack); template<typename I, typename S, typename Repack> 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<I> S, typename Repack = no_op_repacker> requires std::forward_iterator<I> #else template<typename I, typename S, typename Repack = no_op_repacker> #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<format FormatTag, utf_iter I, std::sentinel_for<I> S, class Repack> #else template<format FormatTag, typename I, typename S, class Repack> #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<typename I, typename S, typename Repack> constexpr auto unpack_iterator_and_sentinel_impl(I first, S last, Repack repack) { using value_type = detail::iter_value_t<I>; if constexpr ( std::is_same_v<value_type, char> #if defined(__cpp_char8_t) || std::is_same_v<value_type, char8_t> #endif ) { return unpack_result<format::utf8, I, S, Repack>{ first, last, repack}; } else if constexpr ( #if defined(_MSC_VER) std::is_same_v<value_type, wchar_t> || #endif std::is_same_v<value_type, char16_t>) { return unpack_result<format::utf16, I, S, Repack>{ first, last, repack}; } else if constexpr ( #if !defined(_MSC_VER) std::is_same_v<value_type, wchar_t> || #endif std::is_same_v<value_type, char32_t>) { return unpack_result<format::utf32, I, S, Repack>{ first, last, repack}; } else { static_assert( std::is_same_v<Repack, no_such_type>, "Unpacked iterator is not a utf_iter!"); return 0; } } } }} #include <boost/parser/detail/text/transcode_iterator.hpp> 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<FromFormat, ToFormat, I, S, ErrorHandler> first, utf_iterator<FromFormat, ToFormat, I, S, ErrorHandler> last, Repack repack) { using iterator = utf_iterator<FromFormat, ToFormat, I, S, ErrorHandler>; if constexpr ( #if BOOST_PARSER_DETAIL_TEXT_USE_CONCEPTS std::bidirectional_iterator<I> #else std::is_base_of_v< std::bidirectional_iterator_tag, typename std::iterator_traits<I>::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<iterator, int, decltype(first.end()), Repack, false>( 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<FromFormat, ToFormat, I, S, ErrorHandler> first, S last, Repack repack) { using iterator = utf_iterator<FromFormat, ToFormat, I, S, ErrorHandler>; if constexpr ( #if BOOST_PARSER_DETAIL_TEXT_USE_CONCEPTS std::bidirectional_iterator<I> #else std::is_base_of_v< std::bidirectional_iterator_tag, typename std::iterator_traits<I>::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<iterator, int, S, Repack, false>(last, repack)); } } }}} #endif