[range] RFC: span(iterator, size)

Hi there, I want to query if there's any interest in such a utility: span(iterator, size) : iterator_range which simply returns iterator_range(it, it + size) for RandomAccessIterator; for others modeling ForwardIterator, a special iterator adaptor, say, counted_iterator is used, so we don't have to advance it just for getting the end iterator. Thoughts?

Hi,
2013/10/30 TONGARI J
Hi there,
I want to query if there's any interest in such a utility:
span(iterator, size) : iterator_range
which simply returns iterator_range(it, it + size) for RandomAccessIterator; for others modeling ForwardIterator, a special iterator adaptor, say, counted_iterator is used, so we don't have to advance it just for getting the end iterator.
Thoughts?
I & Nail will add `taken` range adaptor. http://dl.dropboxusercontent.com/u/1682460/git/OvenToBoost/libs/range/doc/ht... https://github.com/faithandbrave/OvenToBoost/blob/master/boost/range/adaptor... v = {1, 2, 3, 4, 5}; r | taken(3); // {1, 2, 3} Also, I have iterator adaptor version (internal).
======================== Akira Takahashi mailto:faithandbrave@gmail.com site : https://sites.google.com/site/faithandbrave/about/en

Hi Akira,
2013/10/30 Akira Takahashi
Hi,
2013/10/30 TONGARI J
Hi there,
I want to query if there's any interest in such a utility:
span(iterator, size) : iterator_range
which simply returns iterator_range(it, it + size) for RandomAccessIterator; for others modeling ForwardIterator, a special iterator adaptor, say, counted_iterator is used, so we don't have to advance it just for getting the end iterator.
Thoughts?
I & Nail will add `taken` range adaptor.
http://dl.dropboxusercontent.com/u/1682460/git/OvenToBoost/libs/range/doc/ht...
https://github.com/faithandbrave/OvenToBoost/blob/master/boost/range/adaptor...
v = {1, 2, 3, 4, 5}; r | taken(3); // {1, 2, 3}
Also, I have iterator adaptor version (internal).
I don't think this is what I want, but the underlying iterator may be similar to what I called 'counted_iterator', I'm not sure. So, 'span' is a utility function that generates a range from an iterator & size, unlike 'taken' which is an adaptor from another range. If you can provide the 'span' utility as well, that'll be great :) Thanks,

2013/10/30 TONGARI J
Hi Akira,
I don't think this is what I want, but the underlying iterator may be similar to what I called 'counted_iterator', I'm not sure. So, 'span' is a utility function that generates a range from an iterator & size, unlike 'taken' which is an adaptor from another range. If you can provide the 'span' utility as well, that'll be great :)
Thanks,
fmm... What do you think about out of range check? What situation is it useful? Thanks, Akira

2013/10/30 Akira Takahashi
2013/10/30 TONGARI J
Hi Akira,
I don't think this is what I want, but the underlying iterator may be similar to what I called 'counted_iterator', I'm not sure. So, 'span' is a utility function that generates a range from an iterator & size, unlike 'taken' which is an adaptor from another range. If you can provide the 'span' utility as well, that'll be great :)
Thanks,
fmm... What do you think about out of range check?
I'd say, it's the user's duty to ensure it won't go over the end.
What situation is it useful?
When you want to ignore the difference between RandomAccessIterator & ForwardIterator while keeping the efficiency of RandomAccessIterator. Some API may look like this: function(iterator, n, ...) that only require iterator to be ForwardIterator, but the implementation may sacrifice the efficiency of RandomAccessIterator, just because the implementor doesn't want to bother tag-dispatching for such optimization... (OK, I'm the one)

2013/10/30 TONGARI J
2013/10/30 Akira Takahashi
... What do you think about out of range check?
I'd say, it's the user's duty to ensure it won't go over the end.
What situation is it useful?
When you want to ignore the difference between RandomAccessIterator & ForwardIterator while keeping the efficiency of RandomAccessIterator.
Some API may look like this: function(iterator, n, ...) that only require iterator to be ForwardIterator, but the implementation may sacrifice the efficiency of RandomAccessIterator, just because the implementor doesn't want to bother tag-dispatching for such optimization... (OK, I'm the one)
Thank you. I understood your motivation. My opinion is here: First, I wouldn't like to provide iterator interface in Boost.Range functions (expect begin/end). In my opinion, iterator is low layer interface. It is not Boost.Range layer. Second, I rethink interface by first reason: r | random_access_taken(n); or r | random_access_span(n); I don't think useful the function (explicit efficient phrase). At least, we need better name for random access. However, my `taken` implementation hasn't optimization for random access iterator. I'll add optimization to `taken` implementation. Thanks, Akira

2013/10/30 Akira Takahashi
2013/10/30 TONGARI J
...
Second, I rethink interface by first reason: r | random_access_taken(n); or r | random_access_span(n);
I don't think useful the function (explicit efficient phrase). At least, we need better name for random access.
Sorry, I read mistake. you don't want explicit efficient for random access.

29.10.2013 19:54, TONGARI J:
I want to query if there's any interest in such a utility:
span(iterator, size) : iterator_range
That reminds me CountedRanges from STL: http://www.youtube.com/watch?v=dUEA8fHx0r0&t=35m14s
which simply returns iterator_range(it, it + size) for RandomAccessIterator; for others modeling ForwardIterator, a special iterator adaptor, say, counted_iterator is used, so we don't have to advance it just for getting the end iterator.
What type of underlying iterator you plan to use, let say for ForwardIterator? It looks like this type will contain not just iterator, and *efficient* implementation is not clear for me. Just imagine case where next(end(span(first, n))) is legal, like when original range has more than n elements. What end(span(first, n)) would have internally, which state? How it can reach end(span(first, n+n))? Perhaps we need whole new range category in order to make it efficient? Or maybe just implement algorithms for counted ranges, which can take advantage of counted range, like Stepanov shows above? -- Evgeny Panasyuk

Hi Evgeny,
2013/10/30 Evgeny Panasyuk
29.10.2013 19:54, TONGARI J:
I want to query if there's any interest in such a utility:
span(iterator, size) : iterator_range
That reminds me CountedRanges from STL: http://www.youtube.com/watch?** v=dUEA8fHx0r0&t=35m14shttp://www.youtube.com/watch?v=dUEA8fHx0r0&t=35m14s
Thanks for the link,I'll take a look later.
which simply returns iterator_range(it, it + size) for
RandomAccessIterator; for others modeling ForwardIterator, a special iterator adaptor, say, counted_iterator is used, so we don't have to advance it just for getting the end iterator.
What type of underlying iterator you plan to use, let say for ForwardIterator?
So called 'counted_iterator', same category as the wrapped one. It looks like this type will contain not just iterator, and *efficient*
implementation is not clear for me.
The states are: iterator it; std::size_t count; For comparison, only count is compared; dereference is simply *it; increment both it & count; So the code below: for (auto val : span(it, n)) {...} Is equivalent to: for (std::size_t i = 0; i != n, ++i, ++it) {...}
Just imagine case where next(end(span(first, n))) is legal, like when original range has more than n elements. What end(span(first, n)) would have internally, which state?
it = first; count = n; How it can reach end(span(first, n+n))?
Not sure what you mean here.
Perhaps we need whole new range category in order to make it efficient?
I don't think so.
Or maybe just implement algorithms for counted ranges, which can take advantage of counted range, like Stepanov shows above?
Will look later, to see if I missed some points... Thanks,

30.10.2013 5:38, TONGARI J:
That reminds me CountedRanges from STL: http://www.youtube.com/watch?** v=dUEA8fHx0r0&t=35m14shttp://www.youtube.com/watch?v=dUEA8fHx0r0&t=35m14s Thanks for the link,I'll take a look later.
(note, it is link to exact moment which lasts several minutes, not the whole video)
What type of underlying iterator you plan to use, let say for ForwardIterator? So called 'counted_iterator', same category as the wrapped one. It looks like this type will contain not just iterator, and *efficient* implementation is not clear for me. The states are:
iterator it; std::size_t count;
For comparison, only count is compared; dereference is simply *it; increment both it & count;
1. So, span(first, n) and span(next(first), n) will result in "equal" iterators? 2. As I understand, span(first, n) will produce following "iterators": begin {.it = first, .count = 0} end { .it = ???, .count = n } What is end.it? Especially you mentioned that you plan to preserve same range category as original iterator has - what about BidirectionalIterators? -- Evgeny Panasyuk

2013/10/30 Evgeny Panasyuk
1. So, span(first, n) and span(next(first), n) will result in "equal" iterators?
No. Suppose we have a sequence S = {1, 2, 3, 4, 5}, &i is the iterator to i. Given first = &1, n = 4, span(first, n)->[begin {.it = &1, .count = 0}, end { .it = &1, .count = 4 }], which results in {1, 2, 3, 4} span(next(first), n)->[begin {.it = &2, .count = 0}, end { .it = &2, .count = 4 }], which results in {2, 3, 4, 5}
2. As I understand, span(first, n) will produce following "iterators": begin {.it = first, .count = 0} end { .it = ???, .count = n }
What is end.it? end { .it = first, .count = n }
Especially you mentioned that you plan to preserve same range category as original iterator has - what about BidirectionalIterators?
That's my mistake, they should be ForwardIterators.

2013/10/30 TONGARI J
2013/10/30 Evgeny Panasyuk
1. So, span(first, n) and span(next(first), n) will result in "equal" iterators?
No.
if you mean begin-or-end(span(first, n)) == begin-or-end(span(next(first), n)), then yes, but it's pathic.
Suppose we have a sequence S = {1, 2, 3, 4, 5}, &i is the iterator to i. Given first = &1, n = 4, span(first, n)->[begin {.it = &1, .count = 0}, end { .it = &1, .count = 4 }], which results in {1, 2, 3, 4} span(next(first), n)->[begin {.it = &2, .count = 0}, end { .it = &2, .count = 4 }], which results in {2, 3, 4, 5}
2. As I understand, span(first, n) will produce following "iterators": begin {.it = first, .count = 0} end { .it = ???, .count = n }
What is end.it?
end { .it = first, .count = n }
Especially you mentioned that you plan to preserve same range category as original iterator has - what about BidirectionalIterators?
That's my mistake, they should be ForwardIterators.

30.10.2013 11:29, TONGARI J:
1. So, span(first, n) and span(next(first), n) will result in "equal" iterators? if you mean begin-or-end(span(first, n)) == begin-or-end(span(next(first), n)), then yes, but it's pathic.
Yes, that what I mean. This limitation should be placed as warning.
Especially you mentioned that you plan to preserve same range category as original iterator has - what about BidirectionalIterators? That's my mistake, they should be ForwardIterators.
1. What about RandomAccessIterators? 2. Imagine if we have std::list x with 10 elements. Will dereference of end(span(begin(x), 5)) be undefined? -- Evgeny Panasyuk

2013/10/30 Evgeny Panasyuk
30.10.2013 11:29, TONGARI J:
1. So, span(first, n) and span(next(first), n) will result in "equal"
iterators?
if you mean begin-or-end(span(first, n)) == begin-or-end(span(next(first),
n)), then yes, but it's pathic.
Yes, that what I mean. This limitation should be placed as warning.
Especially you mentioned that you plan to preserve same range category as
original iterator has - what about BidirectionalIterators?
That's my mistake, they should be ForwardIterators.
1. What about RandomAccessIterators?
For RandomAccessIterators, 'span' will return the iterator as is, no wrapping.
2. Imagine if we have std::list x with 10 elements. Will dereference of end(span(begin(x), 5)) be undefined?
It's defined to be non-dereferenceable.

30.10.2013 12:18, TONGARI J: >>>> Especially you mentioned that you plan to preserve same range category as >>>> original iterator has - what about BidirectionalIterators? >>> That's my mistake, they should be ForwardIterators. >> 1. What about RandomAccessIterators? > For RandomAccessIterators, 'span' will return the iterator as is, no > wrapping. So, you are talking about following mapping: Original | Wrapped _____________________________ Input | Input Forward | Forward Bidirectional | Forward RandomAccess | RandomAccess + dereference of end of returned will be undefined (even if it was legal in "original" range). + comparison of iterators from different span(..) invocations (with different args) on same range will be also undefined. Ok, I thought maybe you are talking about something more generally applicable. -- Evgeny Panasyuk

2013/10/30 Evgeny Panasyuk
30.10.2013 5:38, TONGARI J:
That reminds me CountedRanges from STL: http://www.youtube.com/watch?****http://www.youtube.com/watch?**
v=dUEA8fHx0r0&t=35m14s<http://**www.youtube.com/watch?v=** dUEA8fHx0r0&t=35m14shttp://www.youtube.com/watch?v=dUEA8fHx0r0&t=35m14s
Thanks for the link,I'll take a look later.
(note, it is link to exact moment which lasts several minutes, not the whole video)
After watching the video, it reminds me that 'span' also makes copy_n, fill_n or something like that redundant.
participants (3)
-
Akira Takahashi
-
Evgeny Panasyuk
-
TONGARI J