Merge pull request #15 from boostorg/next_prior_fix_iterator_backtracking

Reworked next() and prior() taking the distance arguments.
This commit is contained in:
Andrey Semashev 2014-06-25 22:26:44 +04:00
commit 8e24c798ad
2 changed files with 136 additions and 4 deletions

View File

@ -13,6 +13,17 @@
#define BOOST_NEXT_PRIOR_HPP_INCLUDED #define BOOST_NEXT_PRIOR_HPP_INCLUDED
#include <iterator> #include <iterator>
#if defined(_MSC_VER) && _MSC_VER <= 1310
#include <boost/mpl/and.hpp>
#include <boost/type_traits/is_integral.hpp>
#endif
#include <boost/type_traits/is_unsigned.hpp>
#include <boost/type_traits/integral_promotion.hpp>
#include <boost/type_traits/make_signed.hpp>
#include <boost/type_traits/has_plus.hpp>
#include <boost/type_traits/has_plus_assign.hpp>
#include <boost/type_traits/has_minus.hpp>
#include <boost/type_traits/has_minus_assign.hpp>
namespace boost { namespace boost {
@ -26,14 +37,118 @@ namespace boost {
// Contributed by Dave Abrahams // Contributed by Dave Abrahams
namespace next_prior_detail {
template< typename T, typename Distance, bool HasPlus = has_plus< T, Distance >::value >
struct next_impl2
{
static T call(T x, Distance n)
{
std::advance(x, n);
return x;
}
};
template< typename T, typename Distance >
struct next_impl2< T, Distance, true >
{
static T call(T x, Distance n)
{
return x + n;
}
};
template< typename T, typename Distance, bool HasPlusAssign = has_plus_assign< T, Distance >::value >
struct next_impl1 :
public next_impl2< T, Distance >
{
};
template< typename T, typename Distance >
struct next_impl1< T, Distance, true >
{
static T call(T x, Distance n)
{
x += n;
return x;
}
};
template<
typename T,
typename Distance,
typename PromotedDistance = typename integral_promotion< Distance >::type,
#if !defined(_MSC_VER) || _MSC_VER > 1310
bool IsUInt = is_unsigned< PromotedDistance >::value
#else
// MSVC 7.1 has problems with applying is_unsigned to non-integral types
bool IsUInt = mpl::and_< is_integral< PromotedDistance >, is_unsigned< PromotedDistance > >::value
#endif
>
struct prior_impl3
{
static T call(T x, Distance n)
{
std::advance(x, -n);
return x;
}
};
template< typename T, typename Distance, typename PromotedDistance >
struct prior_impl3< T, Distance, PromotedDistance, true >
{
static T call(T x, Distance n)
{
typedef typename make_signed< PromotedDistance >::type signed_distance;
std::advance(x, -static_cast< signed_distance >(static_cast< PromotedDistance >(n)));
return x;
}
};
template< typename T, typename Distance, bool HasMinus = has_minus< T, Distance >::value >
struct prior_impl2 :
public prior_impl3< T, Distance >
{
};
template< typename T, typename Distance >
struct prior_impl2< T, Distance, true >
{
static T call(T x, Distance n)
{
return x - n;
}
};
template< typename T, typename Distance, bool HasMinusAssign = has_minus_assign< T, Distance >::value >
struct prior_impl1 :
public prior_impl2< T, Distance >
{
};
template< typename T, typename Distance >
struct prior_impl1< T, Distance, true >
{
static T call(T x, Distance n)
{
x -= n;
return x;
}
};
} // namespace next_prior_detail
template <class T> template <class T>
inline T next(T x) { return ++x; } inline T next(T x) { return ++x; }
template <class T, class Distance> template <class T, class Distance>
inline T next(T x, Distance n) inline T next(T x, Distance n)
{ {
std::advance(x, n); return next_prior_detail::next_impl1< T, Distance >::call(x, n);
return x;
} }
template <class T> template <class T>
@ -42,8 +157,7 @@ inline T prior(T x) { return --x; }
template <class T, class Distance> template <class T, class Distance>
inline T prior(T x, Distance n) inline T prior(T x, Distance n)
{ {
std::advance(x, -n); return next_prior_detail::prior_impl1< T, Distance >::call(x, n);
return x;
} }
} // namespace boost } // namespace boost

View File

@ -66,14 +66,32 @@ bool minus_n_test(RandomAccessIterator first, RandomAccessIterator last, Bidirec
return std::distance(i, last) == std::distance(j, last2); return std::distance(i, last) == std::distance(j, last2);
} }
template<class Iterator, class Distance>
bool minus_n_unsigned_test(Iterator first, Iterator last, Distance size)
{
Iterator i = boost::prior(last, size);
return i == first;
}
int test_main(int, char*[]) int test_main(int, char*[])
{ {
std::vector<int> x(8); std::vector<int> x(8);
std::list<int> y(x.begin(), x.end()); std::list<int> y(x.begin(), x.end());
// Tests with iterators
BOOST_REQUIRE(plus_one_test(x.begin(), x.end(), y.begin())); BOOST_REQUIRE(plus_one_test(x.begin(), x.end(), y.begin()));
BOOST_REQUIRE(plus_n_test(x.begin(), x.end(), y.begin())); BOOST_REQUIRE(plus_n_test(x.begin(), x.end(), y.begin()));
BOOST_REQUIRE(minus_one_test(x.begin(), x.end(), y.end())); BOOST_REQUIRE(minus_one_test(x.begin(), x.end(), y.end()));
BOOST_REQUIRE(minus_n_test(x.begin(), x.end(), y.end())); BOOST_REQUIRE(minus_n_test(x.begin(), x.end(), y.end()));
BOOST_REQUIRE(minus_n_unsigned_test(x.begin(), x.end(), x.size()));
BOOST_REQUIRE(minus_n_unsigned_test(y.begin(), y.end(), y.size()));
// Tests with integers
BOOST_REQUIRE(boost::next(5) == 6);
BOOST_REQUIRE(boost::next(5, 7) == 12);
BOOST_REQUIRE(boost::prior(5) == 4);
BOOST_REQUIRE(boost::prior(5, 7) == -2);
BOOST_REQUIRE(boost::prior(5, 7u) == -2);
return 0; return 0;
} }