forked from boostorg/detail
Actualized numeric_traits implementation.
1. Ported to Boost.TypeTraits primitives for type inspection and simple metaprogramming instead of local implementations. This effectively drops any workarounds for compilers without support for partial template specializations. Such compilers are long outdated. 2. Include more fine-grained headers from Boost.TypeTraits to optimize compilation times. 3. Made numeric_distance function constexpr. 4. Updated the test accordingly (i.e. replaced the use of now removed local components with Boost.TypeTraits). Also replaced lexical_cast with standard streams to further reduce dependencies. None of these changes should affect functionality.
This commit is contained in:
@ -56,65 +56,39 @@
|
|||||||
// 21 Jan 2001 - Created (David Abrahams)
|
// 21 Jan 2001 - Created (David Abrahams)
|
||||||
|
|
||||||
#ifndef BOOST_NUMERIC_TRAITS_HPP_DWA20001901
|
#ifndef BOOST_NUMERIC_TRAITS_HPP_DWA20001901
|
||||||
# define BOOST_NUMERIC_TRAITS_HPP_DWA20001901
|
#define BOOST_NUMERIC_TRAITS_HPP_DWA20001901
|
||||||
|
|
||||||
# include <boost/config.hpp>
|
#include <cstddef>
|
||||||
# include <boost/cstdint.hpp>
|
#include <boost/config.hpp>
|
||||||
# include <boost/static_assert.hpp>
|
#include <boost/limits.hpp>
|
||||||
# include <boost/type_traits.hpp>
|
#include <boost/cstdint.hpp>
|
||||||
# include <boost/detail/select_type.hpp>
|
#include <boost/type_traits/is_signed.hpp>
|
||||||
# include <boost/limits.hpp>
|
#include <boost/type_traits/conditional.hpp>
|
||||||
|
#ifdef BOOST_NO_LIMITS_COMPILE_TIME_CONSTANTS
|
||||||
|
#include <boost/static_assert.hpp>
|
||||||
|
#include <boost/type_traits/is_integral.hpp>
|
||||||
|
#endif
|
||||||
|
|
||||||
namespace boost { namespace detail {
|
namespace boost { namespace detail {
|
||||||
|
|
||||||
// Template class is_signed -- determine whether a numeric type is signed
|
#ifndef BOOST_NO_LIMITS_COMPILE_TIME_CONSTANTS
|
||||||
// Requires that T is constructable from the literals -1 and 0. Compile-time
|
|
||||||
// error results if that requirement is not met (and thus signedness is not
|
|
||||||
// likely to have meaning for that type).
|
|
||||||
template <class Number>
|
|
||||||
struct is_signed
|
|
||||||
{
|
|
||||||
#if defined(BOOST_NO_LIMITS_COMPILE_TIME_CONSTANTS)
|
|
||||||
BOOST_STATIC_CONSTANT(bool, value = (Number(-1) < Number(0)));
|
|
||||||
#else
|
|
||||||
BOOST_STATIC_CONSTANT(bool, value = std::numeric_limits<Number>::is_signed);
|
|
||||||
#endif
|
|
||||||
};
|
|
||||||
|
|
||||||
# ifndef BOOST_NO_LIMITS_COMPILE_TIME_CONSTANTS
|
|
||||||
// digit_traits - compute the number of digits in a built-in integer
|
// digit_traits - compute the number of digits in a built-in integer
|
||||||
// type. Needed for implementations on which numeric_limits is not specialized
|
// type. Needed for implementations on which numeric_limits is not specialized
|
||||||
// for intmax_t (e.g. VC6).
|
// for some integer types, like __int128 in libstdc++ (gcc).
|
||||||
template <bool is_specialized> struct digit_traits_select;
|
template <class T, bool IsSpecialized = std::numeric_limits<T>::is_specialized>
|
||||||
|
struct digit_traits
|
||||||
// numeric_limits is specialized; just select that version of digits
|
|
||||||
template <> struct digit_traits_select<true>
|
|
||||||
{
|
{
|
||||||
template <class T> struct traits
|
BOOST_STATIC_CONSTANT(int, digits = std::numeric_limits<T>::digits);
|
||||||
{
|
|
||||||
BOOST_STATIC_CONSTANT(int, digits = std::numeric_limits<T>::digits);
|
|
||||||
};
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// numeric_limits is not specialized; compute digits from sizeof(T)
|
// numeric_limits is not specialized; compute digits from sizeof(T)
|
||||||
template <> struct digit_traits_select<false>
|
template <class T>
|
||||||
|
struct digit_traits<T, false>
|
||||||
{
|
{
|
||||||
template <class T> struct traits
|
BOOST_STATIC_CONSTANT(int, digits = (
|
||||||
{
|
sizeof(T) * std::numeric_limits<unsigned char>::digits
|
||||||
BOOST_STATIC_CONSTANT(int, digits = (
|
- (boost::is_signed<T>::value ? 1 : 0))
|
||||||
sizeof(T) * std::numeric_limits<unsigned char>::digits
|
);
|
||||||
- (is_signed<T>::value ? 1 : 0))
|
|
||||||
);
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
// here's the "usable" template
|
|
||||||
template <class T> struct digit_traits
|
|
||||||
{
|
|
||||||
typedef digit_traits_select<
|
|
||||||
::std::numeric_limits<T>::is_specialized> selector;
|
|
||||||
typedef typename selector::template traits<T> traits;
|
|
||||||
BOOST_STATIC_CONSTANT(int, digits = traits::digits);
|
|
||||||
};
|
};
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@ -124,44 +98,48 @@ namespace boost { namespace detail {
|
|||||||
template <class Integer>
|
template <class Integer>
|
||||||
struct integer_traits
|
struct integer_traits
|
||||||
{
|
{
|
||||||
# ifndef BOOST_NO_LIMITS_COMPILE_TIME_CONSTANTS
|
#ifndef BOOST_NO_LIMITS_COMPILE_TIME_CONSTANTS
|
||||||
private:
|
private:
|
||||||
typedef Integer integer_type;
|
typedef Integer integer_type;
|
||||||
typedef std::numeric_limits<integer_type> x;
|
typedef std::numeric_limits<integer_type> x;
|
||||||
public:
|
public:
|
||||||
typedef typename
|
typedef typename boost::conditional<
|
||||||
if_true<(int(x::is_signed)
|
(int(x::is_signed)
|
||||||
&& (!int(x::is_bounded)
|
&& (!int(x::is_bounded)
|
||||||
// digits is the number of no-sign bits
|
// digits is the number of no-sign bits
|
||||||
|| (int(x::digits) + 1 >= digit_traits<boost::intmax_t>::digits)))>::template then<
|
|| (int(x::digits) + 1 >= digit_traits<boost::intmax_t>::digits))),
|
||||||
Integer,
|
Integer,
|
||||||
|
|
||||||
typename if_true<(int(x::digits) + 1 < digit_traits<signed int>::digits)>::template then<
|
|
||||||
signed int,
|
|
||||||
|
|
||||||
typename if_true<(int(x::digits) + 1 < digit_traits<signed long>::digits)>::template then<
|
typename boost::conditional<
|
||||||
signed long,
|
(int(x::digits) + 1 < digit_traits<signed int>::digits),
|
||||||
|
signed int,
|
||||||
|
|
||||||
// else
|
typename boost::conditional<
|
||||||
intmax_t
|
(int(x::digits) + 1 < digit_traits<signed long>::digits),
|
||||||
>::type>::type>::type difference_type;
|
signed long,
|
||||||
|
boost::intmax_t
|
||||||
|
>::type
|
||||||
|
>::type
|
||||||
|
>::type difference_type;
|
||||||
#else
|
#else
|
||||||
BOOST_STATIC_ASSERT(boost::is_integral<Integer>::value);
|
BOOST_STATIC_ASSERT(boost::is_integral<Integer>::value);
|
||||||
|
|
||||||
typedef typename
|
typedef typename boost::conditional<
|
||||||
if_true<(sizeof(Integer) >= sizeof(intmax_t))>::template then<
|
(sizeof(Integer) >= sizeof(intmax_t)),
|
||||||
|
|
||||||
typename if_true<(is_signed<Integer>::value)>::template then<
|
|
||||||
Integer,
|
|
||||||
intmax_t
|
|
||||||
>::type,
|
|
||||||
|
|
||||||
typename if_true<(sizeof(Integer) < sizeof(std::ptrdiff_t))>::template then<
|
boost::conditional<
|
||||||
|
(boost::is_signed<Integer>::value),
|
||||||
|
Integer,
|
||||||
|
boost::intmax_t
|
||||||
|
>,
|
||||||
|
|
||||||
|
boost::conditional<
|
||||||
|
(sizeof(Integer) < sizeof(std::ptrdiff_t)),
|
||||||
std::ptrdiff_t,
|
std::ptrdiff_t,
|
||||||
intmax_t
|
boost::intmax_t
|
||||||
>::type
|
>
|
||||||
>::type difference_type;
|
>::type::type difference_type;
|
||||||
# endif
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
// Right now, only supports integers, but should be expanded.
|
// Right now, only supports integers, but should be expanded.
|
||||||
@ -172,7 +150,7 @@ namespace boost { namespace detail {
|
|||||||
};
|
};
|
||||||
|
|
||||||
template <class Number>
|
template <class Number>
|
||||||
typename numeric_traits<Number>::difference_type numeric_distance(Number x, Number y)
|
inline BOOST_CONSTEXPR typename numeric_traits<Number>::difference_type numeric_distance(Number x, Number y)
|
||||||
{
|
{
|
||||||
typedef typename numeric_traits<Number>::difference_type difference_type;
|
typedef typename numeric_traits<Number>::difference_type difference_type;
|
||||||
return difference_type(y) - difference_type(x);
|
return difference_type(y) - difference_type(x);
|
||||||
|
@ -17,17 +17,18 @@
|
|||||||
|
|
||||||
#include <boost/detail/numeric_traits.hpp>
|
#include <boost/detail/numeric_traits.hpp>
|
||||||
#include <cassert>
|
#include <cassert>
|
||||||
#include <boost/type_traits.hpp>
|
#include <boost/type_traits/conditional.hpp>
|
||||||
|
#include <boost/type_traits/is_signed.hpp>
|
||||||
|
#include <boost/type_traits/is_same.hpp>
|
||||||
#include <boost/static_assert.hpp>
|
#include <boost/static_assert.hpp>
|
||||||
#include <boost/cstdint.hpp>
|
#include <boost/cstdint.hpp>
|
||||||
#include <boost/utility.hpp>
|
|
||||||
#include <boost/lexical_cast.hpp>
|
|
||||||
#include <climits>
|
#include <climits>
|
||||||
#include <typeinfo>
|
#include <typeinfo>
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
|
#include <sstream>
|
||||||
#include <string>
|
#include <string>
|
||||||
#ifndef BOOST_NO_LIMITS
|
#ifndef BOOST_NO_LIMITS
|
||||||
# include <limits>
|
#include <limits>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// =================================================================================
|
// =================================================================================
|
||||||
@ -42,7 +43,7 @@ template <unsigned size> struct complement; // forward
|
|||||||
|
|
||||||
// The template complement, below, does all the real work, using "poor man's
|
// The template complement, below, does all the real work, using "poor man's
|
||||||
// partial specialization". We need complement_traits_aux<> so that MSVC doesn't
|
// partial specialization". We need complement_traits_aux<> so that MSVC doesn't
|
||||||
// complain about undefined min/max as we're trying to recursively define them.
|
// complain about undefined min/max as we're trying to recursively define them.
|
||||||
template <class Number, unsigned size>
|
template <class Number, unsigned size>
|
||||||
struct complement_traits_aux
|
struct complement_traits_aux
|
||||||
{
|
{
|
||||||
@ -109,7 +110,7 @@ struct complement<1>
|
|||||||
template <class Number>
|
template <class Number>
|
||||||
struct traits
|
struct traits
|
||||||
{
|
{
|
||||||
BOOST_STATIC_CONSTANT(bool, is_signed = boost::detail::is_signed<Number>::value);
|
BOOST_STATIC_CONSTANT(bool, is_signed = boost::is_signed<Number>::value);
|
||||||
BOOST_STATIC_CONSTANT(Number, min =
|
BOOST_STATIC_CONSTANT(Number, min =
|
||||||
complement_base<is_signed>::template values<Number>::min);
|
complement_base<is_signed>::template values<Number>::min);
|
||||||
BOOST_STATIC_CONSTANT(Number, max =
|
BOOST_STATIC_CONSTANT(Number, max =
|
||||||
@ -184,21 +185,30 @@ template <> struct promote<boost::uintmax_t> {
|
|||||||
std::string static from(const boost::uintmax_t x) {
|
std::string static from(const boost::uintmax_t x) {
|
||||||
if (x > ULONG_MAX)
|
if (x > ULONG_MAX)
|
||||||
return std::string("large unsigned value");
|
return std::string("large unsigned value");
|
||||||
else
|
else {
|
||||||
return boost::lexical_cast<std::string>((unsigned long)x);
|
std::ostringstream strm;
|
||||||
|
strm << (unsigned long)x;
|
||||||
|
return strm.str();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
template <> struct promote<boost::intmax_t> {
|
template <> struct promote<boost::intmax_t> {
|
||||||
std::string static from(const boost::intmax_t x) {
|
std::string static from(const boost::intmax_t x) {
|
||||||
if (x > boost::intmax_t(ULONG_MAX))
|
if (x > boost::intmax_t(ULONG_MAX))
|
||||||
return std::string("large positive signed value");
|
return std::string("large positive signed value");
|
||||||
else if (x >= 0)
|
else if (x >= 0) {
|
||||||
return boost::lexical_cast<std::string>((unsigned long)x);
|
std::ostringstream strm;
|
||||||
|
strm << (unsigned long)x;
|
||||||
|
return strm.str();
|
||||||
|
}
|
||||||
|
|
||||||
if (x < boost::intmax_t(LONG_MIN))
|
if (x < boost::intmax_t(LONG_MIN))
|
||||||
return std::string("large negative signed value");
|
return std::string("large negative signed value");
|
||||||
else
|
else {
|
||||||
return boost::lexical_cast<std::string>((long)x);
|
std::ostringstream strm;
|
||||||
|
strm << (long)x;
|
||||||
|
return strm.str();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
#endif
|
#endif
|
||||||
@ -225,7 +235,7 @@ template <class Number>
|
|||||||
void test_aux(unsigned_tag, Number*)
|
void test_aux(unsigned_tag, Number*)
|
||||||
{
|
{
|
||||||
typedef typename boost::detail::numeric_traits<Number>::difference_type difference_type;
|
typedef typename boost::detail::numeric_traits<Number>::difference_type difference_type;
|
||||||
BOOST_STATIC_ASSERT(!boost::detail::is_signed<Number>::value);
|
BOOST_STATIC_ASSERT(!boost::is_signed<Number>::value);
|
||||||
BOOST_STATIC_ASSERT(
|
BOOST_STATIC_ASSERT(
|
||||||
(sizeof(Number) < sizeof(boost::intmax_t))
|
(sizeof(Number) < sizeof(boost::intmax_t))
|
||||||
| (boost::is_same<difference_type, boost::intmax_t>::value));
|
| (boost::is_same<difference_type, boost::intmax_t>::value));
|
||||||
@ -242,7 +252,7 @@ void test_aux(unsigned_tag, Number*)
|
|||||||
|
|
||||||
const Number max = complement_traits<Number>::max;
|
const Number max = complement_traits<Number>::max;
|
||||||
const Number min = complement_traits<Number>::min;
|
const Number min = complement_traits<Number>::min;
|
||||||
|
|
||||||
const Number test_max = (sizeof(Number) < sizeof(boost::intmax_t))
|
const Number test_max = (sizeof(Number) < sizeof(boost::intmax_t))
|
||||||
? max
|
? max
|
||||||
: max / 2 - 1;
|
: max / 2 - 1;
|
||||||
@ -251,10 +261,10 @@ void test_aux(unsigned_tag, Number*)
|
|||||||
<< stream_number(max) << "..." << std::flush;
|
<< stream_number(max) << "..." << std::flush;
|
||||||
std::cout << "difference_type = " << typeid(difference_type).name() << "..."
|
std::cout << "difference_type = " << typeid(difference_type).name() << "..."
|
||||||
<< std::flush;
|
<< std::flush;
|
||||||
|
|
||||||
difference_type d1 = boost::detail::numeric_distance(Number(0), test_max);
|
difference_type d1 = boost::detail::numeric_distance(Number(0), test_max);
|
||||||
difference_type d2 = boost::detail::numeric_distance(test_max, Number(0));
|
difference_type d2 = boost::detail::numeric_distance(test_max, Number(0));
|
||||||
|
|
||||||
std::cout << "0->" << stream_number(test_max) << "==" << std::dec << stream_number(d1) << "; "
|
std::cout << "0->" << stream_number(test_max) << "==" << std::dec << stream_number(d1) << "; "
|
||||||
<< std::hex << stream_number(test_max) << "->0==" << std::dec << stream_number(d2) << "..." << std::flush;
|
<< std::hex << stream_number(test_max) << "->0==" << std::dec << stream_number(d2) << "..." << std::flush;
|
||||||
|
|
||||||
@ -272,11 +282,11 @@ struct in_range_tag {};
|
|||||||
template <class Number>
|
template <class Number>
|
||||||
void signed_test(in_range_tag, Number*)
|
void signed_test(in_range_tag, Number*)
|
||||||
{
|
{
|
||||||
BOOST_STATIC_ASSERT(boost::detail::is_signed<Number>::value);
|
BOOST_STATIC_ASSERT(boost::is_signed<Number>::value);
|
||||||
typedef typename boost::detail::numeric_traits<Number>::difference_type difference_type;
|
typedef typename boost::detail::numeric_traits<Number>::difference_type difference_type;
|
||||||
const Number max = complement_traits<Number>::max;
|
const Number max = complement_traits<Number>::max;
|
||||||
const Number min = complement_traits<Number>::min;
|
const Number min = complement_traits<Number>::min;
|
||||||
|
|
||||||
difference_type d1 = boost::detail::numeric_distance(min, max);
|
difference_type d1 = boost::detail::numeric_distance(min, max);
|
||||||
difference_type d2 = boost::detail::numeric_distance(max, min);
|
difference_type d2 = boost::detail::numeric_distance(max, min);
|
||||||
|
|
||||||
@ -293,7 +303,7 @@ void signed_test(in_range_tag, Number*)
|
|||||||
template <class Number>
|
template <class Number>
|
||||||
void signed_test(out_of_range_tag, Number*)
|
void signed_test(out_of_range_tag, Number*)
|
||||||
{
|
{
|
||||||
BOOST_STATIC_ASSERT(boost::detail::is_signed<Number>::value);
|
BOOST_STATIC_ASSERT(boost::is_signed<Number>::value);
|
||||||
typedef typename boost::detail::numeric_traits<Number>::difference_type difference_type;
|
typedef typename boost::detail::numeric_traits<Number>::difference_type difference_type;
|
||||||
const Number max = complement_traits<Number>::max;
|
const Number max = complement_traits<Number>::max;
|
||||||
const Number min = complement_traits<Number>::min;
|
const Number min = complement_traits<Number>::min;
|
||||||
@ -318,7 +328,7 @@ template <class Number>
|
|||||||
void test_aux(signed_tag, Number*)
|
void test_aux(signed_tag, Number*)
|
||||||
{
|
{
|
||||||
typedef typename boost::detail::numeric_traits<Number>::difference_type difference_type;
|
typedef typename boost::detail::numeric_traits<Number>::difference_type difference_type;
|
||||||
BOOST_STATIC_ASSERT(boost::detail::is_signed<Number>::value);
|
BOOST_STATIC_ASSERT(boost::is_signed<Number>::value);
|
||||||
BOOST_STATIC_ASSERT(
|
BOOST_STATIC_ASSERT(
|
||||||
(sizeof(Number) < sizeof(boost::intmax_t))
|
(sizeof(Number) < sizeof(boost::intmax_t))
|
||||||
| (boost::is_same<difference_type, Number>::value));
|
| (boost::is_same<difference_type, Number>::value));
|
||||||
@ -331,22 +341,20 @@ void test_aux(signed_tag, Number*)
|
|||||||
// Force casting to Number here to work around the fact that it's an enum on MSVC
|
// Force casting to Number here to work around the fact that it's an enum on MSVC
|
||||||
BOOST_STATIC_ASSERT(Number(complement_traits<Number>::max) > Number(0));
|
BOOST_STATIC_ASSERT(Number(complement_traits<Number>::max) > Number(0));
|
||||||
BOOST_STATIC_ASSERT(Number(complement_traits<Number>::min) < Number(0));
|
BOOST_STATIC_ASSERT(Number(complement_traits<Number>::min) < Number(0));
|
||||||
#endif
|
#endif
|
||||||
const Number max = complement_traits<Number>::max;
|
const Number max = complement_traits<Number>::max;
|
||||||
const Number min = complement_traits<Number>::min;
|
const Number min = complement_traits<Number>::min;
|
||||||
|
|
||||||
std::cout << std::hex << "min = " << stream_number(min) << ", max = "
|
std::cout << std::hex << "min = " << stream_number(min) << ", max = "
|
||||||
<< stream_number(max) << "..." << std::flush;
|
<< stream_number(max) << "..." << std::flush;
|
||||||
std::cout << "difference_type = " << typeid(difference_type).name() << "..."
|
std::cout << "difference_type = " << typeid(difference_type).name() << "..."
|
||||||
<< std::flush;
|
<< std::flush;
|
||||||
|
|
||||||
typedef typename boost::detail::if_true<
|
typedef typename boost::conditional<
|
||||||
(sizeof(Number) < sizeof(boost::intmax_t))>
|
(sizeof(Number) < sizeof(boost::intmax_t)),
|
||||||
::template then<
|
in_range_tag,
|
||||||
in_range_tag,
|
out_of_range_tag
|
||||||
out_of_range_tag
|
>::type range_tag;
|
||||||
>::type
|
|
||||||
range_tag;
|
|
||||||
signed_test<Number>(range_tag(), 0);
|
signed_test<Number>(range_tag(), 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -365,7 +373,7 @@ void test(Number* = 0)
|
|||||||
<< "..." << std::flush;
|
<< "..." << std::flush;
|
||||||
|
|
||||||
// factoring out difference_type for the assert below confused Borland :(
|
// factoring out difference_type for the assert below confused Borland :(
|
||||||
typedef boost::detail::is_signed<
|
typedef boost::is_signed<
|
||||||
#if !defined(BOOST_MSVC) || BOOST_MSVC > 1300
|
#if !defined(BOOST_MSVC) || BOOST_MSVC > 1300
|
||||||
typename
|
typename
|
||||||
#endif
|
#endif
|
||||||
@ -373,10 +381,12 @@ void test(Number* = 0)
|
|||||||
> is_signed;
|
> is_signed;
|
||||||
BOOST_STATIC_ASSERT(is_signed::value);
|
BOOST_STATIC_ASSERT(is_signed::value);
|
||||||
|
|
||||||
typedef typename boost::detail::if_true<
|
typedef typename boost::conditional<
|
||||||
boost::detail::is_signed<Number>::value
|
boost::is_signed<Number>::value,
|
||||||
>::template then<signed_tag, unsigned_tag>::type signedness;
|
signed_tag,
|
||||||
|
unsigned_tag
|
||||||
|
>::type signedness;
|
||||||
|
|
||||||
test_aux<Number>(signedness(), 0);
|
test_aux<Number>(signedness(), 0);
|
||||||
std::cout << "passed" << std::endl;
|
std::cout << "passed" << std::endl;
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user