This page is a snapshot from the LWG issues list, see the Library Active Issues List for more information and the meaning of WP status.

### 2779. [networking.ts] Relax requirements on buffer sequence iterators

Section: 16.2.1 [networking.ts::buffer.reqmts.mutablebuffersequence] Status: WP Submitter: Vinnie Falco Opened: 2016-10-05 Last modified: 2021-02-27

Priority: Not Prioritized

View all issues with WP status.

Discussion:

Addresses: networking.ts

We propose to relax the ForwardIterator requirements of buffer sequences in [networking.ts] by allowing buffer sequence iterators to return rvalues when dereferenced, and skip providing `operator->`. A paraphrased explanation of why the referential equality rules of ForwardIterator are harmful to the buffer sequence requirements comes from N4128, 3.3.7 "Ranges For The Standard Library":

> The [networking.ts] dependence on ForwardIterator in the buffer sequence requirements ties together the traversal and access properties of iterators. For instance, no forward iterator may return an rvalue proxy when it is dereferenced; the ForwardIterator concept requires that unary `operator*` return an lvalue. This problem has serious consequences for lazy evaluation that applies transformations to buffer sequence elements on the fly. If the transformation function does not return an lvalue, the range's iterator can model no concept stronger than InputIterator, even if the resulting iterator could in theory support BidirectionalIterator. The result in practice is that most range adaptors today will not be compatible with [networking.ts], thereby limiting the types that [networking.ts] can be passed, for no good reason.

Consider a user defined function `trim` which lazily adapts a `ConstBufferSequence`, such that when iterating the buffers in the new sequence, each buffer appears one byte shorter than in the underlying sequence:

>     #include <boost/range/adaptor/transformed.hpp>

>     struct trim
>     {
>       using result_type = const_buffer;
>       result_type operator()(const_buffer b)
>       {
>         return const_buffer{b.data(), b.size() - 1};
>       }
>     };

>     template <ConstBufferSequence>
>     auto
>     trim(ConstBufferSequence const& buffers)
>     {
>       using namespace boost::adaptors;
>       return buffers | transformed(trim{});
>     }

`trim` returns a BidirectionalRange, whose `const_iterator` returns an rvalue when dereferenced. This breaks the requirements of ForwardIterator. A solution that meets the referential equality rules of ForwardIterator, would be to evaluate the transformed sequence upon construction (for example, by storing each transformed `const_buffer` in a `vector`). Unfortunately this work-around is more expensive since it would add heap allocation which the original example avoids.

The requirement of InputIterator `operator->` is also unnecessary for buffer sequence iterators, and should be removed. Because [networking.ts] only requires that a buffer sequence iterator's `value_type` be convertible to `const_buffer` or `mutable_buffer`, implementations of [networking.ts] cannot assume the existence of any particular member functions or data members other than an implicit conversion to `const_buffer` or `mutable_buffer`. Removing the requirement for `operator->` to be present, provides additional relief from the referential equality requirements of ForwardIterator and allows transformations of buffer sequences to meet the requirements of buffer sequences.

This proposal imposes no changes on existing implementations of [networking.ts]. It does not change anything in the standard. The proposal is precise, minimal, and allows range adapters to transform buffer sequences in optimized, compatible ways.

[Issues processing Telecon 2016-10-07]

Status set to LEWG

[2017-02-21, Jonathan comments]

The use of the term "strict aliasing" in the issue discussion is misleading as that refers to type-based alias analysis in compilers, but the rule for `ForwardIterator`s is related to referential equality and not strict aliasing.

[2017-02-22, Vinnie Falco comments]

We have eliminated the use of the term "strict aliasing" from the discussion.

[2017-07-10, Toronto, LEWG comments]

Status change: LEWG → Open.

Forward to LWG with the note that they may want to use "input +" instead of "bidirectional -". Unanimous yes.

[2017-07 Toronto Wednesday night issue processing]

Status to Ready

Proposed resolution:

This wording is relative to N4588.

1. Modify 16.2.1 [networking.ts::buffer.reqmts.mutablebuffersequence] as indicated:

   > An iterator type meeting the requirements for bidirectional iterators (C++Std [bidirectional.iterators]) whose value type is convertible to `mutable_buffer`

   > An iterator type whose `reference` type is convertible to `mutable_buffer`, and which satisfies all the requirements for bidirectional iterators (C++Std [bidirectional.iterators]) except that:

   > 1. there is no requirement that `operator->` is provided, and
   > 2. there is no requirement that `reference` be a reference type.

2. Modify 16.2.2 [networking.ts::buffer.reqmts.constbuffersequence] as indicated:

   > An iterator type meeting the requirements for bidirectional iterators (C++Std [bidirectional.iterators]) whose value type is convertible to `const_buffer`.

   > An iterator type whose `reference` type is convertible to `const_buffer`, and which satisfies all the requirements for bidirectional iterators (C++Std [bidirectional.iterators]) except that:

   > 1. there is no requirement that `operator->` is provided, and
   > 2. there is no requirement that `reference` be a reference type.