boost/parser/detail/text/concepts.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_CONCEPTS_HPP #define BOOST_PARSER_DETAIL_TEXT_CONCEPTS_HPP #include <boost/parser/detail/text/config.hpp> #include <boost/parser/detail/text/utf.hpp> #include <boost/parser/detail/text/detail/begin_end.hpp> #if BOOST_PARSER_DETAIL_TEXT_USE_CONCEPTS #include <ranges> #include <string_view> namespace boost::parser::detail { namespace text { BOOST_PARSER_DETAIL_TEXT_NAMESPACE_V2 { //[ concepts_concepts #ifdef _MSC_VER inline constexpr format wchar_t_format = format::utf16; #else inline constexpr format wchar_t_format = format::utf32; #endif template<typename T, format F> concept code_unit = (std::same_as<T, char8_t> && F == format::utf8) || (std::same_as<T, char16_t> && F == format::utf16) || (std::same_as<T, char32_t> && F == format::utf32) || (std::same_as<T, char> && F == format::utf8) || (std::same_as<T, wchar_t> && F == wchar_t_format); template<typename T> concept utf8_code_unit = code_unit<T, format::utf8>; template<typename T> concept utf16_code_unit = code_unit<T, format::utf16>; template<typename T> concept utf32_code_unit = code_unit<T, format::utf32>; template<typename T, format F> concept code_unit_iter = std::input_iterator<T> && code_unit<std::iter_value_t<T>, F>; template<typename T> concept utf_code_unit = utf8_code_unit<T> || utf16_code_unit<T> || utf32_code_unit<T>; template<typename T, format F> concept code_unit_range = std::ranges::input_range<T> && code_unit<std::ranges::range_value_t<T>, F>; template<typename T, format F> concept contiguous_code_unit_range = std::ranges::contiguous_range<T> && code_unit<std::ranges::range_value_t<T>, F>; template<typename T> concept utf8_iter = code_unit_iter<T, format::utf8>; template<typename T> concept utf8_range = code_unit_range<T, format::utf8>; template<typename T> concept contiguous_utf8_range = contiguous_code_unit_range<T, format::utf8>; template<typename T> concept utf16_iter = code_unit_iter<T, format::utf16>; template<typename T> concept utf16_range = code_unit_range<T, format::utf16>; template<typename T> concept contiguous_utf16_range = contiguous_code_unit_range<T, format::utf16>; template<typename T> concept utf32_iter = code_unit_iter<T, format::utf32>; template<typename T> concept utf32_range = code_unit_range<T, format::utf32>; template<typename T> concept contiguous_utf32_range = contiguous_code_unit_range<T, format::utf32>; template<typename T> concept code_point = utf32_code_unit<T>; template<typename T> concept code_point_iter = utf32_iter<T>; template<typename T> concept code_point_range = utf32_range<T>; template<typename T> concept utf_iter = utf8_iter<T> || utf16_iter<T> || utf32_iter<T>; template<typename T> concept utf_range = utf8_range<T> || utf16_range<T> || utf32_range<T>; template<typename T> concept grapheme_iter = // clang-format off std::input_iterator<T> && code_point_range<std::iter_reference_t<T>> && requires(T t) { { t.base() } -> code_point_iter; // clang-format on }; template<typename T> concept grapheme_range = std::ranges::input_range<T> && grapheme_iter<std::ranges::iterator_t<T>>; template<typename R> using code_point_iterator_t = decltype(std::declval<R>().begin().base()); template<typename R> using code_point_sentinel_t = decltype(std::declval<R>().end().base()); template<typename T, format F> concept grapheme_iter_code_unit = // clang-format off grapheme_iter<T> && requires(T t) { { t.base().base() } -> code_unit_iter<F>; // clang-format on }; template<typename T, format F> concept grapheme_range_code_unit = grapheme_range<T> && grapheme_iter_code_unit<std::ranges::iterator_t<T>, F>; namespace dtl { template<typename T, class CodeUnit> concept eraseable_insertable_sized_bidi_range = // clang-format off std::ranges::sized_range<T> && std::ranges::input_range<T> && requires(T t, CodeUnit const * it) { { t.erase(t.begin(), t.end()) } -> std::same_as<std::ranges::iterator_t<T>>; { t.insert(t.end(), it, it) } -> std::same_as<std::ranges::iterator_t<T>>; }; // clang-format on } template<typename T> concept utf8_string = // clang-format off utf8_code_unit<std::ranges::range_value_t<T>> && dtl::eraseable_insertable_sized_bidi_range< T, std::ranges::range_value_t<T>>; // clang-format on template<typename T> concept utf16_string = // clang-format off utf16_code_unit<std::ranges::range_value_t<T>> && dtl::eraseable_insertable_sized_bidi_range< T, std::ranges::range_value_t<T>>; // clang-format on template<typename T> concept utf_string = utf8_string<T> || utf16_string<T>; template<typename T> // clang-format off concept transcoding_error_handler = requires(T t, std::string_view msg) { { t(msg) } -> std::same_as<char32_t>; // clang-format on }; //] // Clang 13 defines __cpp_lib_concepts but not std::indirectly copyable. #if defined(__clang_major__) && __clang_major__ <= 13 template<typename In, typename Out> // clang-format off concept indirectly_copyable = std::indirectly_readable<In> && std::indirectly_writable<Out, std::iter_reference_t<In>>; // clang-format on #else template<typename In, typename Out> concept indirectly_copyable = std::indirectly_copyable<In, Out>; #endif }}} #endif namespace boost::parser::detail { namespace text { namespace detail { #if BOOST_PARSER_DETAIL_TEXT_USE_CONCEPTS template<typename T> using iterator_t = std::ranges::iterator_t<T>; template<typename T> using sentinel_t = std::ranges::sentinel_t<T>; template<typename T> using iter_value_t = std::iter_value_t<T>; template<typename T> using iter_reference_t = std::iter_reference_t<T>; template<typename T> using range_value_t = std::ranges::range_value_t<T>; template<typename T> using range_reference_t = std::ranges::range_reference_t<T>; template<typename T> using range_difference_t = std::ranges::range_difference_t<T>; #else template<typename T> using iterator_t = decltype(detail::begin(std::declval<T &>())); template<typename T> using sentinel_t = decltype(detail::end(std::declval<T &>())); template<typename T> using iter_value_t = typename std::iterator_traits<T>::value_type; template<typename T> using iter_reference_t = decltype(*std::declval<T &>()); template<typename T> using range_value_t = iter_value_t<iterator_t<T>>; template<typename T> using range_reference_t = iter_reference_t<iterator_t<T>>; template<typename T> using range_difference_t = std::ptrdiff_t; template<typename T> constexpr bool code_unit_v = #if defined(__cpp_char8_t) std::is_same_v<T, char8_t> || #endif std::is_same_v<T, char16_t> || std::is_same_v<T, char32_t> || std::is_same_v<T, char> || std::is_same_v<T, wchar_t>; #endif }}} #endif