diff --git a/include/boost/next_prior.hpp b/include/boost/next_prior.hpp index e1d2e42..7854ec4 100644 --- a/include/boost/next_prior.hpp +++ b/include/boost/next_prior.hpp @@ -13,6 +13,17 @@ #define BOOST_NEXT_PRIOR_HPP_INCLUDED #include +#if defined(_MSC_VER) && _MSC_VER <= 1310 +#include +#include +#endif +#include +#include +#include +#include +#include +#include +#include namespace boost { @@ -26,14 +37,118 @@ namespace boost { // 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 inline T next(T x) { return ++x; } template inline T next(T x, Distance n) { - std::advance(x, n); - return x; + return next_prior_detail::next_impl1< T, Distance >::call(x, n); } template @@ -42,8 +157,7 @@ inline T prior(T x) { return --x; } template inline T prior(T x, Distance n) { - std::advance(x, -n); - return x; + return next_prior_detail::prior_impl1< T, Distance >::call(x, n); } } // namespace boost diff --git a/test/next_prior_test.cpp b/test/next_prior_test.cpp index ebce472..4f9b01a 100644 --- a/test/next_prior_test.cpp +++ b/test/next_prior_test.cpp @@ -66,14 +66,32 @@ bool minus_n_test(RandomAccessIterator first, RandomAccessIterator last, Bidirec return std::distance(i, last) == std::distance(j, last2); } +template +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*[]) { std::vector x(8); std::list y(x.begin(), x.end()); + // Tests with iterators BOOST_REQUIRE(plus_one_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_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; }