aboutsummaryrefslogtreecommitdiff
path: root/libstdc++-v3/src/gen-num-limits.cc
diff options
context:
space:
mode:
Diffstat (limited to 'libstdc++-v3/src/gen-num-limits.cc')
-rw-r--r--libstdc++-v3/src/gen-num-limits.cc707
1 files changed, 707 insertions, 0 deletions
diff --git a/libstdc++-v3/src/gen-num-limits.cc b/libstdc++-v3/src/gen-num-limits.cc
new file mode 100644
index 0000000..8dd3a16
--- /dev/null
+++ b/libstdc++-v3/src/gen-num-limits.cc
@@ -0,0 +1,707 @@
+// Copyright (C) 1999, 2000 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 <gdr@egcs.cygnus.com>
+//
+// 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 <bits/c++config.h>
+
+//
+// Force Linux <limits.h> 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 <limits.h>
+#include <float.h>
+#include <stdio.h>
+#include <signal.h>
+#include <setjmp.h>
+#include <math.h>
+#ifdef _GLIBCPP_USE_WCHAR_T
+#include <wchar.h>
+#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.
+
+jmp_buf env;
+
+void signal_handler(int sig)
+{
+#ifdef __CYGWIN__
+ static sigset_t x;
+ signal (sig, signal_handler);
+ sigemptyset (&x);
+ sigprocmask(SIG_SETMASK, &x, NULL);
+#endif /* __CYGWIN__ */
+ longjmp(env, sig);
+}
+
+template<typename Operation>
+bool trapping(const Operation& op)
+{
+ if (setjmp(env) == 0) op();
+ else return true;
+ return false;
+}
+
+template<typename T> struct division_by_zero {
+ void operator() () const
+ {
+ volatile T zero = T();
+ volatile T one = T(1);
+ volatile T infinity = one / zero;
+ }
+};
+
+template<typename T> struct overflow {
+ void operator() () const
+ {
+ T i = T(1);
+ T j = T();
+ while (i>j) {
+ j = i;
+ i = i * 2 + 1;
+ }
+ }
+};
+
+template<typename T> struct underflow {};
+
+// traps
+template<typename T> void traps()
+{
+ signal(SIGFPE, signal_handler);
+ bool trap_flag = trapping(division_by_zero<T>());
+ signal(SIGFPE, signal_handler);
+ trap_flag = trap_flag && trapping(overflow<T>());
+ 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(SIGFPE, signal_handler); \
+ const char* p = bool_alpha[trapping(division_by_zero<T>())]; \
+ 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<typename T> 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<typename T> struct declarator : type_name_trait<T> {
+ typedef type_name_trait<T> 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<typename T> 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<typename T>
+const bool predicate<T>::is_signed = T(-1) < 0;
+
+// Non integer types should specialize this
+template<typename T>
+const bool predicate<T>::is_integer = true;
+
+// Non exact types should specialize this;
+template<typename T>
+const bool predicate<T>::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<typename T>
+const bool predicate<T>::has_infinity = false;
+
+template<typename T>
+const bool predicate<T>::has_quiet_nan = false;
+
+template<typename T>
+const bool predicate<T>::has_signaling_nan = false;
+
+template<typename T>
+const bool predicate<T>::has_denorm = false;
+
+template<typename T>
+const bool predicate<T>::has_denorm_loss = false;
+
+
+
+// Each type conforming to IEC559 specifications should specialize this.
+template<typename T>
+const bool predicate<T>::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<typename T> 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<typename T>
+const int value<T>::digits =
+ bits_per_byte * sizeof(T) - int(predicate<T>::is_signed);
+
+// Non integer types should specialize this. Alwyas two for
+// integer types.
+template<typename T>
+const int value<T>::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
+
+
+template<typename T>
+const char value<T>::epsilon[] = "0";
+
+template<typename T>
+const char value<T>::round_error[] = "0";
+
+#define SPECIALIZE_EPSILON(T, E) DO_SPECIALIZE_EPSILON(T, E)
+#define DO_SPECIALIZE_EPSILON(T, E) const char value< T >::epsilon[] = #E
+
+SPECIALIZE_EPSILON(float, FLT_EPSILON);
+SPECIALIZE_EPSILON(double, DBL_EPSILON);
+SPECIALIZE_EPSILON(long double, LDBL_EPSILON);
+
+#undef DO_SPECIALIZE_EPSILON
+#undef SPECIALIZE_EPSILON
+
+
+#define SPECIALIZE_ROUND_ERROR(T, R) const char value< T >::round_error[] = #R
+
+SPECIALIZE_ROUND_ERROR(float, 1.0f);
+SPECIALIZE_ROUND_ERROR(double, 1.0);
+SPECIALIZE_ROUND_ERROR(long double, 1.0L);
+
+#undef SPECIALIZE_ROUND_ERROR
+
+
+template<typename T>
+const int value<T>::min_exponent = 0;
+
+template<typename T>
+const int value<T>::min_exponent10 = 0;
+
+template<typename T>
+const int value<T>::max_exponent = 0;
+
+template<typename T>
+const int value<T>::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<typename T> void is_signed()
+{
+ printf("%s%s = %s;\n", tab2, "static const bool is_signed",
+ bool_alpha[predicate<T>::is_signed]);
+}
+
+// a fundamental type is modulo iff it isn't signed
+template<typename T> void is_modulo()
+{
+ printf("%s%s = %s;\n", tab2, "static const bool is_modulo",
+ bool_alpha[! predicate<T>::is_signed]);
+}
+
+template<typename T>
+void min()
+{
+ printf("%s%s%s%s\n%s%s%s%s\n", tab2, "static ", declarator<T>::type_name,
+ " min() throw()", tab2, "{ return ", value<T>::min, "; }");
+}
+
+template<typename T>
+void max()
+{
+ printf("%s%s%s%s\n%s%s%s%s\n", tab2, "static ", declarator<T>::type_name,
+ " max() throw()", tab2, "{ return ", value<T>::max, "; }");
+}
+
+template<typename T>
+void is_integer()
+{
+ printf("%s%s = %s;\n", tab2, "static const bool is_integer",
+ bool_alpha[predicate<T>::is_integer]);
+}
+
+template<typename T>
+void is_exact()
+{
+ printf("%s%s = %s;\n", tab2, "static const bool is_exact",
+ bool_alpha[predicate<T>::is_exact]);
+}
+
+template<typename T>
+void digits()
+{
+ printf("%s%s = %d;\n", tab2, "static const int digits",
+ value<T>::digits);
+}
+
+template<typename T>
+void digits10()
+{
+ printf("%s%s = %d;\n", tab2, "static const int digits10",
+ int(log10_of_two * value<T>::digits));
+}
+
+template<typename T>
+void radix()
+{
+ printf("%s%s = %d;\n", tab2, "static const int radix",
+ value<T>::radix);
+}
+
+template<typename T>
+void epsilon()
+{
+ printf("%s%s %s %s\n%s%s %s%s\n", tab2, "static",
+ declarator<T>::type_name, "epsilon() throw()",
+ tab2, "{ return", value<T>::epsilon, "; }");
+}
+
+template<typename T>
+void round_error()
+{
+ printf("%s%s %s %s\n%s%s %s%s\n", tab2, "static",
+ declarator<T>::type_name, "round_error() throw()",
+ tab2, "{ return", value<T>::round_error, "; }");
+}
+
+template<typename T>
+void min_exponent()
+{
+ printf("%s%s = %d;\n", tab2, "static const int min_exponent",
+ value<T>::min_exponent);
+}
+
+template<typename T>
+void min_exponent10()
+{
+ printf("%s%s = %d;\n", tab2, "static const int min_exponent10",
+ value<T>::min_exponent10);
+}
+
+template<typename T>
+void max_exponent()
+{
+ printf("%s%s = %d;\n", tab2, "static const int max_exponent",
+ value<T>::max_exponent);
+}
+
+template<typename T>
+void max_exponent10()
+{
+ printf("%s%s = %d;\n", tab2, "static const int max_exponent10",
+ value<T>::max_exponent10);
+}
+
+template<typename T>
+void has_infinity()
+{
+ printf("%s%s = %s;\n", tab2, "static const bool has_infinity",
+ bool_alpha[predicate<T>::has_infinity]);
+}
+
+template<typename T>
+void has_quiet_nan()
+{
+ printf("%s%s = %s;\n", tab2, "static const bool has_quiet_NaN",
+ bool_alpha[predicate<T>::has_quiet_nan]);
+}
+
+template<typename T>
+void has_signaling_nan()
+{
+ printf("%s%s = %s;\n", tab2, "static const bool has_signaling_NaN",
+ bool_alpha[predicate<T>::has_signaling_nan]);
+}
+
+template<typename T>
+void has_denorm_loss()
+{
+ printf("%s%s = %s;\n", tab2, "static const bool has_denorm_loss",
+ bool_alpha[predicate<T>::has_denorm_loss]);
+}
+
+template<typename T> 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<T>::type_name, "infinity() throw()",
+ tab2, "{ return static_cast<", declarator<T>::type_name,
+ ">(0); }");
+ }
+
+ static void quiet_NaN()
+ {
+ printf("%s%s %s %s\n%s%s%s%s\n", tab2, "static",
+ declarator<T>::type_name, "quiet_NaN() throw()",
+ tab2, "{ return static_cast<", declarator<T>::type_name,
+ ">(0); }");
+ }
+
+ static void signaling_NaN()
+ {
+ printf("%s%s %s %s\n%s%s%s%s\n", tab2, "static",
+ declarator<T>::type_name, "signaling_NaN() throw()",
+ tab2, "{ return static_cast<", declarator<T>::type_name,
+ ">(0); }");
+ }
+
+ static void denorm_min()
+ {
+ printf("%s%s %s %s\n%s%s%s%s\n", tab2, "static",
+ declarator<T>::type_name, "denorm_min() throw()",
+ tab2, "{ return static_cast<", declarator<T>::type_name,
+ ">(0); }");
+ }
+};
+
+
+template<typename T>
+void is_iec559()
+{
+ printf("%s%s = %s;\n", tab2, "static const bool is_iec559",
+ bool_alpha[predicate<T>::is_iec559]);
+}
+
+// tinyness_before
+template<typename T>
+void tinyness_before()
+{
+ printf("%s%s;\n", tab2, "static const bool tinyness_before = false");
+}
+
+// round style
+template<typename T>
+void round_style()
+{
+ printf("%s%s;\n", tab2, "static const float_round_style "
+ "round_style = round_toward_zero");
+}
+
+
+
+// type traits
+template<typename T> struct type_trait {
+
+ type_trait()
+ {
+ declarator<T>::start();
+ printf("%s%s;\n\n", tab2, "static const bool is_specialized = true");
+ min<T>();
+ max<T>();
+ printf("\n");
+ digits<T>();
+ digits10<T>();
+ is_signed<T>();
+ is_integer<T>();
+ is_exact<T>();
+ radix<T>();
+ epsilon<T>();
+ round_error<T>();
+ printf("\n");
+ min_exponent<T>();
+ min_exponent10<T>();
+ max_exponent<T>();
+ max_exponent10<T>();
+ printf("\n");
+ has_infinity<T>();
+ has_quiet_nan<T>();
+ has_signaling_nan<T>();
+ infinity_trait<T>::has_denorm();
+ has_denorm_loss<T>();
+ printf("\n");
+ infinity_trait<T>::infinity();
+ infinity_trait<T>::quiet_NaN();
+ infinity_trait<T>::signaling_NaN();
+ infinity_trait<T>::denorm_min();
+ printf("\n");
+ is_iec559<T>();
+ printf("%s%s;\n", tab2, "static const bool is_bounded = true");
+ is_modulo<T>();
+ printf("\n");
+ traps<T>();
+ tinyness_before<T>();
+ round_style<T>();
+ declarator<T>::end();
+ }
+};
+
+int main()
+{
+ type_trait<bool>();
+
+ type_trait<char>();
+ type_trait<signed char>();
+ type_trait<unsigned char>();
+#if defined( _GLIBCPP_USE_WCHAR_T) && defined(_GLIBCPP_HAS_WCHAR_MIN_MAX)
+ type_trait<wchar_t>();
+#endif
+
+ type_trait<short>();
+ type_trait<unsigned short>();
+
+ type_trait<int>();
+ type_trait<unsigned int>();
+
+ type_trait<long>();
+ type_trait<unsigned long>();
+
+#ifdef _GLIBCPP_USE_LONG_LONG
+ type_trait<long long>();
+ type_trait<unsigned long long>();
+#endif
+
+ type_trait<float>();
+ type_trait<double>();
+ type_trait<long double>();
+
+ // 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); }
+}
+