The problem I was trying to solve sounded pretty basic, but turned out to be a bit hairy.
I need to select some lines of arbitrary length from an input stream (file or standard input) and print them to output. In other words, a function that just echos the line would do the job. The input stream is encoded in UTF-8. For reasons that I don't quite understand, the normal <string>
mangles the stream, so I couldn't use:
std::string line;
std::readline(line);
std::cout << line;
I did solve it using basic_istream::getline()
; however, this function writes to a buffer, and I need to tell it how big the buffer is. To make it deal with lines of arbitrary length, I need to read to a buffer in a loop, checking whether failbit
is set (when the end of the line wasn't reached).
Then, the easier solution was to use iterators on the input and the output stream, like this:
template<typename I, typename O, typename T>
I copy_until(I first, I last, O d_first, T delim)
{
while (first != last && *first != delim) {
*d_first = *first;
++first;
++d_first;
}
return first;
}
This copies from first
up to last
at most, and stops if the delimiter is encountered. It returns a pointer to the first character in the input range that was not copied.
It can be used like this to copy all input to output:
int main()
{
std::istreambuf_iterator<char> first(std::cin);
std::istreambuf_iterator<char> last;
std::ostreambuf_iterator<char> d_first(std::cout);
while (first != last) {
first = copy_until(first, last, d_first, '\n');
std::cout.put(*first);
++first;
}
}
The third argument of copy_until
could of course be a unary predicate, then instead of while (first != last && *first != delim)
it would say while (first != last && !p(*first))
.
More important questions:
- Is there an algorithm in
<algorithm>
that I have overlooked?copy_if
andpartition_point
come close, but they don't do exactly that, andpartition_point
followed bycopy_n
will not work with forward iterators. - I am not sure how to declare that the two iterators need to point to the same type as the type of the delimiter or the argument to the unary predicate.
- Not certain about the return value. This one is the most useful for my particular use case.
- Or maybe there is a much, much easier way that avoids this altogether. But
copy_until
might be useful in other contexts?