| Document #: | P4030R0 [Latest] [Status] |
| Date: | 2026-02-22 |
| Project: | Programming Language C++ |
| Audience: |
SG-9 Ranges SG-16 Unicode LEWG |
| Reply-to: |
Eddie Nolan <eddiejnolan@gmail.com> |
The main reason for adding these views is to assist users of the UTF
transcoding range adaptors (see [P2728R7]). That paper introduces the
adaptors to_utf8,
to_utf16, and
to_utf32, which take as input ranges
of char8_t,
char16_t,
and
char32_t.
The input and output of these views use native endianness. But users
often need to convert to and from UTF encodings with specific
endianness: UTF-16LE, UTF-16BE, UTF-32LE, and UTF-32BE.
Rather than introduce a combinatorial explosion of UTF adaptors with various endianness of input and output, we should follow the single responsibility principle and add standard endianness views so users can handle endianness separately.
In addition to UTF transcoding, this facility will help users handle endianness conversions for other streams of data, such as network protocols (TCP/IP, TLS, DNS, etc) and file formats (BMP, TIFF).
Before
|
After
|
|---|---|
|
|
Before
|
After
|
|---|---|
|
|
This paper depends on [P3117R1] “Extending Conditionally Borrowed”.
Add the following subclause to 25.7 [range.adaptors]:
struct byteswap-if-native-is-big-endian { // exposition only/
constexpr auto operator()(auto x) const noexcept {
if constexpr (endian::native == endian::big) {
return std::byteswap(x);
} else {
return x;
}
}
};struct byteswap-if-native-is-little-endian { // exposition only/
constexpr auto operator()(auto x) const noexcept {
if constexpr (endian::native == endian::little) {
return std::byteswap(x);
} else {
return x;
}
}
};If std::endian::native != std::endian::big
and std::endian::native != std::endian::little,
the following four range adaptor objects are not provided.
Otherwise:
The name from_little_endian
denotes a range adaptor object ([range.adaptor.object]). Let
E be an expression and let
T be remove_cvref_t<decltype((E))>.
If ranges::range_value_t<T>
does not model integral, from_little_endian(E)
is ill-formed. The expression from_little_endian(E)
is expression-equivalent to:
T is a specialization of
empty_view ([range.empty.view]),
then empty_view<range_value_t<T>>{}.ranges::transform_view(std::views::all(E), byteswap-if-native-is-big-endian{}).The name from_big_endian denotes
a range adaptor object ([range.adaptor.object]). Let
E be an expression and let
T be remove_cvref_t<decltype((E))>.
If ranges::range_value_t<T>
does not model integral, from_big_endian(E)
is ill-formed. The expression from_big_endian(E)
is expression-equivalent to:
T is a specialization of
empty_view ([range.empty.view]),
then empty_view<range_value_t<T>>{}.ranges::transform_view(std::views::all(E), byteswap-if-native-is-little-endian{}).The name to_little_endian denotes
a range adaptor object ([range.adaptor.object]). Let
E be an expression and let
T be remove_cvref_t<decltype((E))>.
If ranges::range_value_t<T>
does not model integral, to_little_endian(E)
is ill-formed. The expression to_little_endian(E)
is expression-equivalent to:
T is a specialization of
empty_view ([range.empty.view]),
then empty_view<range_value_t<T>>{}.ranges::transform_view(std::views::all(E), byteswap-if-native-is-big-endian{}).The name to_big_endian denotes a
range adaptor object ([range.adaptor.object]). Let
E be an expression and let
T be remove_cvref_t<decltype((E))>.
If ranges::range_value_t<T>
does not model integral, to_big_endian(E)
is ill-formed. The expression to_big_endian(E)
is expression-equivalent to:
T is a specialization of
empty_view ([range.empty.view]),
then empty_view<range_value_t<T>>{}.ranges::transform_view(std::views::all(E), byteswap-if-native-is-little-endian{}).Add the following macro definition to 17.3.2
[version.syn], header
<version>
synopsis, with the value selected by the editor to reflect the date of
adoption of this paper:
#define __cpp_lib_endian_views 20XXXXL // also in <ranges>from_little_endian/to_little_endian
and
from_big_endian/to_big_endian
do the same thing. We include both names for the sake of pipeline
readability; it would be harder to read the pipelines if we used names
like from_or_to_little_endian or
byteswap_if_native_is_big_endian.