mirror of
https://github.com/boostorg/utility.git
synced 2025-05-09 23:14:02 +00:00
Moved numeric_traits_test.cpp to Boost.Detail.
This commit is contained in:
parent
88c36c1941
commit
2ed5ee9588
@ -24,8 +24,6 @@ run compressed_pair_test.cpp ../../test/build//boost_test_exec_monitor/<link>sta
|
|||||||
|
|
||||||
run iterators_test.cpp ../../test/build//boost_test_exec_monitor/<link>static ;
|
run iterators_test.cpp ../../test/build//boost_test_exec_monitor/<link>static ;
|
||||||
|
|
||||||
run numeric_traits_test.cpp ;
|
|
||||||
|
|
||||||
run operators_test.cpp ../../test/build//boost_test_exec_monitor/<link>static ;
|
run operators_test.cpp ../../test/build//boost_test_exec_monitor/<link>static ;
|
||||||
|
|
||||||
compile result_of_test.cpp ;
|
compile result_of_test.cpp ;
|
||||||
|
@ -1,406 +0,0 @@
|
|||||||
// (C) Copyright David Abrahams 2001.
|
|
||||||
// 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 for most recent version including documentation.
|
|
||||||
|
|
||||||
// Revision History
|
|
||||||
// 1 Apr 2001 Fixes for ICL; use BOOST_STATIC_CONSTANT
|
|
||||||
// 11 Feb 2001 Fixes for Borland (David Abrahams)
|
|
||||||
// 23 Jan 2001 Added test for wchar_t (David Abrahams)
|
|
||||||
// 23 Jan 2001 Now statically selecting a test for signed numbers to avoid
|
|
||||||
// warnings with fancy compilers. Added commentary and
|
|
||||||
// additional dumping of traits data for tested types (David
|
|
||||||
// Abrahams).
|
|
||||||
// 21 Jan 2001 Initial version (David Abrahams)
|
|
||||||
|
|
||||||
#include <boost/detail/numeric_traits.hpp>
|
|
||||||
#include <cassert>
|
|
||||||
#include <boost/type_traits.hpp>
|
|
||||||
#include <boost/static_assert.hpp>
|
|
||||||
#include <boost/cstdint.hpp>
|
|
||||||
#include <boost/utility.hpp>
|
|
||||||
#include <boost/lexical_cast.hpp>
|
|
||||||
#include <climits>
|
|
||||||
#include <typeinfo>
|
|
||||||
#include <iostream>
|
|
||||||
#include <string>
|
|
||||||
#ifndef BOOST_NO_LIMITS
|
|
||||||
# include <limits>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// =================================================================================
|
|
||||||
// template class complement_traits<Number> --
|
|
||||||
//
|
|
||||||
// statically computes the max and min for 1s and 2s-complement binary
|
|
||||||
// numbers. This helps on platforms without <limits> support. It also shows
|
|
||||||
// an example of a recursive template that works with MSVC!
|
|
||||||
//
|
|
||||||
|
|
||||||
template <unsigned size> struct complement; // forward
|
|
||||||
|
|
||||||
// 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
|
|
||||||
// complain about undefined min/max as we're trying to recursively define them.
|
|
||||||
template <class Number, unsigned size>
|
|
||||||
struct complement_traits_aux
|
|
||||||
{
|
|
||||||
BOOST_STATIC_CONSTANT(Number, max = complement<size>::template traits<Number>::max);
|
|
||||||
BOOST_STATIC_CONSTANT(Number, min = complement<size>::template traits<Number>::min);
|
|
||||||
};
|
|
||||||
|
|
||||||
template <unsigned size>
|
|
||||||
struct complement
|
|
||||||
{
|
|
||||||
template <class Number>
|
|
||||||
struct traits
|
|
||||||
{
|
|
||||||
private:
|
|
||||||
// indirection through complement_traits_aux necessary to keep MSVC happy
|
|
||||||
typedef complement_traits_aux<Number, size - 1> prev;
|
|
||||||
public:
|
|
||||||
#if defined(__GNUC__) && __GNUC__ == 4 && __GNUC_MINOR__ == 0 && __GNUC_PATCHLEVEL__ == 2
|
|
||||||
// GCC 4.0.2 ICEs on these C-style casts
|
|
||||||
BOOST_STATIC_CONSTANT(Number, max =
|
|
||||||
Number((prev::max) << CHAR_BIT)
|
|
||||||
+ Number(UCHAR_MAX));
|
|
||||||
BOOST_STATIC_CONSTANT(Number, min = Number((prev::min) << CHAR_BIT));
|
|
||||||
#else
|
|
||||||
// Avoid left shifting negative integers, use multiplication instead
|
|
||||||
BOOST_STATIC_CONSTANT(Number, shift = 1u << CHAR_BIT);
|
|
||||||
BOOST_STATIC_CONSTANT(Number, max =
|
|
||||||
Number(Number(prev::max) * shift)
|
|
||||||
+ Number(UCHAR_MAX));
|
|
||||||
BOOST_STATIC_CONSTANT(Number, min = Number(Number(prev::min) * shift));
|
|
||||||
#endif
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
// Template class complement_base<> -- defines values for min and max for
|
|
||||||
// complement<1>, at the deepest level of recursion. Uses "poor man's partial
|
|
||||||
// specialization" again.
|
|
||||||
template <bool is_signed> struct complement_base;
|
|
||||||
|
|
||||||
template <> struct complement_base<false>
|
|
||||||
{
|
|
||||||
template <class Number>
|
|
||||||
struct values
|
|
||||||
{
|
|
||||||
BOOST_STATIC_CONSTANT(Number, min = 0);
|
|
||||||
BOOST_STATIC_CONSTANT(Number, max = UCHAR_MAX);
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
template <> struct complement_base<true>
|
|
||||||
{
|
|
||||||
template <class Number>
|
|
||||||
struct values
|
|
||||||
{
|
|
||||||
BOOST_STATIC_CONSTANT(Number, min = SCHAR_MIN);
|
|
||||||
BOOST_STATIC_CONSTANT(Number, max = SCHAR_MAX);
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
// Base specialization of complement, puts an end to the recursion.
|
|
||||||
template <>
|
|
||||||
struct complement<1>
|
|
||||||
{
|
|
||||||
template <class Number>
|
|
||||||
struct traits
|
|
||||||
{
|
|
||||||
BOOST_STATIC_CONSTANT(bool, is_signed = boost::detail::is_signed<Number>::value);
|
|
||||||
BOOST_STATIC_CONSTANT(Number, min =
|
|
||||||
complement_base<is_signed>::template values<Number>::min);
|
|
||||||
BOOST_STATIC_CONSTANT(Number, max =
|
|
||||||
complement_base<is_signed>::template values<Number>::max);
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
// Now here's the "pretty" template you're intended to actually use.
|
|
||||||
// complement_traits<Number>::min, complement_traits<Number>::max are the
|
|
||||||
// minimum and maximum values of Number if Number is a built-in integer type.
|
|
||||||
template <class Number>
|
|
||||||
struct complement_traits
|
|
||||||
{
|
|
||||||
BOOST_STATIC_CONSTANT(Number, max = (complement_traits_aux<Number, sizeof(Number)>::max));
|
|
||||||
BOOST_STATIC_CONSTANT(Number, min = (complement_traits_aux<Number, sizeof(Number)>::min));
|
|
||||||
};
|
|
||||||
|
|
||||||
// =================================================================================
|
|
||||||
|
|
||||||
// Support for streaming various numeric types in exactly the format I want. I
|
|
||||||
// needed this in addition to all the assertions so that I could see exactly
|
|
||||||
// what was going on.
|
|
||||||
//
|
|
||||||
// Numbers go through a 2-stage conversion process (by default, though, no real
|
|
||||||
// conversion).
|
|
||||||
//
|
|
||||||
template <class T> struct stream_as {
|
|
||||||
typedef T t1;
|
|
||||||
typedef T t2;
|
|
||||||
};
|
|
||||||
|
|
||||||
// char types first get converted to unsigned char, then to unsigned.
|
|
||||||
template <> struct stream_as<char> {
|
|
||||||
typedef unsigned char t1;
|
|
||||||
typedef unsigned t2;
|
|
||||||
};
|
|
||||||
template <> struct stream_as<unsigned char> {
|
|
||||||
typedef unsigned char t1; typedef unsigned t2;
|
|
||||||
};
|
|
||||||
template <> struct stream_as<signed char> {
|
|
||||||
typedef unsigned char t1; typedef unsigned t2;
|
|
||||||
};
|
|
||||||
|
|
||||||
#if defined(BOOST_MSVC_STD_ITERATOR) // No intmax streaming built-in
|
|
||||||
|
|
||||||
// With this library implementation, __int64 and __uint64 get streamed as strings
|
|
||||||
template <> struct stream_as<boost::uintmax_t> {
|
|
||||||
typedef std::string t1;
|
|
||||||
typedef std::string t2;
|
|
||||||
};
|
|
||||||
|
|
||||||
template <> struct stream_as<boost::intmax_t> {
|
|
||||||
typedef std::string t1;
|
|
||||||
typedef std::string t2;
|
|
||||||
};
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// Standard promotion process for streaming
|
|
||||||
template <class T> struct promote
|
|
||||||
{
|
|
||||||
static typename stream_as<T>::t1 from(T x) {
|
|
||||||
typedef typename stream_as<T>::t1 t1;
|
|
||||||
return t1(x);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
#if defined(BOOST_MSVC_STD_ITERATOR) // No intmax streaming built-in
|
|
||||||
|
|
||||||
// On this platform, stream them as long/unsigned long if they fit.
|
|
||||||
// Otherwise, write a string.
|
|
||||||
template <> struct promote<boost::uintmax_t> {
|
|
||||||
std::string static from(const boost::uintmax_t x) {
|
|
||||||
if (x > ULONG_MAX)
|
|
||||||
return std::string("large unsigned value");
|
|
||||||
else
|
|
||||||
return boost::lexical_cast<std::string>((unsigned long)x);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
template <> struct promote<boost::intmax_t> {
|
|
||||||
std::string static from(const boost::intmax_t x) {
|
|
||||||
if (x > boost::intmax_t(ULONG_MAX))
|
|
||||||
return std::string("large positive signed value");
|
|
||||||
else if (x >= 0)
|
|
||||||
return boost::lexical_cast<std::string>((unsigned long)x);
|
|
||||||
|
|
||||||
if (x < boost::intmax_t(LONG_MIN))
|
|
||||||
return std::string("large negative signed value");
|
|
||||||
else
|
|
||||||
return boost::lexical_cast<std::string>((long)x);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// This is the function which converts types to the form I want to stream them in.
|
|
||||||
template <class T>
|
|
||||||
typename stream_as<T>::t2 stream_number(T x)
|
|
||||||
{
|
|
||||||
return promote<T>::from(x);
|
|
||||||
}
|
|
||||||
// =================================================================================
|
|
||||||
|
|
||||||
//
|
|
||||||
// Tests for built-in signed and unsigned types
|
|
||||||
//
|
|
||||||
|
|
||||||
// Tag types for selecting tests
|
|
||||||
struct unsigned_tag {};
|
|
||||||
struct signed_tag {};
|
|
||||||
|
|
||||||
// Tests for unsigned numbers. The extra default Number parameter works around
|
|
||||||
// an MSVC bug.
|
|
||||||
template <class Number>
|
|
||||||
void test_aux(unsigned_tag, Number*)
|
|
||||||
{
|
|
||||||
typedef typename boost::detail::numeric_traits<Number>::difference_type difference_type;
|
|
||||||
BOOST_STATIC_ASSERT(!boost::detail::is_signed<Number>::value);
|
|
||||||
BOOST_STATIC_ASSERT(
|
|
||||||
(sizeof(Number) < sizeof(boost::intmax_t))
|
|
||||||
| (boost::is_same<difference_type, boost::intmax_t>::value));
|
|
||||||
|
|
||||||
#if defined(__GNUC__) && __GNUC__ == 4 && __GNUC_MINOR__ == 0 && __GNUC_PATCHLEVEL__ == 2
|
|
||||||
// GCC 4.0.2 ICEs on this C-style cases
|
|
||||||
BOOST_STATIC_ASSERT((complement_traits<Number>::max) > Number(0));
|
|
||||||
BOOST_STATIC_ASSERT((complement_traits<Number>::min) == Number(0));
|
|
||||||
#else
|
|
||||||
// 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>::min) == Number(0));
|
|
||||||
#endif
|
|
||||||
|
|
||||||
const Number max = complement_traits<Number>::max;
|
|
||||||
const Number min = complement_traits<Number>::min;
|
|
||||||
|
|
||||||
const Number test_max = (sizeof(Number) < sizeof(boost::intmax_t))
|
|
||||||
? max
|
|
||||||
: max / 2 - 1;
|
|
||||||
|
|
||||||
std::cout << std::hex << "(unsigned) min = " << stream_number(min) << ", max = "
|
|
||||||
<< stream_number(max) << "..." << std::flush;
|
|
||||||
std::cout << "difference_type = " << typeid(difference_type).name() << "..."
|
|
||||||
<< std::flush;
|
|
||||||
|
|
||||||
difference_type d1 = boost::detail::numeric_distance(Number(0), test_max);
|
|
||||||
difference_type d2 = boost::detail::numeric_distance(test_max, Number(0));
|
|
||||||
|
|
||||||
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;
|
|
||||||
|
|
||||||
assert(d1 == difference_type(test_max));
|
|
||||||
assert(d2 == -difference_type(test_max));
|
|
||||||
}
|
|
||||||
|
|
||||||
// Tests for signed numbers. The extra default Number parameter works around an
|
|
||||||
// MSVC bug.
|
|
||||||
struct out_of_range_tag {};
|
|
||||||
struct in_range_tag {};
|
|
||||||
|
|
||||||
// This test morsel gets executed for numbers whose difference will always be
|
|
||||||
// representable in intmax_t
|
|
||||||
template <class Number>
|
|
||||||
void signed_test(in_range_tag, Number*)
|
|
||||||
{
|
|
||||||
BOOST_STATIC_ASSERT(boost::detail::is_signed<Number>::value);
|
|
||||||
typedef typename boost::detail::numeric_traits<Number>::difference_type difference_type;
|
|
||||||
const Number max = complement_traits<Number>::max;
|
|
||||||
const Number min = complement_traits<Number>::min;
|
|
||||||
|
|
||||||
difference_type d1 = boost::detail::numeric_distance(min, max);
|
|
||||||
difference_type d2 = boost::detail::numeric_distance(max, min);
|
|
||||||
|
|
||||||
std::cout << stream_number(min) << "->" << stream_number(max) << "==";
|
|
||||||
std::cout << std::dec << stream_number(d1) << "; ";
|
|
||||||
std::cout << std::hex << stream_number(max) << "->" << stream_number(min)
|
|
||||||
<< "==" << std::dec << stream_number(d2) << "..." << std::flush;
|
|
||||||
assert(d1 == difference_type(max) - difference_type(min));
|
|
||||||
assert(d2 == difference_type(min) - difference_type(max));
|
|
||||||
}
|
|
||||||
|
|
||||||
// This test morsel gets executed for numbers whose difference may exceed the
|
|
||||||
// capacity of intmax_t.
|
|
||||||
template <class Number>
|
|
||||||
void signed_test(out_of_range_tag, Number*)
|
|
||||||
{
|
|
||||||
BOOST_STATIC_ASSERT(boost::detail::is_signed<Number>::value);
|
|
||||||
typedef typename boost::detail::numeric_traits<Number>::difference_type difference_type;
|
|
||||||
const Number max = complement_traits<Number>::max;
|
|
||||||
const Number min = complement_traits<Number>::min;
|
|
||||||
|
|
||||||
difference_type min_distance = complement_traits<difference_type>::min;
|
|
||||||
difference_type max_distance = complement_traits<difference_type>::max;
|
|
||||||
|
|
||||||
const Number n1 = Number(min + max_distance);
|
|
||||||
const Number n2 = Number(max + min_distance);
|
|
||||||
difference_type d1 = boost::detail::numeric_distance(min, n1);
|
|
||||||
difference_type d2 = boost::detail::numeric_distance(max, n2);
|
|
||||||
|
|
||||||
std::cout << stream_number(min) << "->" << stream_number(n1) << "==";
|
|
||||||
std::cout << std::dec << stream_number(d1) << "; ";
|
|
||||||
std::cout << std::hex << stream_number(max) << "->" << stream_number(n2)
|
|
||||||
<< "==" << std::dec << stream_number(d2) << "..." << std::flush;
|
|
||||||
assert(d1 == max_distance);
|
|
||||||
assert(d2 == min_distance);
|
|
||||||
}
|
|
||||||
|
|
||||||
template <class Number>
|
|
||||||
void test_aux(signed_tag, Number*)
|
|
||||||
{
|
|
||||||
typedef typename boost::detail::numeric_traits<Number>::difference_type difference_type;
|
|
||||||
BOOST_STATIC_ASSERT(boost::detail::is_signed<Number>::value);
|
|
||||||
BOOST_STATIC_ASSERT(
|
|
||||||
(sizeof(Number) < sizeof(boost::intmax_t))
|
|
||||||
| (boost::is_same<difference_type, Number>::value));
|
|
||||||
|
|
||||||
#if defined(__GNUC__) && __GNUC__ == 4 && __GNUC_MINOR__ == 0 && __GNUC_PATCHLEVEL__ == 2
|
|
||||||
// GCC 4.0.2 ICEs on this cast
|
|
||||||
BOOST_STATIC_ASSERT((complement_traits<Number>::max) > Number(0));
|
|
||||||
BOOST_STATIC_ASSERT((complement_traits<Number>::min) < Number(0));
|
|
||||||
#else
|
|
||||||
// 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>::min) < Number(0));
|
|
||||||
#endif
|
|
||||||
const Number max = complement_traits<Number>::max;
|
|
||||||
const Number min = complement_traits<Number>::min;
|
|
||||||
|
|
||||||
std::cout << std::hex << "min = " << stream_number(min) << ", max = "
|
|
||||||
<< stream_number(max) << "..." << std::flush;
|
|
||||||
std::cout << "difference_type = " << typeid(difference_type).name() << "..."
|
|
||||||
<< std::flush;
|
|
||||||
|
|
||||||
typedef typename boost::detail::if_true<
|
|
||||||
(sizeof(Number) < sizeof(boost::intmax_t))>
|
|
||||||
::template then<
|
|
||||||
in_range_tag,
|
|
||||||
out_of_range_tag
|
|
||||||
>::type
|
|
||||||
range_tag;
|
|
||||||
signed_test<Number>(range_tag(), 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// Test for all numbers. The extra default Number parameter works around an MSVC
|
|
||||||
// bug.
|
|
||||||
template <class Number>
|
|
||||||
void test(Number* = 0)
|
|
||||||
{
|
|
||||||
std::cout << "testing " << typeid(Number).name() << ":\n"
|
|
||||||
#ifndef BOOST_NO_LIMITS_COMPILE_TIME_CONSTANTS
|
|
||||||
<< "is_signed: " << (std::numeric_limits<Number>::is_signed ? "true\n" : "false\n")
|
|
||||||
<< "is_bounded: " << (std::numeric_limits<Number>::is_bounded ? "true\n" : "false\n")
|
|
||||||
<< "digits: " << std::numeric_limits<Number>::digits << "\n"
|
|
||||||
#endif
|
|
||||||
<< "..." << std::flush;
|
|
||||||
|
|
||||||
// factoring out difference_type for the assert below confused Borland :(
|
|
||||||
typedef boost::detail::is_signed<
|
|
||||||
#if !defined(BOOST_MSVC) || BOOST_MSVC > 1300
|
|
||||||
typename
|
|
||||||
#endif
|
|
||||||
boost::detail::numeric_traits<Number>::difference_type
|
|
||||||
> is_signed;
|
|
||||||
BOOST_STATIC_ASSERT(is_signed::value);
|
|
||||||
|
|
||||||
typedef typename boost::detail::if_true<
|
|
||||||
boost::detail::is_signed<Number>::value
|
|
||||||
>::template then<signed_tag, unsigned_tag>::type signedness;
|
|
||||||
|
|
||||||
test_aux<Number>(signedness(), 0);
|
|
||||||
std::cout << "passed" << std::endl;
|
|
||||||
}
|
|
||||||
|
|
||||||
int main()
|
|
||||||
{
|
|
||||||
test<char>();
|
|
||||||
test<unsigned char>();
|
|
||||||
test<signed char>();
|
|
||||||
test<wchar_t>();
|
|
||||||
test<short>();
|
|
||||||
test<unsigned short>();
|
|
||||||
test<int>();
|
|
||||||
test<unsigned int>();
|
|
||||||
test<long>();
|
|
||||||
test<unsigned long>();
|
|
||||||
#if defined(BOOST_HAS_LONG_LONG) && !defined(BOOST_NO_INTEGRAL_INT64_T)
|
|
||||||
test< ::boost::long_long_type>();
|
|
||||||
test< ::boost::ulong_long_type>();
|
|
||||||
#elif defined(BOOST_MSVC)
|
|
||||||
// The problem of not having compile-time static class constants other than
|
|
||||||
// enums prevents this from working, since values get truncated.
|
|
||||||
// test<boost::uintmax_t>();
|
|
||||||
// test<boost::intmax_t>();
|
|
||||||
#endif
|
|
||||||
return 0;
|
|
||||||
}
|
|
Loading…
x
Reference in New Issue
Block a user