C++ range I/O specification

Contents

  1. General
  2. Requirements
    1. Input requirements
    2. Output requirements
  3. Input operations
    1. Function template input
    2. Function template overwrite
    3. Function template back_insert
    4. Function template back_insert_n
    5. Function template front_insert
    6. Function template front_insert_n
    7. Function template insert
    8. Function template insert_n
  4. Output operations
    1. Function template write_all

General

This specification defines several functions and associated types that support the use of ranges with IOStreams.

Header <rangeio> synopsis

namespace std {
  // Generalized input operation
  template<class Range, class Iterator, class Behaviour>
    RangeInputOperation input(Range& range, Iterator i, Behaviour behaviour);
  template<class Range, class Behaviour>
    RangeInputOperation input(Range& range, Behaviour behaviour);
  
  // Overwriting input operation
  template<class Range>
    RangeInputOperation overwrite(Range& range);
  
  // Back inserting input operation
  template<class Range>
    RangeInputOperation back_insert(Range& range);
  template<class Range>
    RangeInputOperation back_insert_n(Range& range, size_t count);
  
  // Front inserting input operation
  template<class Range>
    RangeInputOperation front_insert(Range& range);
  template<class Range>
    RangeInputOperation front_insert_n(Range& range, size_t count);
  
  // General inserting input operation
  template<class Range, class Iterator>
    RangeInputOperation insert(Range& range, Iterator pos);
  template<class Range, class Iterator>
    RangeInputOperation insert_n(Range& range, Iterator pos, size_t count);
  
  // Output operation
  template<class Range>
    RangeOutputOperation write_all(Range&& range);
  template<class Range, class Delimiter>
    RangeOutputOperation write_all(Range&& range, Delimiter&& delim);
}

Requirements

Range I/O functions are functions that take a range, possibly with other arguments, and return range I/O operation objects that can be used in IOStreams insertion or extraction expressions to perform input or output using the range.

Range I/O functions and range I/O operation objects must not copy the provided range. For ranges given as an lvalue, they must keep a reference or pointer to the range. For ranges given as an rvalue, they must move the range into a locally-owned variable.

Behaviour is undefined if the range I/O operation object is used after the range goes out of scope or is modified by any other operation.

Range I/O operation objects must be MoveConstructible, MoveAssignable, and Destructible.

The range I/O operation objects returned by range I/O functions should be usable with input or output streams (as applicable) either by lvalue reference or rvalue reference. This is to support the following two use cases (r is a Range):

cin >> back_insert(r);

and

auto b = back_insert(r);
cin >> b;
// b may now be queried for information about the last read

All input and output operations should set the stream width value to 0 immediately before returning.

Input requirements

The generalized range input function takes a lvalue reference to a range, and a behaviour object that describes how values read from the stream are to be written to the range. Different behaviour types allow different ways of storing values read from the stream into the range.

A type satisfies the requirements of the behaviour type if the expressions shown in the table below are valid and have the indicated semantics. In that table and throughout this section:

  1. p is an instance of a range input operation type returned by a range input function;
  2. b is an instance of a range input operation behaviour type;
  3. r is a non-const lvalue reference to a range type (that is, a type that can be used as the argument of a range for loop);
  4. i is a valid iterator that references a location in r in the range [begin(r), end(r)) – it does not necessarily need to be the same type as returned by begin(r)/end(r), but it must be convertible to that type;
  5. It is the type of i;
  6. in is a non-const lvalue reference to an instance of basic_istream.
Expression Return type Pre/post-condition
b.prepare(r, i) tuple<bool, It> Called at the beginning of every input operation, and possibly during construction of the input operation. Allows the behaviour object to prepare for an input operation. The first element of the tuple indicates whether to attempt input, the second is the iterator to initialize next to.
b.read(in, r, i) tuple<bool, It, bool, bool> Called repeatedly during an input operation. Attempts to read and parse a value from in, and store it in r. The first element of the tuple indicates whether to continue attempting input, the second is the iterator to set next to, the third indicates whether a value was successfully retrieved from in, the fourth indicates whether a value was successfully stored in r.

The return value from the generalized input function is a range input operation type that can be used in stream extraction expressions by lvalue or rvalue. The input operation object type satisfies the following requirements:

Expression Return type Pre/post-condition
p.count size_t Equal to the number of values successfully read and parsed from in. Initially zero.
p.stored size_t Equal to the number of values stored in r. Initially zero.
p.next It An iterator to the next position in r where a value would be stored. Its initial value is either explicitly specified, or determined via a call to p.prepare(r, begin(r)).

Example:

struct back_insert_only_if_even
{
  using iterator_type = vector<int>::iterator;
  
  auto prepare(vector<int>& r, iterator_type /* not used here */)
  {
    return make_tuple(true, end(r));
  }
  
  auto read(istream& in, vector<int>& r, iterator_type /* not used here */)
  {
    auto v = int{};
    
    auto store_ok = false;
    auto read_ok = bool(in >> v);
    
    if (read_ok && !(v % 2))
    {
      r.push_back(v);
      store_ok = true;
    }
    
    return make_tuple(bool(in), end(r), read_ok, store_ok);
  }
};

auto r = vector<int>{};

auto p = input(r, back_insert_only_if_even{});

auto iss = istringstream{"1 2 3 4 5"};

iss >> p;

// r = { 2, 4 }
// p.count = 5
// p.stored = 2
// p.next = r.end()

All the standard range input functions behave the same as a call to the generalized range input function with an appropriate behaviour object.

Any formatting that would apply to the input of a single value type of the range must be applied to every element of the range. Input operations must set the stream width to zero immediately before returning.

Output requirements

Range output functions return a range output operation object that can be used with stream insertion operations by lvalue or rvalue. The output operation object type satisfies the requirements shown in the table below. In that table and throughout this section:

  1. p is an instance of a range output operation type returned by a range output function;
  2. r is a range type (that is, a type that can be used as the argument of a range for loop);
  3. It is the type returned by begin(r);
  4. out is a non-const lvalue reference to an instance of basic_ostream.
Expression Return type Pre/post-condition
p.count size_t Equal to the number of values successfully written to out. Initially zero.
p.next It An iterator to the next position in r to be read. This will be begin(r) before any output operations, and end(r) after any completely successful output operations.

Any formatting that would apply to the output of a single value type of the range must be applied to every element of the range. Output operations must set the stream width to zero immediately before returning.

After every element insertion, the state of the output stream is checked by the stream object’s conversion to bool, and if it is false, the operation ends immediately.

When the range is empty, an output operation should attempt an unformatted write of out.width() copies of out.fill() to out, then call out.width(0).

Input operations

Function template input

template <class Range, class Iterator, class Behaviour>
  RangeInputOperation input(Range& r, Iterator i, Behaviour b);
Returns:
A range input operation object that conforms to the behaviour described in the input requirements above, and that references r, initializes next to i, and uses the range input behaviour object b to control the input behaviour.
template <class Range, class Behaviour>
  RangeInputOperation input(Range& r, Behaviour b);
Note:
Same as the previous overload, with next initialized by the result of b.prepare(r, begin(r)).

Function template overwrite

template<class Range>
  RangeInputOperation overwrite(Range& r);
Returns:
A range input operation object that conforms to the behaviour described in the input requirements above, and that references r and initializes next to begin(r).
The behaviour reads values from the input stream and replaces the elements in r successively from beginning to end, stopping when r has been completely overwritten or input fails, whichever comes first.

Function template back_insert

template<class Range>
  RangeInputOperation back_insert(Range& r);
Returns:
A range input operation object that conforms to the behaviour described in the input requirements above, and that references r and initializes next to end(r).
The behaviour reads values from the input stream and uses r.push_back() to append elements to r, stopping when input fails.

Function template back_insert_n

template<class Range>
  RangeInputOperation back_insert_n(Range& r, size_t n);
Returns:
A range input operation object that conforms to the behaviour described in the input requirements above, and that references r and initializes next to end(r).
The behaviour reads values from the input stream and uses r.push_back() to append elements to r, stopping when n elements have been read/appended or input fails, whichever comes first.

Function template front_insert

template<class Range>
  RangeInputOperation front_insert(Range& r);
Returns:
A range input operation object that conforms to the behaviour described in the input requirements above, and that references r and initializes next to begin(r).
The behaviour reads values from the input stream and uses r.push_front() to prepend elements to r, stopping when input fails.

Function template front_insert_n

template<class Range>
  RangeInputOperation front_insert_n(Range& r, size_t n);
Returns:
A range input operation object that conforms to the behaviour described in the input requirements above, and that references r and initializes next to begin(r).
The behaviour reads values from the input stream and uses r.push_front() to prepend elements to r, stopping when n elements have been read/prepended or input fails, whichever comes first.

Function template insert

template<class Range,class Iterator>
  RangeInputOperation insert(Range& r, Iterator i);
Returns:
A range input operation object that conforms to the behaviour described in the input requirements above, and that references r and initializes next to i.
The behaviour reads values from the input stream and uses r.insert() at the position i to insert elements into r, stopping when input fails.

Function template insert_n

template<class Range,class Iterator>
  RangeInputOperation insert_n(Range& r, Iterator i, size_t n);
Returns:
A range input operation object that conforms to the behaviour described in the input requirements above, and that references r and initializes next to i.
The behaviour reads values from the input stream and uses r.insert() at the position i to insert elements into r, stopping when n elements have been read/inserted or input fails, whichever comes first.

Output operations

Function template write_all

template <class Range>
  RangeOutputOperation write_all(Range&& r);
Returns:
A range output operation object that conforms to the behaviour described in the output requirements above, and that references r and initializes next to begin(r).
The behaviour writes successive values from r to the output stream, stopping when all elements of r have been written or output fails, whichever comes first.
template <class Range, class Delimiter>
  RangeOutputOperation write_all(Range&& r, Delimiter&& d);
Returns:
A range output operation object that conforms to the behaviour described in the output requirements above, and that references r and initializes next to begin(r).
The behaviour writes successive values from r to the output stream, stopping when all elements of r have been written or output fails, whichever comes first.
After every element except the last, the delimiter d is written to the output stream.