No Endian Views
- Document number:
- P4247R0
- Date:
2026-07-11 - Audience:
- LEWG
- Project:
- ISO/IEC 14882 Programming Languages — C++, ISO/IEC JTC1/SC22/WG21
- Reply-to:
- Jan Schultke <janschultke@gmail.com>
- GitHub Issue:
- wg21.link/P4247/github
- Source:
- github.com/eisenwave/cpp-proposals/blob/master/src/no-endian-views.cow
Endian Views
should not be pursued.
Contents
Introduction
Endian Views are of limited use to serialization
The serialization pipeline
Contrived motivation
Problems with range checks
Endian Views are a pessimization
Endian Views work poorly for floating-point
Proposed action
References
1. Introduction
[P4030R1] Endian Views
introduces Endianness adaptors
,
,
, and
.
I argue that these are not suitable for standardization because they are
unfit for the intended use case,
for the reasons described below.
1.1. Endian Views are of limited use to serialization
1.1.1. The serialization pipeline
Serialization and deserialization is a pipeline with several steps. Let's take deserialization of UTF-32 code points for example:
CONSUME → REINTERPRET → ADJUST ENDIAN std::byte[4] uint32_t uint32_t
The key problem with Endian Views is that they are intended to assist in this pipeline,
but they only cover the last transformation step,
i.e.
1.1.2. Contrived motivation
[P4030R1] §2 Before/After Tables
contains a motivating example involving
constexpr vector < uint32_t > utf16be_to_utf32be ( const vector < uint16_t > & utf16be_data ) { /* ... */ }
This signature is contrived
because it doesn't make sense for the user to hold a
where the Endianness of the elements is incorrect
(at least not if Endian Views are used);
nothing can be meaningfully done with that data, other than
- shooting yourself in the foot by forgetting that the data is not usable due to having the wrong Endianness yet,
- making it usable by swapping Endianness (but why didn't you do that sooner?), or
- serializing the data without Endian swap, but then Endian Views were neither used for deserialization nor serialization.
However, again, Endian Views are useless for this purpose because the use case deliberately avoids ever performing Endianness adjustment.
The comparison table the paper should be showing is:
| Before | After |
|---|---|
|
|
|
… where can be trivially implemented by the user as:
This comparison table makes a few things readily apparent:
-
Endian Views provide incredibly low value because they are just a shorthand
for wrapping a trivial-to-implement utility function in
.views :: transform There is one minor exception to this: if the original data is contiguous and the Endianness conversion is a no-op, the result is also contiguous, whereas never produces a contiguous range.transform_view - Endian Views address just a small part of the pipeline; the benefits are marginal if not more of the pipeline is covered by the feature.
-
Both before and after, the code expresses the overall idea of
loading Big-Endian data
in several pieces like chunking, reinterpretation, and Endian swapping. Neither side is expressive.
A significant improvement over the left column would look like:
1.1.3. Problems with range checks
However, both with this version and all the previous ones,
there is an issue with needing to check each iteration over a
element whether at least four bytes remain in the range.
If we didn't use views whatsoever, we could easily check whether the amount of bytes
is a multiple of four once in the function,
and perform the conversion in bulk unchecked for the remainder of the function.
Whether the compiler can factor out this range check is questionable, and it could significantly worsen performance of using views if it cannot. [P4030R1] does not investigate this problem.
1.2. Endian Views are a pessimization
Another major problem with Endian Views is that their intended usage is pessimized.
Consider a typical use case of serializing a as UTF-32LE in a file:
Due to how widespread Little-Endian architectures are,
the branch can also arguably be omitted by most users in favor of a two-line function,
where one line is:
Endian Views provide negative value for this use case
because not only would it require a lot more effort to use them here,
they would also drop the contiguity of the data
when transforming from to an ,
despite the fact that Endian Views try to preserve contiguity.
Curiously, the terms performance
, optimization
, or throughput
,
do not appear once in [P4030R1] as if this subject were not worth discussing.
This would not be that big of a problem
- if encoding of text wasn't a primary advertised use case (where we should at least care about our low-level utilities performing well), and
-
if the baseline wasn't a single call to
(which Endian Views can only perform worse than; the question is just how much worse).std :: fwrite
1.3. Endian Views work poorly for floating-point
The design of Endian Views is centered around integral types;
and other view types can only be used if the element type
of the transformed range is integral.
However, serialization is perfectly reasonable for other types,
such as .
For example, the
STL file format
is essentially a sequence of 32-bit floating-point values.
With the current design,
the user would have to add another two steps to the pipeline which bit-cast
to (and back)
to be able to use Endian Views.
This seems hostile and makes the feature even less attractive than it already is.
Even if this problem were resolved by making Endian Views accept anything trivially copyable, the more pressing issue is that not every floating-point bit pattern is valid for the type, and thus some may result in undefined behavior when returned from a function. This gives us a few options:
-
Accept that Endian Views for
can sometimes result in undefined behavior. Deal with it 😎float - Don't accept floating-point types ([P4030R1]).
- Accept only those floating-point types where byte-swapping is always well-defined.
-
Don't try to hold invalid floating-point values in the first place.
That is, use the
approach mentioned above.views :: from_bytes < float , endian :: big >
The first option reduces safety,
the second option is unergonomic, and
the third option is clunky and makes serialization non-portable.
The last option doesn't have any of these problems, and it demonstrates that [P4030R1] artificially creates a problem that cannot be solved without unpleasant trade-offs.
2. Proposed action
Do not pursue the design of [P4030R1].
If the design is pursued, [P4030R1] needs substantial work:
-
Provide proper design discussion of a view that converts directly from bytes
versus a view that only does the Endian swap.
Just because one can be composed from the other doesn't mean the smaller (Endian swap) utility
is automatically better,
just like composing
fromstd :: fwrite isn't a good idea, even though it may be academically satisfying.std :: putchar - Provide proper discussion of performance considerations. Currently, there is no mention of performance whatsoever.
- Discuss the intended use case and the existing practice in the targeted domains. That is, do established C++ libraries actually use views for their serialization purposes, and do those views use an Endian swap in the pipeline? Is that technique a creative invention of [P4030R1] or already established?
-
Discuss how much benefit Endian Views provide as compared to wrapping a simple utility function
in
. The paper currently does not even consider the possibility of aviews :: transform utility function rather thanstd :: from_big_endian .views :: from_big_endian
That doesn't mean that the overarching problem of serialization and deserialization with Endian transformation is not worth solving. It is worth solving, but not using Endian Views.