diff --git a/include/beman/utf_view/code_unit_view.hpp b/include/beman/utf_view/code_unit_view.hpp index 998d0586..933fb7fd 100644 --- a/include/beman/utf_view/code_unit_view.hpp +++ b/include/beman/utf_view/code_unit_view.hpp @@ -15,7 +15,7 @@ namespace beman::utf_view { -/* PAPER: namespace std::uc { */ +/* PAPER: namespace std::ranges::views { */ namespace detail { diff --git a/include/beman/utf_view/detail/concepts.hpp b/include/beman/utf_view/detail/concepts.hpp index fd7b7fce..ca00e4b8 100644 --- a/include/beman/utf_view/detail/concepts.hpp +++ b/include/beman/utf_view/detail/concepts.hpp @@ -15,7 +15,7 @@ namespace beman::utf_view { -/* PAPER: namespace std::uc { */ +/* PAPER: namespace std::ranges { */ template using exposition_only_with_reference = T&; // exposition only diff --git a/include/beman/utf_view/to_utf_view.hpp b/include/beman/utf_view/to_utf_view.hpp index 8cd7af2e..7d3db695 100644 --- a/include/beman/utf_view/to_utf_view.hpp +++ b/include/beman/utf_view/to_utf_view.hpp @@ -71,7 +71,7 @@ namespace detail { } // namespace detail -/* PAPER: namespace std::uc { */ +/* PAPER: namespace std::ranges { */ /* PAPER */ @@ -1160,6 +1160,8 @@ inline constexpr detail::to_utf_impl to_utf16; inline constexpr detail::to_utf_impl to_utf32; +/* PAPER: namespace views { */ +/* PAPER: */ /* PAPER: template<@*code-unit-to*@ ToType> */ /* PAPER: inline constexpr @*unspecified*@ to_utf; */ /* PAPER: */ @@ -1168,11 +1170,13 @@ inline constexpr detail::to_utf_impl to_utf32; /* PAPER: inline constexpr @*unspecified*@ to_utf16; */ /* PAPER: */ /* PAPER: inline constexpr @*unspecified*@ to_utf32; */ +/* PAPER: */ +/* PAPER: } */ +/* PAPER: */ +/* PAPER: } */ } // namespace beman::utf_view -/* PAPER: } */ - template inline constexpr bool std::ranges::enable_borrowed_range< beman::utf_view::exposition_only_to_utf_view_impl> = @@ -1194,16 +1198,16 @@ inline constexpr bool std::ranges::enable_borrowed_range */ /* PAPER: inline constexpr bool enable_borrowed_range< */ -/* PAPER: std::uc::exposition_only_to_utf_view_impl> = enable_borrowed_range; */ +/* PAPER: std::exposition_only_to_utf_view_impl> = enable_borrowed_range; */ /* PAPER: */ /* PAPER: template */ -/* PAPER: inline constexpr bool enable_borrowed_range> = enable_borrowed_range; */ +/* PAPER: inline constexpr bool enable_borrowed_range> = enable_borrowed_range; */ /* PAPER: */ /* PAPER: template */ -/* PAPER: inline constexpr bool enable_borrowed_range> = enable_borrowed_range; */ +/* PAPER: inline constexpr bool enable_borrowed_range> = enable_borrowed_range; */ /* PAPER: */ /* PAPER: template */ -/* PAPER: inline constexpr bool enable_borrowed_range> = enable_borrowed_range; */ +/* PAPER: inline constexpr bool enable_borrowed_range> = enable_borrowed_range; */ /* PAPER: */ /* PAPER: } */ diff --git a/paper/P2728.md b/paper/P2728.md index 736f6672..5b4bea3e 100644 --- a/paper/P2728.md +++ b/paper/P2728.md @@ -119,6 +119,7 @@ monofont: "DejaVu Sans Mono" - Replace code unit views with range adaptor closure objects that are expression-equivalent to P3117 `transform_view` - Move `null_sentinel` and `null_term` into P3705 +- Remove `std::uc` namespace and replace it with `std::ranges` and `std::ranges::views` # Motivation @@ -169,7 +170,7 @@ code units in sequence may encode a particular code point. ```cpp std::u32string hello_world = - u8"こんにちは世界" | std::uc::to_utf32 | std::ranges::to(); + u8"こんにちは世界" | std::views::to_utf32 | std::ranges::to(); ``` ## Sanitizing potentially invalid Unicode @@ -181,7 +182,7 @@ Substitution of Maximal Subparts: ```cpp template std::basic_string sanitize(CharT const* str) { - return std::null_term(str) | std::uc::to_utf | std::ranges::to>(); + return std::null_term(str) | std::views::to_utf | std::ranges::to>(); } ``` @@ -189,7 +190,7 @@ std::basic_string sanitize(CharT const* str) { ```cpp std::optional last_nonascii(std::ranges::view auto str) { - for (auto c : str | std::uc::to_utf32 | std::views::reverse + for (auto c : str | std::views::to_utf32 | std::views::reverse | std::views::filter([](char32_t c) { return c > 0x7f; }) | std::views::take(1)) { return c; @@ -259,14 +260,14 @@ void change_playing_card_suits() { Let's say that we want to take code points that we got from ICU, and transcode them to UTF-8. The problem is that ICU's code point type is `int`. Since `int` is not a character type, it's not deduced by `to_utf8` to be UTF-32 data. We -can address this by using the `std::uc::as_char32_t` to cast the `int`s to +can address this by using the `std::views::as_char32_t` to cast the `int`s to `char32_t`: ```cpp std::vector input = get_icu_code_points(); // This is ill-formed without the as_char32_t adaptation. auto input_utf8 = - input | std::uc::as_char32_t | std::uc::to_utf8 | std::ranges::to(); + input | std::views::as_char32_t | std::views::to_utf8 | std::ranges::to(); ``` # Proposed design @@ -299,7 +300,7 @@ implementation-dependent. ### Rejecting ranges of `char` and `wchar_t` ```c++ -using namespace std::uc; +using namespace std::views; auto v1 = u8"text" | to_utf32; // Ok. auto v2 = u"text" | to_utf8; // Ok. @@ -318,7 +319,7 @@ auto v10 = std::wstring | as_charN_t | to_utf8; // Ok. ### Accepting ranges of `char` and `wchar_t` ```c++ -using namespace std::uc; +using namespace std::views; auto v1 = u8"text" | to_utf32; // Ok. auto v2 = u"text" | to_utf8; // Ok. @@ -420,7 +421,7 @@ practice. Rejecting `char` and `wchar_t` for UTF transcoding will therefore have limited benefits. On the other hand, rejecting these types will send users over to Stack Overflow to discover they need to copy boilerplate called -`| std::uc::as_char8_t` for reasons that will seem academic to most of them. +`| std::views::as_char8_t` for reasons that will seem academic to most of them. ## Error handling mechanism @@ -441,8 +442,8 @@ The UTF transcoding views in this paper provide such a basis operation by adding an `success()` member function to the iterator of the transcoding view, which informs users whether the current code point is a U+FFFD that was inserted in response to an invalid code unit sequence. The `success()` member -function returns a `std::expected`, where -`std::uc::transcoding_error` is a new enum class containing enumerators for +function returns a `std::expected`, where +`std::transcoding_error` is a new enum class containing enumerators for every category of transcoding error. Users who choose not to implement error handling will simply sanitize any @@ -456,12 +457,12 @@ by wrapping the iterator or by iterating with a traditional for loop: - Producing an error log message - Collecting statistics on transcoding errors - Implementing a custom transcoding view whose `value_type` is - `std::expected` + `std::expected` ### Why `std::expected`? The main alternative to consider here would be to specify that -default-constructed `std::uc::transcoding_error` values represent success, or +default-constructed `std::transcoding_error` values represent success, or add a `success` enumerator whose value is zero. There is precedent for doing this in the standard in the error handling approach of `std::from_chars`, which returns a `std::from_chars_result` containing a `std::errc` that has an @@ -520,7 +521,7 @@ but not vice versa. See [Appendix: Implementing Existing Practice for Error Handling](#appendix-implementing-existing-practice-for-error-handling) for code examples which demonstrate this. -### `std::uc::transcoding_error` enumerators +### `std::transcoding_error` enumerators - `truncated_utf8_sequence` - An ill-formed subsequence that matches the beginning of some well-formed @@ -4765,7 +4766,7 @@ we can always provide `base()`, we have no trouble returning a ``` template S, output_iterator O> transcode_result transcode_to_utf32(I first, S last, O out) { - auto r = ranges::subrange(first, last) | uc::as_utf32; + auto r = ranges::subrange(first, last) | views::as_utf32; auto copy_result = ranges::copy(r, out); @@ -4786,7 +4787,7 @@ standard. The transcoding views are lazy, as you'd expect. They also compose with the standard view adaptors, so just transcoding at most 10 UTF-16 code units out -of some UTF can be done with `foo | std::uc::to_utf16 | +of some UTF can be done with `foo | std::views::to_utf16 | std::ranges::views::take(10)`. Error handling strategies of the user's choosing can be implemented by the @@ -4806,7 +4807,7 @@ produce a replacement character; there is no danger of UB. ## Exposition-only concepts and traits ```c++ -namespace std::uc { +namespace std::ranges { template constexpr bool @*is-empty-view*@ = false; @@ -4860,7 +4861,7 @@ namespace std::uc { ## Transcoding views ```c++ -namespace std::uc { +namespace std::ranges { enum class transcoding_error { truncated_utf8_sequence, @@ -5276,6 +5277,8 @@ namespace std::uc { template to_utf32_view(R&&) -> to_utf32_view>; +namespace views { + template<@*code-unit-to*@ ToType> inline constexpr @*unspecified*@ to_utf; @@ -5284,22 +5287,25 @@ namespace std::uc { inline constexpr @*unspecified*@ to_utf16; inline constexpr @*unspecified*@ to_utf32; + +} + } namespace std::ranges { template inline constexpr bool enable_borrowed_range< - std::uc::@*to-utf-view-impl*@> = enable_borrowed_range; + std::@*to-utf-view-impl*@> = enable_borrowed_range; - template - inline constexpr bool enable_borrowed_range> = enable_borrowed_range; + template + inline constexpr bool enable_borrowed_range> = enable_borrowed_range; - template - inline constexpr bool enable_borrowed_range> = enable_borrowed_range; + template + inline constexpr bool enable_borrowed_range> = enable_borrowed_range; - template - inline constexpr bool enable_borrowed_range> = enable_borrowed_range; + template + inline constexpr bool enable_borrowed_range> = enable_borrowed_range; } ``` @@ -5494,17 +5500,17 @@ since a `utf_view` is empty if and only if its underlying range is empty. ## Add code unit adaptors ``` -namespace std::uc { +namespace std::ranges::views { template struct @*implicit-cast-to*@ { constexpr T operator()(auto x) const noexcept { return x; } }; - inline constexpr @*unspecified*@ as_char8_t; - + inline constexpr @*unspecified*@ as_char8_t; + inline constexpr @*unspecified*@ as_char16_t; - + inline constexpr @*unspecified*@ as_char32_t; } ``` @@ -5723,7 +5729,7 @@ size_t iconv(iconv_t cd, const char** inbuf, size_t* inbytesleft, char** outbuf, assert(outbuf); assert(*outbuf); assert(outbytesleft); - auto view = std::ranges::subrange(*inbuf, *inbuf + *inbytesleft) | std::uc::to_utf32; + auto view = std::ranges::subrange(*inbuf, *inbuf + *inbytesleft) | std::views::to_utf32; for (auto it = std::ranges::begin(view), end = std::ranges::end(view); it != end;) { if (it.success()) { if (*outbytesleft < sizeof(char32_t)) { @@ -5826,7 +5832,7 @@ constexpr char16_t* u_strFromUTF8WithSub( ++*pNumSubstitutions; if (subchar > 0xFFFF) { std::array subchar_utf16{}; - std::ranges::copy(std::array{subchar} | std::uc::to_utf16, subchar_utf16.data()); + std::ranges::copy(std::array{subchar} | std::views::to_utf16, subchar_utf16.data()); write(subchar_utf16[0]); if (destCapacity == 0) { return dest; @@ -5845,9 +5851,9 @@ constexpr char16_t* u_strFromUTF8WithSub( }; if (srcLength == -1) { - return impl(std::null_term(src) | std::uc::to_utf16); + return impl(std::null_term(src) | std::views::to_utf16); } else { - return impl(std::ranges::subrange(src, src + srcLength) | std::uc::to_utf16); + return impl(std::ranges::subrange(src, src + srcLength) | std::views::to_utf16); } } ``` @@ -5912,17 +5918,17 @@ constexpr int MultiByteToWideChar(unsigned int CodePage, unsigned long dwFlags, }; if (cbMultiByte == -1) { if constexpr (sizeof(wchar_t) == 2) { - return impl(std::null_term(lpMultiByteStr) | std::uc::to_utf16); + return impl(std::null_term(lpMultiByteStr) | std::views::to_utf16); } else { - return impl(std::null_term(lpMultiByteStr) | std::uc::to_utf32); + return impl(std::null_term(lpMultiByteStr) | std::views::to_utf32); } } else { if constexpr (sizeof(wchar_t) == 2) { return impl(std::ranges::subrange(lpMultiByteStr, lpMultiByteStr + cbMultiByte) | - std::uc::to_utf16); + std::views::to_utf16); } else { return impl(std::ranges::subrange(lpMultiByteStr, lpMultiByteStr + cbMultiByte) | - std::uc::to_utf32); + std::views::to_utf32); } } }