Merge branch 'develop'

This commit is contained in:
Andrey Semashev 2017-07-13 20:59:28 +03:00
commit d9d076874e
2 changed files with 75 additions and 55 deletions

View File

@ -1,8 +1,11 @@
// Boost next_prior.hpp header file ---------------------------------------// // Boost next_prior.hpp header file ---------------------------------------//
// (C) Copyright Dave Abrahams and Daniel Walker 1999-2003. Distributed under the Boost // (C) Copyright Dave Abrahams and Daniel Walker 1999-2003.
// Software License, Version 1.0. (See accompanying file // Copyright (c) Andrey Semashev 2017
// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) //
// 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)
// See http://www.boost.org/libs/utility for documentation. // See http://www.boost.org/libs/utility for documentation.
@ -13,13 +16,8 @@
#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/config.hpp>
#include <boost/mpl/and.hpp> #include <boost/core/enable_if.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.hpp>
#include <boost/type_traits/has_plus_assign.hpp> #include <boost/type_traits/has_plus_assign.hpp>
#include <boost/type_traits/has_minus.hpp> #include <boost/type_traits/has_minus.hpp>
@ -39,18 +37,36 @@ namespace boost {
namespace next_prior_detail { namespace next_prior_detail {
template< typename T, typename Distance, bool HasPlus = has_plus< T, Distance >::value > // The trait attempts to detect if the T type is an iterator. Class-type iterators are assumed
struct next_impl2 // to have the nested type iterator_category. Strictly speaking, this is not required to be the
// case (e.g. a user can specialize iterator_traits for T without defining T::iterator_category).
// Still, this is a good heuristic in practice, and we can't do anything better anyway.
// Since C++17 we can test for iterator_traits<T>::iterator_category presence instead as it is
// required to be only present for iterators.
template< typename T, typename Void = void >
struct is_iterator
{ {
static T call(T x, Distance n) static BOOST_CONSTEXPR_OR_CONST bool value = false;
{
std::advance(x, n);
return x;
}
}; };
template< typename T >
struct is_iterator< T, typename enable_if_has_type< typename T::iterator_category >::type >
{
static BOOST_CONSTEXPR_OR_CONST bool value = true;
};
template< typename T >
struct is_iterator< T*, void >
{
static BOOST_CONSTEXPR_OR_CONST bool value = true;
};
template< typename T, typename Distance, bool HasPlus = has_plus< T, Distance >::value >
struct next_plus_impl;
template< typename T, typename Distance > template< typename T, typename Distance >
struct next_impl2< T, Distance, true > struct next_plus_impl< T, Distance, true >
{ {
static T call(T x, Distance n) static T call(T x, Distance n)
{ {
@ -58,15 +74,14 @@ struct next_impl2< T, Distance, true >
} }
}; };
template< typename T, typename Distance, bool HasPlusAssign = has_plus_assign< T, Distance >::value > template< typename T, typename Distance, bool HasPlusAssign = has_plus_assign< T, Distance >::value >
struct next_impl1 : struct next_plus_assign_impl :
public next_impl2< T, Distance > public next_plus_impl< T, Distance >
{ {
}; };
template< typename T, typename Distance > template< typename T, typename Distance >
struct next_impl1< T, Distance, true > struct next_plus_assign_impl< T, Distance, true >
{ {
static T call(T x, Distance n) static T call(T x, Distance n)
{ {
@ -75,47 +90,28 @@ struct next_impl1< T, Distance, true >
} }
}; };
template< typename T, typename Distance, bool IsIterator = is_iterator< T >::value >
template< struct next_advance_impl :
typename T, public next_plus_assign_impl< T, Distance >
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 > template< typename T, typename Distance >
struct prior_impl3< T, Distance, PromotedDistance, true > struct next_advance_impl< T, Distance, true >
{ {
static T call(T x, Distance n) static T call(T x, Distance n)
{ {
typedef typename make_signed< PromotedDistance >::type signed_distance; std::advance(x, n);
std::advance(x, -static_cast< signed_distance >(static_cast< PromotedDistance >(n)));
return x; return x;
} }
}; };
template< typename T, typename Distance, bool HasMinus = has_minus< T, Distance >::value > template< typename T, typename Distance, bool HasMinus = has_minus< T, Distance >::value >
struct prior_impl2 : struct prior_minus_impl;
public prior_impl3< T, Distance >
{
};
template< typename T, typename Distance > template< typename T, typename Distance >
struct prior_impl2< T, Distance, true > struct prior_minus_impl< T, Distance, true >
{ {
static T call(T x, Distance n) static T call(T x, Distance n)
{ {
@ -123,15 +119,14 @@ struct prior_impl2< T, Distance, true >
} }
}; };
template< typename T, typename Distance, bool HasMinusAssign = has_minus_assign< T, Distance >::value > template< typename T, typename Distance, bool HasMinusAssign = has_minus_assign< T, Distance >::value >
struct prior_impl1 : struct prior_minus_assign_impl :
public prior_impl2< T, Distance > public prior_minus_impl< T, Distance >
{ {
}; };
template< typename T, typename Distance > template< typename T, typename Distance >
struct prior_impl1< T, Distance, true > struct prior_minus_assign_impl< T, Distance, true >
{ {
static T call(T x, Distance n) static T call(T x, Distance n)
{ {
@ -140,6 +135,24 @@ struct prior_impl1< T, Distance, true >
} }
}; };
template< typename T, typename Distance, bool IsIterator = is_iterator< T >::value >
struct prior_advance_impl :
public prior_minus_assign_impl< T, Distance >
{
};
template< typename T, typename Distance >
struct prior_advance_impl< T, Distance, true >
{
static T call(T x, Distance n)
{
// Avoid negating n to sidestep possible integer overflow
std::reverse_iterator< T > rx(x);
std::advance(rx, n);
return rx.base();
}
};
} // namespace next_prior_detail } // namespace next_prior_detail
template <class T> template <class T>
@ -148,7 +161,7 @@ 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)
{ {
return next_prior_detail::next_impl1< T, Distance >::call(x, n); return next_prior_detail::next_advance_impl< T, Distance >::call(x, n);
} }
template <class T> template <class T>
@ -157,7 +170,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)
{ {
return next_prior_detail::prior_impl1< T, Distance >::call(x, n); return next_prior_detail::prior_advance_impl< T, Distance >::call(x, n);
} }
} // namespace boost } // namespace boost

View File

@ -86,6 +86,13 @@ int test_main(int, char*[])
BOOST_REQUIRE(minus_n_unsigned_test(x.begin(), x.end(), x.size())); BOOST_REQUIRE(minus_n_unsigned_test(x.begin(), x.end(), x.size()));
BOOST_REQUIRE(minus_n_unsigned_test(y.begin(), y.end(), y.size())); BOOST_REQUIRE(minus_n_unsigned_test(y.begin(), y.end(), y.size()));
BOOST_REQUIRE(plus_one_test(x.rbegin(), x.rend(), y.begin()));
BOOST_REQUIRE(plus_n_test(x.rbegin(), x.rend(), y.begin()));
BOOST_REQUIRE(minus_one_test(x.rbegin(), x.rend(), y.end()));
BOOST_REQUIRE(minus_n_test(x.rbegin(), x.rend(), y.end()));
BOOST_REQUIRE(minus_n_unsigned_test(x.rbegin(), x.rend(), x.size()));
BOOST_REQUIRE(minus_n_unsigned_test(x.rbegin(), x.rend(), y.size()));
// Tests with integers // Tests with integers
BOOST_REQUIRE(boost::next(5) == 6); BOOST_REQUIRE(boost::next(5) == 6);
BOOST_REQUIRE(boost::next(5, 7) == 12); BOOST_REQUIRE(boost::next(5, 7) == 12);