PrevUpHomeNext

Concepts

C++20 Concepts

All interfaces in Boost.Text are constrined either by SFINAE or C++20 concepts. The SFIANE constrains adhere as closely as possible to the C++20 concepts, listed here. Even though the pre-C++20 code uses a naming convention for template parameters, the rest of the documentation will use the C++20 concept names. See the bottom of this page for the mapping from pre-C++20 template parameter names to C++20 concept names.

From concepts.hpp:

template<typename T, format F>
concept code_unit = std::integral<T> && sizeof(T) == (int)F;

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::bidirectional_iterator<T> && code_unit<std::iter_value_t<T>, F>;

template<typename T, format F>
concept code_unit_pointer =
    std::is_pointer_v<T> && code_unit<std::iter_value_t<T>, F>;

template<typename T, format F>
concept code_unit_range = std::ranges::bidirectional_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_pointer = code_unit_pointer<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_pointer = code_unit_pointer<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_pointer = code_unit_pointer<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 grapheme_iter =
    // clang-format off
    std::bidirectional_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::bidirectional_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>
    concept eraseable_sized_bidi_range =
        // clang-format off
        std::ranges::sized_range<T> &&
        std::ranges::bidirectional_range<T> && requires(T t) {
        { t.erase(t.begin(), t.end()) } ->
            std::same_as<std::ranges::iterator_t<T>>;
        // clang-format on
    };
}

template<typename T>
concept utf8_string =
    // clang-format off
    dtl::eraseable_sized_bidi_range<T> &&
    utf8_code_unit<std::ranges::range_value_t<T>> &&
    requires(T t, char const * it) {
    { t.insert(t.end(), it, it) } ->
        std::same_as<std::ranges::iterator_t<T>>;
    // clang-format on
};

template<typename T>
concept utf16_string =
    // clang-format off
    dtl::eraseable_sized_bidi_range<T> &&
    utf16_code_unit<std::ranges::range_value_t<T>> &&
    requires(T t, uint16_t const * it) {
    { t.insert(t.end(), it, it) } ->
        std::same_as<std::ranges::iterator_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) {
    { t("") } -> code_point;
    // clang-format on
};

template<typename T>
concept utf_iter = utf8_iter<T> || utf16_iter<T> || utf32_iter<T>;

template<typename T>
// clang-format off
concept utf_range_like =
    utf8_range<std::remove_reference_t<T>> ||
    utf16_range<std::remove_reference_t<T>> ||
    utf32_range<std::remove_reference_t<T>> ||
    utf8_pointer<std::remove_reference_t<T>> ||
    utf16_pointer<std::remove_reference_t<T>> ||
    utf32_pointer<std::remove_reference_t<T>>;
// clang-format on

From word_break.hpp:

template<typename T>
concept word_prop_func = std::invocable<T, uint32_t> &&
    std::convertible_to<std::invoke_result_t<T, uint32_t>, word_property>;

template<typename T>
concept word_break_func =
    std::invocable<T, uint32_t, uint32_t, uint32_t, uint32_t, uint32_t> &&
        std::convertible_to<
            std::invoke_result_t<
                T,
                uint32_t,
                uint32_t,
                uint32_t,
                uint32_t,
                uint32_t>,
            bool>;

From line_break.hpp:

template<typename T, typename I, typename Extent>
concept line_break_cp_extent_func = std::invocable<T, I, I> &&
    std::convertible_to<std::invoke_result_t<T, I, I>, Extent>;

From collation_search.hpp:

template<typename T, typename I, typename S>
concept searcher_break_func = std::invocable<T, I, I, S> &&
    std::convertible_to<std::invoke_result_t<T, I, I, S>, I>;

template<typename T, typename I, typename S>
concept searcher = std::invocable<T, I, S> &&
    std::convertible_to<std::invoke_result_t<T, I, S>, utf32_view<I>>;

Pre-C++20 Concept Emulation

All constraints in the pre-C++20 interfaces are implemented using SFINAE. All such interfaces use a template parameter naming convention to communicate the notional concept that applies to that template parameter. Below are all the names that are used. Each name corresponds to a C++20 concept, and emulates the corresponding concept as closely as possible. This table summarizes the correspondence:

Table 1.8. Pre-C++20 Template Parameter Names and Their Associated C++20 Concepts

Pre-C++20 Template Parameter Name

C++20 Concept

CharIter

utf8_iter

CharRange

utf8_range

ContigCharRange

contiguous_utf8_range

CUIter

code_unit_iterator

CURange

code_unit_range

CPIter

code_point_iter

CPRange

code_point_range

GraphemeIterator

grapheme_iter

GraphemeRange

grapheme_range

GraphemeIterCUator

grapheme_iter_code_unit

GraphemeRangeCU

grapheme_range_code_unit

CPExtentFunc

line_break_cp_extent_func

WordPropFunc

word_prop_func

CPWordBreakFunc

word_break_func

BreakFunc

searcher_break_func

Searcher

searcher



PrevUpHomeNext