// Copyright (C) 1999, 2000, 2001 Free Software Foundation, Inc. // // This file is part of the GNU ISO C++ Library. This library is free // software; you can redistribute it and/or modify it under the // terms of the GNU General Public License as published by the // Free Software Foundation; either version 2, or (at your option) // any later version. // This library is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // You should have received a copy of the GNU General Public License along // with this library; see the file COPYING. If not, write to the Free // Software Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, // USA. // As a special exception, you may use this file as part of a free software // library without restriction. Specifically, if other files instantiate // templates or use macros or inline functions from this file, or you compile // this file and link it with other files to produce an executable, this // file does not by itself cause the resulting executable to be covered by // the GNU General Public License. This exception does not however // invalidate any other reasons why the executable file might be covered by // the GNU General Public License. // // Written by Gabriel Dos Reis // // Note: This program outputs speciliazations of ISO C++ class template // numeric_limits<> as described in 18.2.1. // Do not compile with optimization turned on. // #include #if HAVE_CONFIG_H # include #endif // // Force Linux to define the *LONG_LONG* // #if __linux__ && _GLIBCPP_USE_LONG_LONG # ifndef __USE_GNU # define __USE_GNU 1 # endif # ifndef _GNU_SOURCE # define _GNU_SOURCE 1 # endif #endif #include #include #include #include #include #include #ifdef _GLIBCPP_USE_WCHAR_T #include #endif // mknumeric_limits will first try to compile this file with // HAVE_SIGSETJMP. If it fails, then it will try without it. Some // systems, such as GNU/Linux/sparc, would remain with the signal // blocked if the signal handler uses longjmp instead of siglongjmp. // We assume here setjmp/longjmp will preserve the sigblock mask if // sigsetjmp is not present. #if ! HAVE_SIGSETJMP # define sigjmp_buf jmp_buf # define sigsetjmp(buf, save) setjmp (buf) # define siglongjmp(env, ret) longjmp (env, ret) #endif const char tab[] = " "; const char tab2[] = " "; const char* bool_alpha[] = { "false", "true" }; const double log10_of_two = .30102999566398119; const int bits_per_byte = CHAR_BIT; const int integer_base_rep = 2; // // numeric_limits members are all static (as it is usually the case for // traits) and of three kinds: predicates, values and functions. // Actually there is no harm to think of values and functions as being // of the same kind. Their main purposes are to denote values. // // // Integer types: bool, char, signed char, unsigned char, wchar_t, // short, unsigned short, int, unsigned, long, unsigned long, // and possibly long long and unsigned long long // // Here ISO 14882 disagrees with LIA-1 in stating bool to be an // integer type. Therefore itn't suprising to see ambiguity in the // interpretation of some members. Need to keep track of the discusion // in LWG on this topic. // // Integer types are first promoted to int or long before the actual // arithmetical operations are carried out. Therefore testing whether // traps occur amounts -- for integer types -- to test whether traps // occur for int, unsigned, long, unsigned long. Furthermore // overflow cannot happen for unsigned integer types. sigjmp_buf env; /* The prototype of signal() may vary. Accomodate variations such as void(*)(int) and void(*)(...). */ template inline void (*signal_adapter (signal_handler_type (*signal_func)(signal_number_type, signal_handler_type), signal_number_type arg, void (*handler)(int)))(int) { return (void (*)(int))(*signal_func)(arg, (signal_handler_type)handler); } void signal_handler(int sig) { #ifdef __CYGWIN__ static sigset_t x; signal_adapter (signal, sig, signal_handler); sigemptyset (&x); sigprocmask(SIG_SETMASK, &x, NULL); #endif /* __CYGWIN__ */ siglongjmp(env, sig); } template bool trapping(const Operation& op) { if (sigsetjmp(env, 1) == 0) op(); else return true; return false; } template struct division_by_zero { void operator() () const { volatile T zero = T(); volatile T one = T(1); volatile T infinity = one / zero; } }; template struct overflow { void operator() () const { T i = T(1); T j = T(); while (i>j) { j = i; i = i * 2 + 1; } } }; template struct underflow {}; // traps template void traps() { signal_adapter (signal, SIGFPE, signal_handler); signal_adapter (signal, SIGTRAP, signal_handler); bool trap_flag = trapping(division_by_zero()); signal_adapter (signal, SIGFPE, signal_handler); signal_adapter (signal, SIGTRAP, signal_handler); trap_flag = trap_flag || trapping(overflow()); const char* p = bool_alpha[trap_flag]; printf("%s%s = %s;\n", tab2, "static const bool traps", p); } #define SPECIALIZE_TRAPPING(T) \ template<> void traps< T >() \ { \ signal_adapter (signal, SIGFPE, signal_handler); \ signal_adapter (signal, SIGTRAP, signal_handler); \ const char* p = bool_alpha[trapping(division_by_zero())]; \ printf("%s%s = %s;\n", tab2, "static const bool traps", p); \ } SPECIALIZE_TRAPPING(unsigned char); SPECIALIZE_TRAPPING(unsigned short); SPECIALIZE_TRAPPING(unsigned int); SPECIALIZE_TRAPPING(unsigned long); #if _GLIBCPP_USE_LONG_LONG SPECIALIZE_TRAPPING(unsigned long long); #endif #undef SPECIALIZE_TRAPPING template struct type_name_trait { static const char type_name[]; static const char trait_name[]; }; #define DEFINED_TYPE_NAME(T) \ const char type_name_trait< T >::type_name[] = #T; \ const char type_name_trait< T >::trait_name[] = "numeric_limits<" #T ">"; DEFINED_TYPE_NAME(bool); DEFINED_TYPE_NAME(char); DEFINED_TYPE_NAME(signed char); DEFINED_TYPE_NAME(unsigned char); DEFINED_TYPE_NAME(wchar_t); DEFINED_TYPE_NAME(short); DEFINED_TYPE_NAME(unsigned short); DEFINED_TYPE_NAME(int); DEFINED_TYPE_NAME(unsigned int); DEFINED_TYPE_NAME(long); DEFINED_TYPE_NAME(unsigned long); #ifdef _GLIBCPP_USE_LONG_LONG DEFINED_TYPE_NAME(long long); DEFINED_TYPE_NAME(unsigned long long); #endif DEFINED_TYPE_NAME(float); DEFINED_TYPE_NAME(double); DEFINED_TYPE_NAME(long double); #undef DEFINED_TYPE_NAME // declarator template struct declarator : type_name_trait { typedef type_name_trait base; static void start() { printf("%s%s %s %s\n", tab, "template<> struct", base::trait_name, "{"); } static void end() { printf("%s};\n\n", tab); } }; // // Predicates // template struct predicate { static const bool is_signed; static const bool is_integer; static const bool is_exact; static const bool has_infinity; static const bool has_quiet_nan; static const bool has_signaling_nan; static const bool has_denorm; static const bool has_denorm_loss; static const bool is_iec559; static const bool is_bounded; static const bool traps; }; template const bool predicate::is_signed = T(-1) < 0; // Non integer types should specialize this template const bool predicate::is_integer = true; // Non exact types should specialize this; template const bool predicate::is_exact = true; #define SPECIALIZE_EXACTNESS(T) \ const bool predicate< T >::is_integer = false; \ const bool predicate< T >::is_exact = false SPECIALIZE_EXACTNESS(float); SPECIALIZE_EXACTNESS(double); SPECIALIZE_EXACTNESS(long double); #undef SPECIALIZE_EXACTNESS template const bool predicate::has_infinity = false; template const bool predicate::has_quiet_nan = false; template const bool predicate::has_signaling_nan = false; template const bool predicate::has_denorm = false; template const bool predicate::has_denorm_loss = false; // Each type conforming to IEC559 specifications should specialize this. template const bool predicate::is_iec559 = false; #define SPECIALIZE_IEC559(T) \ const bool predicate< T >::is_iec559 = true SPECIALIZE_IEC559(bool); SPECIALIZE_IEC559(int); SPECIALIZE_IEC559(unsigned int); SPECIALIZE_IEC559(long); SPECIALIZE_IEC559(unsigned long); #ifdef _GLIBCPP_USE_LONG_LONG SPECIALIZE_IEC559(long long); SPECIALIZE_IEC559(unsigned long long); #endif #undef SPECIALIZE_IEC559 // // Values // template struct value { static const char min[]; static const char max[]; static const int digits; static const int digits10; static const int radix; static const char epsilon[]; static const char round_error[]; static const int min_exponent; static const int min_exponent10; static const int max_exponent; static const int max_exponent10; }; #define DEFINE_EXTREMA(T, m, M) DO_DEFINE_EXTREMA(T, m, M) #define DO_DEFINE_EXTREMA(T, m, M) \ const char value< T >::min[] = #m; \ const char value< T >::max[] = #M DEFINE_EXTREMA(bool, false, true); DEFINE_EXTREMA(char, CHAR_MIN, CHAR_MAX); DEFINE_EXTREMA(signed char, SCHAR_MIN, SCHAR_MAX); DEFINE_EXTREMA(unsigned char, 0, UCHAR_MAX); #ifdef _GLIBCPP_USE_WCHAR_T DEFINE_EXTREMA(wchar_t, WCHAR_MIN, WCHAR_MAX); #endif DEFINE_EXTREMA(short, SHRT_MIN, SHRT_MAX); DEFINE_EXTREMA(unsigned short, 0, USHRT_MAX); DEFINE_EXTREMA(int, INT_MIN, INT_MAX); DEFINE_EXTREMA(unsigned int, 0, UINT_MAX); DEFINE_EXTREMA(long, LONG_MIN, LONG_MAX); DEFINE_EXTREMA(unsigned long, 0, ULONG_MAX); #ifdef _GLIBCPP_USE_LONG_LONG DEFINE_EXTREMA(long long, LONG_LONG_MIN, LONG_LONG_MAX); DEFINE_EXTREMA(unsigned long long, 0, ULONG_LONG_MAX); #endif DEFINE_EXTREMA(float, FLT_MIN, FLT_MAX); DEFINE_EXTREMA(double, DBL_MIN, DBL_MAX); DEFINE_EXTREMA(long double, LDBL_MIN, LDBL_MAX); #undef DEFINE_EXTREMA #undef DO_DEFINE_EXTREMA // Non integer types should specialize this template const int value::digits = bits_per_byte * sizeof(T) - int(predicate::is_signed); // Non integer types should specialize this. Always two for // integer types. template const int value::radix = 2; #define SPECIALIZE_DIGITS(T, D, D10) \ const int value< T >::digits = D; \ const int value< T >::digits10 = D10 SPECIALIZE_DIGITS(float, FLT_MANT_DIG, FLT_DIG); SPECIALIZE_DIGITS(double, DBL_MANT_DIG, DBL_DIG); SPECIALIZE_DIGITS(long double, LDBL_MANT_DIG, LDBL_DIG); #undef SPECIALIZE_DIGITS #define SPECIALIZE_RADIX(T, R) const int value< T >::radix = R SPECIALIZE_RADIX(float, FLT_RADIX); SPECIALIZE_RADIX(double, FLT_RADIX); SPECIALIZE_RADIX(long double, FLT_RADIX); #undef SPECIALIZE_RADIX // Non integer types should specialize this. // Unfortunately, systems that don't deal with weak linking correctly // (Ie, hpux and aix), cannot use this sophisticated yet sane method. So, // explicitly instantiate all the data members here so that they will // be happy. // sophisticated, sane method #if 0 template const char value::epsilon[] = "0"; #endif #define SPECIALIZE_EPSILON(T, E) DO_SPECIALIZE_EPSILON(T, E) #define DO_SPECIALIZE_EPSILON(T, E) const char value< T >::epsilon[] = #E // unsophisticated, gross method #if 1 SPECIALIZE_EPSILON(bool, 0); SPECIALIZE_EPSILON(char, 0); SPECIALIZE_EPSILON(unsigned char, 0); SPECIALIZE_EPSILON(signed char, 0); SPECIALIZE_EPSILON(wchar_t, 0); SPECIALIZE_EPSILON(short, 0); SPECIALIZE_EPSILON(unsigned short, 0); SPECIALIZE_EPSILON(int, 0); SPECIALIZE_EPSILON(unsigned int, 0); SPECIALIZE_EPSILON(long, 0); SPECIALIZE_EPSILON(unsigned long, 0); SPECIALIZE_EPSILON(long long, 0); SPECIALIZE_EPSILON(unsigned long long, 0); #endif SPECIALIZE_EPSILON(float, FLT_EPSILON); SPECIALIZE_EPSILON(double, DBL_EPSILON); SPECIALIZE_EPSILON(long double, LDBL_EPSILON); #undef DO_SPECIALIZE_EPSILON #undef SPECIALIZE_EPSILON // Non integer types should specialize this. // Unfortunately, systems that don't deal with weak linking correctly // (Ie, hpux and aix), cannot use this sophisticated yet sane method. So, // explicitly instantiate all the data members here so that they will // be happy. // sophisticated, sane method #if 0 template const char value::round_error[] = "0"; #endif #define SPECIALIZE_ROUND_ERROR(T, R) const char value< T >::round_error[] = #R // unsophisticated, gross method #if 1 SPECIALIZE_ROUND_ERROR(bool, 0); SPECIALIZE_ROUND_ERROR(char, 0); SPECIALIZE_ROUND_ERROR(unsigned char, 0); SPECIALIZE_ROUND_ERROR(signed char, 0); SPECIALIZE_ROUND_ERROR(wchar_t, 0); SPECIALIZE_ROUND_ERROR(short, 0); SPECIALIZE_ROUND_ERROR(unsigned short, 0); SPECIALIZE_ROUND_ERROR(int, 0); SPECIALIZE_ROUND_ERROR(unsigned int, 0); SPECIALIZE_ROUND_ERROR(long, 0); SPECIALIZE_ROUND_ERROR(unsigned long, 0); SPECIALIZE_ROUND_ERROR(long long, 0); SPECIALIZE_ROUND_ERROR(unsigned long long, 0); #endif SPECIALIZE_ROUND_ERROR(float, 1.0f); SPECIALIZE_ROUND_ERROR(double, 1.0); SPECIALIZE_ROUND_ERROR(long double, 1.0L); #undef SPECIALIZE_ROUND_ERROR template const int value::min_exponent = 0; template const int value::min_exponent10 = 0; template const int value::max_exponent = 0; template const int value::max_exponent10 = 0; #define SPECIALIZE_EXPONENTS(T, m, m10, M, M10) \ const int value< T >::min_exponent = m; \ const int value< T >::min_exponent10 = m10; \ const int value< T >::max_exponent = M; \ const int value< T >::max_exponent10 = M10 SPECIALIZE_EXPONENTS(float, FLT_MIN_EXP, FLT_MIN_10_EXP, FLT_MAX_EXP, FLT_MAX_10_EXP); SPECIALIZE_EXPONENTS(double, DBL_MIN_EXP, DBL_MIN_10_EXP, DBL_MAX_EXP, DBL_MAX_10_EXP); SPECIALIZE_EXPONENTS(long double, LDBL_MIN_EXP, LDBL_MIN_10_EXP, LDBL_MAX_EXP, LDBL_MAX_10_EXP); #undef SPECIALIZE_EXPONENTS // // Functions to output predicates and values. // template void is_signed() { printf("%s%s = %s;\n", tab2, "static const bool is_signed", bool_alpha[predicate::is_signed]); } // a fundamental type is modulo iff it isn't signed template void is_modulo() { printf("%s%s = %s;\n", tab2, "static const bool is_modulo", bool_alpha[! predicate::is_signed]); } template void min() { printf("%s%s%s%s\n%s%s%s%s\n", tab2, "static ", declarator::type_name, " min() throw()", tab2, "{ return ", value::min, "; }"); } template void max() { printf("%s%s%s%s\n%s%s%s%s\n", tab2, "static ", declarator::type_name, " max() throw()", tab2, "{ return ", value::max, "; }"); } template void is_integer() { printf("%s%s = %s;\n", tab2, "static const bool is_integer", bool_alpha[predicate::is_integer]); } template void is_exact() { printf("%s%s = %s;\n", tab2, "static const bool is_exact", bool_alpha[predicate::is_exact]); } template void digits() { printf("%s%s = %d;\n", tab2, "static const int digits", value::digits); } template void digits10() { printf("%s%s = %d;\n", tab2, "static const int digits10", int(log10_of_two * value::digits)); } template void radix() { printf("%s%s = %d;\n", tab2, "static const int radix", value::radix); } template void epsilon() { printf("%s%s %s %s\n%s%s %s%s\n", tab2, "static", declarator::type_name, "epsilon() throw()", tab2, "{ return", value::epsilon, "; }"); } template void round_error() { printf("%s%s %s %s\n%s%s %s%s\n", tab2, "static", declarator::type_name, "round_error() throw()", tab2, "{ return", value::round_error, "; }"); } template void min_exponent() { printf("%s%s = %d;\n", tab2, "static const int min_exponent", value::min_exponent); } template void min_exponent10() { printf("%s%s = %d;\n", tab2, "static const int min_exponent10", value::min_exponent10); } template void max_exponent() { printf("%s%s = %d;\n", tab2, "static const int max_exponent", value::max_exponent); } template void max_exponent10() { printf("%s%s = %d;\n", tab2, "static const int max_exponent10", value::max_exponent10); } template void has_infinity() { printf("%s%s = %s;\n", tab2, "static const bool has_infinity", bool_alpha[predicate::has_infinity]); } template void has_quiet_nan() { printf("%s%s = %s;\n", tab2, "static const bool has_quiet_NaN", bool_alpha[predicate::has_quiet_nan]); } template void has_signaling_nan() { printf("%s%s = %s;\n", tab2, "static const bool has_signaling_NaN", bool_alpha[predicate::has_signaling_nan]); } template void has_denorm_loss() { printf("%s%s = %s;\n", tab2, "static const bool has_denorm_loss", bool_alpha[predicate::has_denorm_loss]); } template struct infinity_trait { static void has_denorm() { printf("%s%s;\n", tab2, "static const float_denorm_style " "has_denorm = denorm_absent"); } static void infinity() { printf("%s%s %s %s\n%s%s%s%s\n", tab2, "static", declarator::type_name, "infinity() throw()", tab2, "{ return static_cast<", declarator::type_name, ">(0); }"); } static void quiet_NaN() { printf("%s%s %s %s\n%s%s%s%s\n", tab2, "static", declarator::type_name, "quiet_NaN() throw()", tab2, "{ return static_cast<", declarator::type_name, ">(0); }"); } static void signaling_NaN() { printf("%s%s %s %s\n%s%s%s%s\n", tab2, "static", declarator::type_name, "signaling_NaN() throw()", tab2, "{ return static_cast<", declarator::type_name, ">(0); }"); } static void denorm_min() { printf("%s%s %s %s\n%s%s%s%s\n", tab2, "static", declarator::type_name, "denorm_min() throw()", tab2, "{ return static_cast<", declarator::type_name, ">(0); }"); } }; template void is_iec559() { printf("%s%s = %s;\n", tab2, "static const bool is_iec559", bool_alpha[predicate::is_iec559]); } // tinyness_before template void tinyness_before() { printf("%s%s;\n", tab2, "static const bool tinyness_before = false"); } // round style template void round_style() { printf("%s%s;\n", tab2, "static const float_round_style " "round_style = round_toward_zero"); } // type traits template struct type_trait { type_trait() { declarator::start(); printf("%s%s;\n\n", tab2, "static const bool is_specialized = true"); min(); max(); printf("\n"); digits(); digits10(); is_signed(); is_integer(); is_exact(); radix(); epsilon(); round_error(); printf("\n"); min_exponent(); min_exponent10(); max_exponent(); max_exponent10(); printf("\n"); has_infinity(); has_quiet_nan(); has_signaling_nan(); infinity_trait::has_denorm(); has_denorm_loss(); printf("\n"); infinity_trait::infinity(); infinity_trait::quiet_NaN(); infinity_trait::signaling_NaN(); infinity_trait::denorm_min(); printf("\n"); is_iec559(); printf("%s%s;\n", tab2, "static const bool is_bounded = true"); is_modulo(); printf("\n"); traps(); tinyness_before(); round_style(); declarator::end(); } }; int main() { type_trait(); type_trait(); type_trait(); type_trait(); #if defined( _GLIBCPP_USE_WCHAR_T) type_trait(); #endif type_trait(); type_trait(); type_trait(); type_trait(); type_trait(); type_trait(); #ifdef _GLIBCPP_USE_LONG_LONG type_trait(); type_trait(); #endif type_trait(); type_trait(); type_trait(); // x86/linux gets this weirdness for the min/max functions: // static long double min() throw() // { return (__extension__ ((union __convert_long_double) // {__convert_long_double_i: {0x0, 0x80000000, 0x1, 0x0}}) // .__convert_long_double_d); } } // G++ doesn't have support for automatic instantiation of static data // members on platforms that don't have weak symbols. On AIX, in // particular, static data members must be explicitly instantiated. // So, we explicitly instantiate some of the ones we need. To save // typing, we don't name the static data members explicitly; we // instead name their containing types. #define INSTANTIATIONS(TYPE) \ template struct predicate; \ template struct value INSTANTIATIONS (bool); INSTANTIATIONS (char); INSTANTIATIONS (signed char); INSTANTIATIONS (unsigned char); INSTANTIATIONS (short); INSTANTIATIONS (unsigned short); INSTANTIATIONS (int); INSTANTIATIONS (unsigned int); INSTANTIATIONS (long); INSTANTIATIONS (unsigned long); INSTANTIATIONS (float); INSTANTIATIONS (double); INSTANTIATIONS (long double);