blob: e3e6dfa0e8a11670f7db89cc56dbb826e87e9374 [file] [log] [blame]
// computing numerical limits
/***************************************************************************
*
* 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 1999-2007 Rogue Wave Software, Inc.
*
**************************************************************************/
#include "config.h"
#include <stdio.h> // for printf()
#ifndef _RWSTD_NO_LIMITS_H
// avoid including broken <limits.h> (due to the use of #include_next)
// with EDG eccp on Linux
# include <limits.h> // for MB_LEN_MAX
#endif // _RWSTD_NO_LIMITS_H
// establish a dependency on the test for long long
// and #define the LONG_LONG macro used in "type.h"
#ifndef _RWSTD_NO_LONG_LONG
# define LONG_LONG long long
#else // if defined (_RWSTD_NO_LONG_LONG)
# if defined (_MSC_VER)
# define LONG_LONG __int64
# endif // _MSC_VER
#endif // _RWSTD_NO_LONG_LONG
#include "types.h" // for type_name()
#ifndef _RWSTD_NO_HONOR_STD
# ifdef _RWSTD_NO_STD_TERMINATE
# include "terminate.h"
# endif // _RWSTD_NO_STD_TERMINATE
#endif // _RWSTD_NO_HONOR_STD
// set to 1 if this is not a two's complement architecture
int no_twos_complement = 0;
// volatile to foil aggressive optimizers
volatile int zero = 0;
volatile int one = zero + 1;
volatile int two = one + 1;
volatile int zero_complement = ~zero;
template<class T>
void print_limit (T n, const char *pfx, const char *sfx,
bool is_max, const char *type)
{
// prevents meaningless comparison warnings when T is unsigned
// e.g., for (n < 0)
/* not const */ T zero = T (0);
char nstr [64] = { 0 };
char* pnstr = nstr + sizeof nstr - 2;
const char digit [] = {
'0','1','2','3','4','5','6','7','8','9', 'a', 'b', 'c', 'd', 'e', 'f'
};
if (is_max || n >= zero) {
T tnstr = n;
*--pnstr = digit [tnstr % 16];
while (tnstr /= 16)
*--pnstr = digit [tnstr % 16];
}
*--pnstr = 'x';
if ( 'c' == type [0]
&& 'h' == type [1]
&& 'a' == type [2]
&& 'r' == type [3]
&& '\0' == type [4]) {
*--pnstr = '\\';
*--pnstr = '\'';
nstr [sizeof nstr - 2] = '\'';
}
else {
*--pnstr = '0';
}
char macro_name [64];
char macro_value [64];
if (is_max) {
sprintf (macro_name, "_RWSTD_%s_MAX", pfx);
sprintf (macro_value, "%s%s", pnstr, sfx);
}
else {
sprintf (macro_name, "_RWSTD_%s_MIN ", pfx);
if (n < zero) {
if (no_twos_complement) {
sprintf (macro_value, "-_RWSTD_%s_MAX", pfx);
}
else {
sprintf (macro_value, "(-_RWSTD_%s_MAX - 1%s)", pfx, sfx);
}
}
else {
sprintf (macro_value, "%s%s", pnstr, sfx);
}
}
printf ("#define %-18s %s\n", macro_name, macro_value);
}
template <class T>
T compute_min (T min)
{
// prevents overzealous gcc optimizer from invoking
// undefined behavior on signed integer over/underflow
for (T tmp; ; --min) {
tmp = T (min - one);
if (tmp >= min)
break;
}
return min;
}
template <class T>
const char* type_suffix (T) { return ""; }
const char* type_suffix (short) { return ""; }
const char* type_suffix (unsigned short) { return "U"; }
const char* type_suffix (int) { return ""; }
const char* type_suffix (unsigned int) { return "U"; }
const char* type_suffix (long) { return "L"; }
const char* type_suffix (unsigned long) { return "UL"; }
#ifndef _RWSTD_NO_LONG_LONG
const char* type_suffix (long long) { return "LL"; }
const char* type_suffix (unsigned long long) { return "ULL"; }
#else
# if defined (_MSC_VER)
const char* type_suffix (__int64) { return "L"; }
const char* type_suffix (unsigned __int64) { return "UL"; }
# endif // _MSC_VER
#endif
template <class T>
T compute_limits (T *pval, const char *pfx, const char *sfx, const char *type)
{
T min = T (-one);
T max = T (one);
int is_signed = T (min - one) < T (zero);
if (!is_signed)
max = min;
// compute the maximum representable value
for (; T (max * two) > max; max *= two);
for (*pval = max / (two + two); *pval; ) {
if (T (max + *pval) < max) {
if (*pval > T (two))
*pval /= two;
else if (max < T (max + one))
*pval = one;
else
break;
}
else
max += *pval;
}
// print the maximum representable value
print_limit (max, pfx, sfx, true, type);
// compute the minimum representable value
for (min = -max; T (min * two) < min; min *= two);
// working around a gcc optimizer "feature" (PR #26211)
// signed integer overflow is undefined behavior
// for (; T (min - 1) < min; min -= 1);
min = compute_min (min);
print_limit (min, pfx, sfx, false, type);
return max;
}
unsigned compute_char_bits ()
{
unsigned bits = 0;
for (unsigned char c = '\01'; c; c <<= 1, ++bits);
printf ("#define _RWSTD_CHAR_BIT %2u\n", bits);
return bits;
}
// used to compute the size of a pointer to a member function
struct EmptyStruct { };
// to silence printf() format comaptibility warnings
#define SIZEOF(T) unsigned (sizeof (T))
int main ()
{
// determine whether this is a two's complement architecture
// and set the no_twos_complement global variable to 1 if not
if (two + zero_complement != one)
no_twos_complement = 1;
// compute sizes of fundamental types
#ifndef _RWSTD_NO_BOOL
printf ("#define _RWSTD_BOOL_SIZE %2u /* sizeof (bool) */\n",
SIZEOF (bool));
#endif // _RWSTD_NO_BOOL
printf ("#define _RWSTD_CHAR_SIZE %2u /* sizeof (char) */\n",
SIZEOF (char));
printf ("#define _RWSTD_SHRT_SIZE %2u /* sizeof (short) */\n",
SIZEOF (short));
printf ("#define _RWSTD_INT_SIZE %2u /* sizeof (int) */\n",
SIZEOF (int));
printf ("#define _RWSTD_LONG_SIZE %2u /* sizeof (long) */\n",
SIZEOF (long));
printf ("#define _RWSTD_FLT_SIZE %2u /* sizeof (float) */\n",
SIZEOF (float));
printf ("#define _RWSTD_DBL_SIZE %2u /* sizeof (double) */\n",
SIZEOF (double));
#ifndef _RWSTD_NO_LONG_DOUBLE
printf ("#define _RWSTD_LDBL_SIZE %2u /* sizeof (long double) */\n",
SIZEOF (long double));
#endif // _RWSTD_NO_LONG_DOUBLE
// compute the sizes of data and function pointers
printf ("#define _RWSTD_PTR_SIZE %2u /* sizeof (void*) */\n",
SIZEOF (void*));
typedef void (*fun_ptr_t)();
printf ("#define _RWSTD_FUNPTR_SIZE %2u /* sizeof (void(*)()) */\n",
SIZEOF (fun_ptr_t));
typedef void (EmptyStruct::*memfun_ptr_t)();
printf ("#define _RWSTD_MEMPTR_SIZE %2u "
"/* sizeof (void (struct::*)()) */\n",
SIZEOF (memfun_ptr_t));
// compute integral limits
const unsigned char_bits = compute_char_bits ();
#ifndef _RWSTD_NO_BOOL
printf ("#define _RWSTD_BOOL_MIN !!0\n");
printf ("#define _RWSTD_BOOL_MAX !0\n");
#endif // _RWSTD_NO_BOOL
if (0 == no_twos_complement) {
// comment out the next #define (this is two's complement
// architecture)
printf ("%s", "// ");
}
printf ("#define _RWSTD_NO_TWOS_COMPLEMENT\n");
#define MKLIMITS(T, pfx, sfx, type) \
do { \
T buf = 0; \
compute_limits (&buf, pfx, sfx, type); \
} while (0)
MKLIMITS (char, "CHAR", "", "char");
MKLIMITS (signed char, "SCHAR", "", "signed char");
MKLIMITS (unsigned char, "UCHAR", "U", "unsigned char");
MKLIMITS (short, "SHRT", "", "short");
MKLIMITS (unsigned short, "USHRT", "U", "unsigned short");
MKLIMITS (int, "INT", "", "int");
MKLIMITS (unsigned int, "UINT", "U", "unsigned int");
MKLIMITS (long, "LONG", "L", "long");
MKLIMITS (unsigned long, "ULONG", "UL", "unsigned long");
#ifndef _RWSTD_NO_LONG_LONG
# define LLong long long
printf ("#define _RWSTD_LLONG_SIZE %2u\n", SIZEOF (LLong));
const char llong_name[] = "long long";
MKLIMITS (LLong, "LLONG", "LL", "long long");
MKLIMITS (unsigned LLong, "ULLONG", "ULL", "unsigned long long");
#else // if defined (_RWSTD_NO_LONG_LONG)
# if defined (_MSC_VER)
# define LLong __int64
printf ("#define _RWSTD_LLONG_SIZE %2u\n", SIZEOF (LLong));
const char llong_name[] = "__int64";
MKLIMITS (LLong, "LLONG", "L", "__int64");
MKLIMITS (unsigned LLong, "ULLONG", "UL", "unsigned __int64");
# else
# define LLong long
const char llong_name[] = "long";
# endif // _MSC_VER
#endif // _RWSTD_NO_LONG_LONG
#ifndef _RWSTD_NO_WCHAR_T
printf ("#define _RWSTD_WCHAR_SIZE %2u /* sizeof (wchar_t) */\n",
SIZEOF (wchar_t));
const char *suffix = "U";
if ((wchar_t)~0 < (wchar_t)0)
suffix = "";
MKLIMITS (wchar_t, "WCHAR", suffix, "wchar_t");
#endif // _RWSTD_NO_WCHAR_T
#if defined (MB_LEN_MAX)
printf ("#define _RWSTD_MB_LEN_MAX %d /* libc value */\n",
MB_LEN_MAX);
#else // if !defined (MB_LEN_MAX)
# if defined (_AIX)
printf ("#define _RWSTD_MB_LEN_MAX %d /* known AIX libc value */\n", 4);
# elif defined (__hpux)
printf ("#define _RWSTD_MB_LEN_MAX %d /* known HP-UX libc value */\n", 4);
# elif defined (__sgi) || defined (sgi)
printf ("#define _RWSTD_MB_LEN_MAX %d /* known IRIX libc value */\n", 5);
# elif defined (__GLIBC__) && __GLIBC_MINOR__ <= 1
printf ("#define _RWSTD_MB_LEN_MAX %d /* known glibc 2.1 value */\n", 6);
# elif defined (__GLIBC__) && __GLIBC_MINOR__ >= 2
printf ("#define _RWSTD_MB_LEN_MAX %d /* known glibc 2.2 value */\n", 16);
# elif defined (__sun__) || defined (__sun) || defined (__sun)
printf ("#define _RWSTD_MB_LEN_MAX %d /* known SunOS libc value */\n", 5);
# elif defined (_WIN32)
printf ("#define _RWSTD_MB_LEN_MAX %d /* known WIN32 libc value */\n", 5);
# else
printf ("#define _RWSTD_MB_LEN_MAX %d /* guess */\n", 8);
# endif
#endif // MB_LEN_MAX
//////////////////////////////////////////////////////////////////
// #define macros for exact and lest-width integer types
// width_bits will have the corresponding bit set for each exact-width
// type already processed (i.e., bit 0 for an 8-bit integer type, bit
// 1 for a 16-bit integer, etc)
int width_bits = 0;
#define PRINT_SPECIFIC(width, least, type) \
do { \
/* avoid warnings about expression being constant */ \
const char* least_str = least; \
if (least_str && *least_str) \
printf ("#define _RWSTD_INT_LEAST%d_T %s _RWSTD_%s_T\n" \
"#define _RWSTD_UINT_LEAST%d_T %s _RWSTD_U%s_T\n", \
width, width < 10 ? " " : "", type, \
width, width < 10 ? " " : "", type); \
else \
printf ("#define _RWSTD_INT%d_T %s signed %s\n" \
"#define _RWSTD_UINT%d_T %s unsigned %s\n", \
width, width < 10 ? " " : "", type, \
width, width < 10 ? " " : "", type); \
} while (0)
if (8 == char_bits) {
width_bits |= 1;
PRINT_SPECIFIC (8, "", "char");
}
else if (16 == char_bits) {
width_bits |= 2;
PRINT_SPECIFIC (16, "", "char");
}
else if (32 == char_bits) {
width_bits |= 4;
PRINT_SPECIFIC (32, "", "char");
}
else if (64 == char_bits) {
width_bits |= 8;
PRINT_SPECIFIC (64, "", "char");
}
if (16 == char_bits * sizeof (short) && !(width_bits & 2)) {
width_bits |= 2;
PRINT_SPECIFIC (16, "", "short");
}
else if (32 == char_bits * sizeof (short) && !(width_bits & 4)) {
width_bits |= 4;
PRINT_SPECIFIC (32, "", "short");
}
else if (64 == char_bits * sizeof (short) && !(width_bits & 8)) {
width_bits |= 8;
PRINT_SPECIFIC (64, "", "short");
}
else if (128 == char_bits * sizeof (short) && !(width_bits & 16)) {
width_bits |= 16;
PRINT_SPECIFIC (128, "", "short");
}
if (32 == char_bits * sizeof (int) && !(width_bits & 4)) {
width_bits |= 4;
PRINT_SPECIFIC (32, "", "int");
}
else if (64 == char_bits * sizeof (int) && !(width_bits & 8)) {
width_bits |= 8;
PRINT_SPECIFIC (64, "", "int");
}
else if (128 == char_bits * sizeof (int) && !(width_bits & 16)) {
width_bits |= 16;
PRINT_SPECIFIC (128, "", "int");
}
if (32 == char_bits * sizeof (long) && !(width_bits & 4)) {
width_bits |= 4;
PRINT_SPECIFIC (32, "", "long");
}
else if (64 == char_bits * sizeof (long) && !(width_bits & 8)) {
width_bits |= 8;
PRINT_SPECIFIC (64, "", "long");
}
else if (128 == char_bits * sizeof (long) && !(width_bits & 16)) {
width_bits |= 16;
PRINT_SPECIFIC (128, "", "long");
}
if (32 == char_bits * sizeof (LLong) && !(width_bits & 4)) {
width_bits |= 4;
PRINT_SPECIFIC (32, "", llong_name);
}
else if (64 == char_bits * sizeof (LLong) && !(width_bits & 8)) {
width_bits |= 8;
PRINT_SPECIFIC (64, "", llong_name);
}
else if (128 == char_bits * sizeof (LLong) && !(width_bits & 16)) {
width_bits |= 16;
PRINT_SPECIFIC (128, "", llong_name);
}
//////////////////////////////////////////////////////////////////
// print the names of the width-specific least integer types
// i.e., INT_LEAST8_T, INT_LEAST16_T, INT_LEAST32_T, ...
if (width_bits & (1 << 0))
PRINT_SPECIFIC (8, "_LEAST", "INT8");
else if (width_bits & (1 << 1))
PRINT_SPECIFIC (8, "_LEAST", "INT16");
else if (width_bits & (1 << 2))
PRINT_SPECIFIC (8, "_LEAST", "INT32");
else if (width_bits & (1 << 3))
PRINT_SPECIFIC (8, "_LEAST", "INT64");
else if (width_bits & (1 << 4))
PRINT_SPECIFIC (8, "_LEAST", "INT128");
if (width_bits & (1 << 1))
PRINT_SPECIFIC (16, "_LEAST", "INT16");
else if (width_bits & (1 << 2))
PRINT_SPECIFIC (16, "_LEAST", "INT32");
else if (width_bits & (1 << 3))
PRINT_SPECIFIC (16, "_LEAST", "INT64");
else if (width_bits & (1 << 4))
PRINT_SPECIFIC (16, "_LEAST", "INT128");
if (width_bits & (1 << 2))
PRINT_SPECIFIC (32, "_LEAST", "INT32");
else if (width_bits & (1 << 3))
PRINT_SPECIFIC (32, "_LEAST", "INT64");
else if (width_bits & (1 << 4))
PRINT_SPECIFIC (32, "_LEAST", "INT128");
if (width_bits & (1 << 3))
PRINT_SPECIFIC (64, "_LEAST", "INT64");
else if (width_bits & (1 << 4))
PRINT_SPECIFIC (64, "_LEAST", "INT128");
if (width_bits & (1 << 4))
PRINT_SPECIFIC (128, "_LEAST", "INT128");
return 0;
}