Skip to content

Instantly share code, notes, and snippets.

@oliora
Last active September 26, 2019 02:38
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save oliora/58d2acd4e025dc90bcaf3885ae54aa19 to your computer and use it in GitHub Desktop.
Save oliora/58d2acd4e025dc90bcaf3885ae54aa19 to your computer and use it in GitHub Desktop.
Implementation of safe std::advance, std::next and std::prev similar to proposed N4317 paper "New Safer Functions to Advance Iterators"
// N4317 "New Safer Functions to Advance Iterators" paper can be found at
// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2014/n4317.pdf
namespace detail {
template<class InputIter>
inline void do_advance(InputIter& it, InputIter end, typename std::iterator_traits<InputIter>::difference_type n, std::input_iterator_tag)
{
assert(n >= 0);
for (; (n > 0) && (it != end); --n)
++it;
}
template<class BiDirIter>
inline void do_advance(BiDirIter& it, BiDirIter end, typename std::iterator_traits<BiDirIter>::difference_type n, std::bidirectional_iterator_tag)
{
if (n >= 0) {
for (; (n > 0) && (it != end); --n)
++it;
} else {
for (; (n < 0) && (it != end); ++n)
--it;
}
}
template<class RandIter>
inline void do_advance(RandIter& it, RandIter end, typename std::iterator_traits<RandIter>::difference_type n, std::random_access_iterator_tag)
{
it += std::min(n, end - it);
}
}
template<class InputIter>
inline void advance(InputIter& it, InputIter end, typename std::iterator_traits<InputIter>::difference_type n)
{
detail::do_advance(it, end, n, typename std::iterator_traits<InputIter>::iterator_category{});
}
template<class InputIter>
inline InputIter next(InputIter it, InputIter end, typename std::iterator_traits<InputIter>::difference_type n = 1)
{
advance(it, end, n);
return it;
}
template<class BidirectionalIter>
inline BidirectionalIter prev(BidirectionalIter it, BidirectionalIter end, typename std::iterator_traits<BidirectionalIter>::difference_type n = 1)
{
static_assert(std::is_base_of<std::bidirectional_iterator_tag, typename std::iterator_traits<BidirectionalIter>::iterator_category>::value,
"Bidirectional iterator required");
advance(it, end, -n);
return it;
}
@oliora
Copy link
Author

oliora commented Sep 25, 2019

With safe advance you can do some nice stuff in much fewer lines:

template<class ForwardIter, class RangeOperation>
inline void paginate(ForwardIter first, ForwardIter last, size_t page_size, RangeOperation op)
{
    static_assert(std::is_base_of<std::forward_iterator_tag, typename std::iterator_traits<ForwardIter>::iterator_category>::value,
                  "Forward iterator required");

    assert(page_size);

    while (first != last)
    {
        auto page_end = next(first, last, page_size);
        op(first, page_end);
        first = page_end;
    }
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment