diff --git a/include/boost/iterator/advance.hpp b/include/boost/iterator/advance.hpp new file mode 100644 index 0000000..2698f2b --- /dev/null +++ b/include/boost/iterator/advance.hpp @@ -0,0 +1,85 @@ +// Copyright (C) 2017 Michel Morin. +// +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#ifndef BOOST_ITERATOR_ADVANCE_HPP +#define BOOST_ITERATOR_ADVANCE_HPP + +#include +#include +#include + +namespace boost { +namespace iterators { + + namespace detail { + template + inline BOOST_CXX14_CONSTEXPR void + advance_impl( + InputIterator& it + , typename iterator_difference::type n + , incrementable_traversal_tag + ) + { + while (n > 0) { + ++it; + --n; + } + } + + template + inline BOOST_CXX14_CONSTEXPR void + advance_impl( + BidirectionalIterator& it + , typename iterator_difference::type n + , bidirectional_traversal_tag + ) + { + if (n >= 0) { + while (n > 0) { + ++it; + --n; + } + } + else { + while (n < 0) { + --it; + ++n; + } + } + } + + template + inline BOOST_CXX14_CONSTEXPR void + advance_impl( + RandomAccessIterator& it + , typename iterator_difference::type n + , random_access_traversal_tag + ) + { + it += n; + } + } + + namespace advance_adl_barrier { + template + inline BOOST_CXX14_CONSTEXPR void + advance(InputIterator& it, typename iterator_difference::type n) + { + detail::advance_impl( + it, n, typename iterator_traversal::type() + ); + } + } + + using namespace advance_adl_barrier; + +} // namespace iterators + +using iterators::advance; + +} // namespace boost + +#endif diff --git a/include/boost/iterator/distance.hpp b/include/boost/iterator/distance.hpp new file mode 100644 index 0000000..8cf3f15 --- /dev/null +++ b/include/boost/iterator/distance.hpp @@ -0,0 +1,65 @@ +// Copyright (C) 2017 Michel Morin. +// +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#ifndef BOOST_ITERATOR_DISTANCE_HPP +#define BOOST_ITERATOR_DISTANCE_HPP + +#include +#include +#include + +namespace boost { +namespace iterators { + + namespace detail { + template + inline BOOST_CXX14_CONSTEXPR typename iterator_difference::type + distance_impl( + SinglePassIterator first + , SinglePassIterator last + , single_pass_traversal_tag + ) + { + typename iterator_difference::type n = 0; + while (first != last) { + ++first; + ++n; + } + return n; + } + + template + inline BOOST_CXX14_CONSTEXPR typename iterator_difference::type + distance_impl( + RandomAccessIterator first + , RandomAccessIterator last + , random_access_traversal_tag + ) + { + return last - first; + } + } + + namespace distance_adl_barrier { + template + inline BOOST_CXX14_CONSTEXPR typename iterator_difference::type + distance(SinglePassIterator first, SinglePassIterator last) + { + return detail::distance_impl( + first, last, typename iterator_traversal::type() + ); + } + } + + using namespace distance_adl_barrier; + +} // namespace iterators + +using iterators::distance; + +} // namespace boost + +#endif diff --git a/test/Jamfile.v2 b/test/Jamfile.v2 index 81547dc..927a98a 100644 --- a/test/Jamfile.v2 +++ b/test/Jamfile.v2 @@ -55,4 +55,7 @@ test-suite iterator [ run minimum_category.cpp ] [ compile-fail minimum_category_compile_fail.cpp ] + + [ run advance_test.cpp ] + [ run distance_test.cpp ] ; diff --git a/test/advance_test.cpp b/test/advance_test.cpp new file mode 100644 index 0000000..230d07e --- /dev/null +++ b/test/advance_test.cpp @@ -0,0 +1,65 @@ +// Copyright (C) 2017 Michel Morin. +// +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#include +#include +#include +#include +#include +#include + +int twice(int x) { return x + x; } + +template +void test_advance(Iterator it_from, Iterator it_to, int n) +{ + boost::advance(it_from, n); + BOOST_TEST(it_from == it_to); +} + +int main() +{ + int array[3] = {1, 2, 3}; + int* ptr1 = array; + int* ptr2 = array + 3; + + { + test_advance(ptr1, ptr2, 3); + test_advance(ptr2, ptr1, -3); + } + + { + std::vector ints(ptr1, ptr2); + test_advance(ints.begin(), ints.end(), 3); + test_advance(ints.end(), ints.begin(), -3); + } + + { + test_advance( + boost::make_transform_iterator(ptr1, twice) + , boost::make_transform_iterator(ptr2, twice) + , 3 + ); + test_advance( + boost::make_transform_iterator(ptr2, twice) + , boost::make_transform_iterator(ptr1, twice) + , -3 + ); + } + + { + std::list ints(ptr1, ptr2); + test_advance(ints.begin(), ints.end(), 3); + test_advance(ints.end(), ints.begin(), -3); + } + + { + boost::container::slist ints(ptr1, ptr2); + test_advance(ints.begin(), ints.end(), 3); + } + + return boost::report_errors(); +} diff --git a/test/distance_test.cpp b/test/distance_test.cpp new file mode 100644 index 0000000..494b0d5 --- /dev/null +++ b/test/distance_test.cpp @@ -0,0 +1,63 @@ +// Copyright (C) 2017 Michel Morin. +// +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#include +#include +#include +#include +#include +#include + +int twice(int x) { return x + x; } + +template +void test_distance(Iterator it_from, Iterator it_to, int n) +{ + BOOST_TEST(boost::distance(it_from, it_to) == n); +} + +int main() +{ + int array[3] = {1, 2, 3}; + int* ptr1 = array; + int* ptr2 = array + 3; + + { + test_distance(ptr1, ptr2, 3); + test_distance(ptr2, ptr1, -3); + } + + { + std::vector ints(ptr1, ptr2); + test_distance(ints.begin(), ints.end(), 3); + test_distance(ints.end(), ints.begin(), -3); + } + + { + test_distance( + boost::make_transform_iterator(ptr1, twice) + , boost::make_transform_iterator(ptr2, twice) + , 3 + ); + test_distance( + boost::make_transform_iterator(ptr2, twice) + , boost::make_transform_iterator(ptr1, twice) + , -3 + ); + } + + { + std::list ints(ptr1, ptr2); + test_distance(ints.begin(), ints.end(), 3); + } + + { + boost::container::slist ints(ptr1, ptr2); + test_distance(ints.begin(), ints.end(), 3); + } + + return boost::report_errors(); +}