blob: 7b0bfa58c168f6b925f313efcf462b412a349b2e [file] [log] [blame]
/***************************************************************************
*
* 18.numeric.special.int.cpp - tests specializations of the numeric_limits
* class template on integer types
*
* $Id$
*
***************************************************************************
*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed
* with this work for additional information regarding copyright
* ownership. The ASF licenses this file to you under the Apache
* License, Version 2.0 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a copy of
* the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
* implied. See the License for the specific language governing
* permissions and limitations under the License.
*
* Copyright 2004-2008 Rogue Wave Software, Inc.
*
**************************************************************************/
#include <limits> // for numeric_limits
#include <climits> // for {CHAR,SHRT,INT,LONG}_{MIN,MAX}, etc.
#include <cstdio> // for sprintf()
#include <rw_driver.h>
template <class T>
struct Limits
{
enum { is_specialized = false };
static T (min) () { return 0; }
static T (max) () { return 0; }
enum { digits };
enum { digits10 };
enum { is_signed };
enum { is_integer };
enum { is_exact };
enum { radix };
enum { is_bounded = false };
static bool is_modulo () { return false; }
static int compute_digits10 () {
return 0;
}
};
// edg (DEC cxx and others) gives an error in strict ANSI mode
// for things like INT_MAX + 1; this works around that error...
template <class T>
inline bool is_modulo (T _max)
{
// avoid MSVC warning C4800: 'int' :
// forcing value to bool 'true' or 'false' (performance warning)
T max_plus_one = _max;
return ++max_plus_one < _max;
}
_RWSTD_SPECIALIZED_FUNCTION
inline bool is_modulo (bool)
{
return false;
}
_RWSTD_SPECIALIZED_CLASS
struct Limits<int>
{
enum { is_specialized = true };
static int (min) () { return INT_MIN; }
static int (max) () { return INT_MAX; }
enum { digits = CHAR_BIT * sizeof (int) - 1 };
enum { digits10 = (digits * 301) / 1000 };
enum { is_signed = true };
enum { is_integer = true };
enum { is_exact = true };
enum { radix = 2 };
enum { is_bounded = true };
static bool is_modulo () { return ::is_modulo ((max)()); }
static int compute_digits10 () {
char buf [80];
return std::sprintf (buf, "%d", INT_MAX) - 1;
}
};
#ifndef _RWSTD_NO_BOOL
_RWSTD_SPECIALIZED_CLASS
struct Limits<bool>
{
enum { is_specialized = true };
static bool (min) () { return false; }
static bool (max) () { return true; }
enum { digits = 1 };
enum { digits10 = (digits * 301) / 1000 };
enum { is_signed = false };
enum { is_integer = true };
enum { is_exact = true };
enum { radix = 2 };
enum { is_bounded = true };
static bool is_modulo () { return ::is_modulo ((max)()); }
static int compute_digits10 () {
return 0;
}
};
#endif //_RWSTD_NO_BOOL
_RWSTD_SPECIALIZED_CLASS
struct Limits<char>
{
enum { is_specialized = true };
static char (min) () { return CHAR_MIN; }
static char (max) () { return CHAR_MAX; }
enum { is_signed = CHAR_MAX == SCHAR_MAX ? true : false };
enum {
digits = is_signed ? CHAR_BIT * sizeof (char) -1
: CHAR_BIT * sizeof (char)
};
enum { digits10 = (digits * 301) / 1000 };
enum { is_integer = true };
enum { is_exact = true };
enum { radix = 2 };
enum { is_bounded = true };
static bool is_modulo () { return ::is_modulo ((max)()); }
static int compute_digits10 () {
char buf [80];
return std::sprintf (buf, "%d", (unsigned char)CHAR_MAX) - 1;
}
};
_RWSTD_SPECIALIZED_CLASS
struct Limits<signed char>
{
enum { is_specialized = true };
static signed char (min) () { return SCHAR_MIN; }
static signed char (max) () { return SCHAR_MAX; }
enum { digits = CHAR_BIT * sizeof (signed char) - 1 };
enum { digits10 = (digits * 301) / 1000 };
enum { is_signed = true };
enum { is_integer = true };
enum { is_exact = true };
enum { radix = 2 };
enum { is_bounded = true };
static bool is_modulo () { return ::is_modulo ((max)()); }
static int compute_digits10 () {
char buf [80];
return std::sprintf (buf, "%d", (unsigned char)SCHAR_MAX) - 1;
}
};
_RWSTD_SPECIALIZED_CLASS
struct Limits<unsigned char>
{
enum { is_specialized = true };
static unsigned char (min) () { return 0; }
static unsigned char (max) () { return UCHAR_MAX; }
enum { digits = CHAR_BIT * sizeof (unsigned char) };
enum { digits10 = (digits * 301) / 1000 };
enum { is_signed = false };
enum { is_integer = true };
enum { is_exact = true };
enum { radix = 2 };
enum { is_bounded = true };
static bool is_modulo () { return ::is_modulo ((max)()); }
static int compute_digits10 () {
char buf [80];
return std::sprintf (buf, "%d", (unsigned char)UCHAR_MAX) - 1;
}
};
#ifndef _RWSTD_NO_NATIVE_WCHAR_T
_RWSTD_SPECIALIZED_CLASS
struct Limits<wchar_t>
{
enum { is_specialized = true };
static wchar_t (min) () {
return wchar_t (-1) > wchar_t (0) ? 0
: sizeof (wchar_t) == sizeof (short) ? wchar_t (SHRT_MIN)
: sizeof (wchar_t) == sizeof (int) ? wchar_t (INT_MIN)
: sizeof (wchar_t) == sizeof (long) ? wchar_t (LONG_MIN)
: wchar_t (SCHAR_MIN);
}
static wchar_t (max) () {
return wchar_t (-1) > wchar_t (0) ?
( sizeof (wchar_t) == sizeof (short) ? wchar_t (USHRT_MAX)
: sizeof (wchar_t) == sizeof (int) ? wchar_t (UINT_MAX)
: sizeof (wchar_t) == sizeof (long) ? wchar_t (ULONG_MAX)
: wchar_t (SCHAR_MAX))
: ( sizeof (wchar_t) == sizeof (short) ? wchar_t (SHRT_MAX)
: sizeof (wchar_t) == sizeof (int) ? wchar_t (INT_MAX)
: sizeof (wchar_t) == sizeof (long) ? wchar_t (LONG_MAX)
: wchar_t (UCHAR_MAX));
}
enum { is_signed = wchar_t (0) > wchar_t (~0) };
enum {
digits = is_signed ? CHAR_BIT * sizeof (wchar_t) - 1
: CHAR_BIT*sizeof(wchar_t)
};
enum { digits10 = (digits * 301) / 1000 };
enum { is_integer = true };
enum { is_exact = true };
enum { radix = 2 };
enum { is_bounded = true };
static bool is_modulo () { return ::is_modulo ((max)()); }
static int compute_digits10 () {
char buf [80];
return std::sprintf (buf, "%u", wchar_t (~0)) - 1;
}
};
#endif //_RWSTD_NO_NATIVE_WCHAR_T
_RWSTD_SPECIALIZED_CLASS
struct Limits<short>
{
enum { is_specialized = true };
static short (min) () { return SHRT_MIN; }
static short (max) () { return SHRT_MAX; }
enum { digits = CHAR_BIT * sizeof (short) - 1 };
enum { digits10 = (digits * 301) / 1000 };
enum { is_signed = true };
enum { is_integer = true };
enum { is_exact = true };
enum { radix = 2 };
enum { is_bounded = true };
static bool is_modulo () { return ::is_modulo ((max)()); }
static int compute_digits10 () {
char buf [80];
return std::sprintf (buf, "%d", (int)SHRT_MAX) - 1;
}
};
_RWSTD_SPECIALIZED_CLASS
struct Limits<long>
{
enum { is_specialized = true };
static long (min) () { return LONG_MIN; }
static long (max) () { return LONG_MAX; }
enum { digits = CHAR_BIT * sizeof(long)-1 };
enum { digits10 = (digits * 301) / 1000 };
enum { is_signed = true };
enum { is_integer = true };
enum { is_exact = true };
enum { radix = 2 };
enum { is_bounded = true };
static bool is_modulo () { return ::is_modulo ((max)()); }
static int compute_digits10 () {
char buf [80];
return std::sprintf (buf, "%ld", LONG_MAX) - 1;
}
};
_RWSTD_SPECIALIZED_CLASS
struct Limits <unsigned short>
{
enum { is_specialized = true };
static unsigned short (min) () { return 0; }
static unsigned short (max) () { return USHRT_MAX; }
enum { digits = CHAR_BIT * sizeof(unsigned short) };
enum { digits10 = (digits * 301) / 1000 };
enum { is_signed = false };
enum { is_integer = true };
enum { is_exact = true };
enum { radix = 2 };
enum { is_bounded = true };
static bool is_modulo () { return ::is_modulo ((max)()); }
static int compute_digits10 () {
char buf [80];
return std::sprintf (buf, "%u", unsigned (USHRT_MAX)) - 1;
}
};
_RWSTD_SPECIALIZED_CLASS
struct Limits<unsigned int>
{
enum { is_specialized = true };
static unsigned int (min) () { return 0; }
static unsigned int (max) () { return UINT_MAX; }
enum { digits = CHAR_BIT * sizeof(unsigned int) };
enum { digits10 = (digits * 301) / 1000 };
enum { is_signed = false };
enum { is_integer = true };
enum { is_exact = true };
enum { radix = 2 };
enum { is_bounded = true };
static bool is_modulo () { return ::is_modulo ((max)()); }
static int compute_digits10 () {
char buf [80];
return std::sprintf (buf, "%u", UINT_MAX) - 1;
}
};
_RWSTD_SPECIALIZED_CLASS
struct Limits<unsigned long>
{
enum { is_specialized = true };
static unsigned long (min) () { return 0; }
static unsigned long (max) () { return ULONG_MAX; }
enum { digits = CHAR_BIT * sizeof(unsigned long) };
enum { digits10 = (digits * 301) / 1000 };
enum { is_signed = false };
enum { is_integer = true };
enum { is_exact = true };
enum { radix = 2 };
enum { is_bounded = true };
static bool is_modulo () { return ::is_modulo ((max)()); }
static int compute_digits10 () {
char buf [80];
return std::sprintf (buf, "%lu", ULONG_MAX) - 1;
}
};
#ifdef _RWSTD_LONG_LONG
_RWSTD_SPECIALIZED_CLASS
struct Limits<_RWSTD_LONG_LONG>
{
typedef _RWSTD_LONG_LONG LLong;
enum { is_specialized = true };
static LLong (min) () {
typedef unsigned _RWSTD_LONG_LONG ULLong;
ULLong zero = 0; // prevent an EDG eccp warning #68-D
return ~zero / ULLong (2) + ULLong (1);
}
static LLong (max) () {
typedef unsigned _RWSTD_LONG_LONG ULLong;
return ~ULLong (0) / ULLong (2);
}
enum { digits = CHAR_BIT * sizeof (LLong) - 1 };
enum { digits10 = (digits * 301) / 1000 };
enum { is_signed = true };
enum { is_integer = true };
enum { is_exact = true };
enum { radix = 2 };
enum { is_bounded = true };
static bool is_modulo () { return ::is_modulo ((max)()); }
static int compute_digits10 () {
char buf [80];
const char fmt[] = "%" _RWSTD_LLONG_PRINTF_PREFIX "u";
return std::sprintf (buf, fmt, (max) ()) - 1;
}
};
_RWSTD_SPECIALIZED_CLASS
struct Limits<unsigned _RWSTD_LONG_LONG>
{
typedef unsigned _RWSTD_LONG_LONG ULLong;
enum { is_specialized = true };
static ULLong (min) () { return 0; }
static ULLong (max) () { return ~ULLong (0); }
enum { digits = CHAR_BIT * sizeof (ULLong) };
enum { digits10 = (digits * 301) / 1000 };
enum { is_signed = false };
enum { is_integer = true };
enum { is_exact = true };
enum { radix = 2 };
enum { is_bounded = true };
static bool is_modulo () { return ::is_modulo ((max)()); }
static int compute_digits10 () {
char buf [80];
const char fmt[] = "%" _RWSTD_LLONG_PRINTF_PREFIX "i";
// work around libc bugs (e.g., glibc on Linux)
const int n = std::sprintf (buf, fmt, (max) ());
if (n < Limits<unsigned>::digits10)
return digits10;
return n - 1;
}
};
#endif // _RWSTD_LONG_LONG
template <class T>
void run_test (T*, const char *tname, const char *fmt)
{
typedef std::numeric_limits<T> limT;
typedef Limits<T> Traits;
RW_ASSERT (0 != tname);
RW_ASSERT (0 != fmt);
#if !defined (__EDG__) || __EDG_VERSION__ > 245
# define ASSERT(expr, fmt) \
/* verify that `expr' is a constant integral expression */ \
{ enum { is_const_integral_expression = limT::expr }; } \
rw_assert (limT::expr == int (Traits::expr), 0, __LINE__, \
"std::numeric_limits<%s>::" #expr \
" == %{@}, got %{@}", \
tname, fmt, Traits::expr, fmt, limT::expr)
#else // if EDG eccp < 3.0
// working around an EDG eccp 2.4x ICE
# define ASSERT(expr) \
/* verify that `expr' is a constant integral expression */ \
switch (limT::expr) { case limT::expr: break; }; \
rw_assert (limT::expr == int (Traits::expr), 0, __LINE__, \
"std::numeric_limits<%s>::" #expr \
"== %{@}, got %{@}", \
tname, fmt, Traits::expr, fmt, limT::expr)
#endif // EDG eccp < 3.0
#define ASSERT_0(expr, fmt) \
rw_assert (!limT::expr, 0, __LINE__, \
"std::numeric_limits<%s>::" #expr " == 0, got %{@}", \
tname, fmt, limT::expr)
ASSERT (is_specialized, "%#b");
// [numeric.special], p1
rw_assert ((limT::min)() == (Traits::min)(), 0, __LINE__,
"std::numeric_limits<%s>::min() == %{@}, got %{@}",
tname, fmt, (Traits::min)(), fmt, (limT::min)());
// [numeric.special], p4
rw_assert ((limT::max)() == (Traits::max)(), 0, __LINE__,
"std::numeric_limits<%s>::max() == %{@}, got %{@}",
tname, fmt, (Traits::max)(), fmt, (limT::max)());
// [numeric.special], p6
ASSERT (digits, "%d");
// [numeric.special], p9
ASSERT (digits10, "%d");
rw_assert (limT::digits10 == Traits::compute_digits10 (), 0, __LINE__,
"std::numeric_limits<%s>::digits10 == %d (computed), got %d",
tname, Traits::compute_digits10 (), limT::digits10);
// [numeric.special], p11
ASSERT (is_signed, "%b");
// [numeric.special], p13
ASSERT (is_integer, "%b");
// [numeric.special], p15
ASSERT (is_exact, "%b");
// [numeric.special], p17
ASSERT (radix, "%i");
// [numeric.special], p20
ASSERT_0 (epsilon (), fmt);
// [numeric.special], p22
ASSERT_0 (round_error (), fmt);
// [numeric.special], p23
ASSERT_0 (min_exponent, "%i");
// [numeric.special], p25
ASSERT_0 (min_exponent10, "%i");
// [numeric.special], p27
ASSERT_0 (max_exponent, "%i");
// [numeric.special], p29
ASSERT_0 (max_exponent10, "%i");
// [numeric.special], p31
ASSERT_0 (has_infinity, "%b");
// [numeric.special], p34
ASSERT_0 (has_quiet_NaN, "%b");
// [numeric.special], p37
ASSERT_0 (has_signaling_NaN, "%b");
// [numeric.special], p40
ASSERT_0 (has_denorm, "%b");
// [numeric.special], p42
ASSERT_0 (has_denorm_loss, "%b");
// [numeric.special], p43
ASSERT_0 (infinity (), fmt);
// [numeric.special], p45
ASSERT_0 (quiet_NaN (), fmt);
// [numeric.special], p47
ASSERT_0 (signaling_NaN (), fmt);
// [numeric.special], p49
ASSERT_0 (denorm_min (), fmt);
// [numeric.special], p52
ASSERT_0 (is_iec559, "%b");
// [numeric.special], p54
ASSERT (is_bounded, "%b");
// [numeric.special], p56
rw_assert (limT::is_modulo == Traits::is_modulo (), 0, __LINE__,
"std::numeric_limits<%s>::is_modulo == %#b",
tname, Traits::is_modulo ());
// [numeric.special], p59
// numeric_limits::traps exercised separately in 18.limits.traps.cpp
// to prevent runtime errors (SIGFPE) from hiding potential assertion
// failures in the rest of the test
// ASSERT_0 (traps, "%b");
// [numeric.special], p61
ASSERT_0 (tinyness_before, "%b");
// [numeric.special], p63
rw_assert (limT::round_style == int (std::round_toward_zero), 0, __LINE__,
"std::numeric_limits<%s>::round_style == %d",
tname, std::round_toward_zero);
}
static int
run_test (int, char**)
{
#define TEST(T, fmt) run_test ((T*)0, #T, fmt)
#ifndef _RWSTD_NO_BOOL
TEST (bool, "%#b");
#endif //_RWSTD_NO_BOOL
TEST (char, "%{#c}");
TEST (signed char, "%{#c}");
TEST (unsigned char, "%{#c}");
TEST (short, "%hi");
TEST (unsigned short, "%hu");
TEST (int, "%i");
TEST (unsigned int, "%u");
TEST (long, "%li");
TEST (unsigned long, "%lu");
#ifdef _RWSTD_LONG_LONG
run_test ((_RWSTD_LONG_LONG*)0, "long long", "%lli");
run_test ((unsigned _RWSTD_LONG_LONG*)0, "unsigned long long", "%llu");
#endif // _RWSTD_LONG_LONG
#ifndef _RWSTD_NO_NATIVE_WCHAR_T
TEST (wchar_t, "%{#lc}");
#endif //_RWSTD_NO_NATIVE_WCHAR_T
TEST (void*, "%#p");
return 0;
}
/**************************************************************************/
int main (int argc, char *argv[])
{
return rw_test (argc, argv, __FILE__,
"numeric.special",
"integer specializations",
run_test,
"",
(void*)0);
}