My problem is more complex than this, so I've narrowed it down to a very simple example that would show me enough to know how to handle the rest.
Say I have an input iterator. I want make a new input iterator derived from it, where each element is the combination of multiple sequential elements of the original input with the following pattern. The run length is encoded in the input sequence.
Input:
{ 1 1 2 3 4 4 6 7 8 9 ... }
Output:
{ (1) (3+4) (6+7+8+9) ... }
I was thinking a function like this could process a single element and increment the input begin iterator (passed by reference). There are a few questions in my comments, plus I'd like to know if there's a good way to do it for the entire stream of elements.
EDIT: I'm aware there's a bug in the call to std::advance
where the tmp
iterator is incremented to be exactly end
, which would be valid for this code. Let's focus on the rest of my questions and I'll fix that. Edit 2: should be fixed now?
template<class TInputIterator, class TOutputIterator>
void process_single(TInputIterator& begin, TInputIterator end, TOutputIterator destination)
{
std::iterator_traits<TInputIterator>::value_type run_length = *begin;
++begin;
// is there a better way to specify run_length elements to accumulate() without having to call advance() here?
TInputIterator tmp(begin);
std::advance(tmp, run_length);
// Edited: this condition should work for the different kinds of iterators?
if ((end < tmp) || (std::distance(begin, tmp) != run_length))
throw std::range_error("The input sequence had too few elements.");
// std::plus is the default accumulate function
*destination = std::accumulate(begin, tmp, 0/*, std::plus<TInputIterator::value_type>()*/);
// should I use std::swap(begin, tmp) here instead?
begin = tmp;
}
Edit 3: In response to the answers, would this be better?
template<class TInputIterator, class TOutputIterator>
TInputIterator process_single(TInputIterator begin, TInputIterator end, TOutputIterator destination)
{
typedef std::iterator_traits<TInputIterator>::value_type value_type;
value_type run_length = *begin;
++begin;
value_type sum = 0;
while (run_length > 0 && begin != end)
{
sum += *begin;
++begin;
--run_length;
}
if (run_length)
{
throw std::range_error("The input sequence had too few elements.");
}
*destination = sum;
return begin;
}
template<class TInputIterator, class TOutputIterator>
void process(TInputIterator begin, TInputIterator end, TOutputIterator destination)
{
while (begin != end)
{
begin = process_single(begin, end, destination);
}
}