OSDN Git Service

2001-02-26 Phil Edwards <pme@sources.redhat.com>
[pf3gnuchains/gcc-fork.git] / libstdc++-v3 / src / gen-num-limits.cc
1 // Copyright (C) 1999, 2000, 2001 Free Software Foundation, Inc.
2 //
3 // This file is part of the GNU ISO C++ Library.  This library is free
4 // software; you can redistribute it and/or modify it under the
5 // terms of the GNU General Public License as published by the
6 // Free Software Foundation; either version 2, or (at your option)
7 // any later version.
8
9 // This library is distributed in the hope that it will be useful,
10 // but WITHOUT ANY WARRANTY; without even the implied warranty of
11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12 // GNU General Public License for more details.
13
14 // You should have received a copy of the GNU General Public License along
15 // with this library; see the file COPYING.  If not, write to the Free
16 // Software Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307,
17 // USA.
18
19 // As a special exception, you may use this file as part of a free software
20 // library without restriction.  Specifically, if other files instantiate
21 // templates or use macros or inline functions from this file, or you compile
22 // this file and link it with other files to produce an executable, this
23 // file does not by itself cause the resulting executable to be covered by
24 // the GNU General Public License.  This exception does not however
25 // invalidate any other reasons why the executable file might be covered by
26 // the GNU General Public License.
27
28 //
29 // Written by Gabriel Dos Reis <gdr@gcc.gnu.org>
30 // 
31 // Note: This program outputs speciliazations of ISO C++ class template
32 // numeric_limits<> as described in 18.2.1.
33 // Do not compile with optimization turned on.
34 //
35
36 #include <bits/c++config.h>
37
38 #if HAVE_CONFIG_H
39 # include <config.h>
40 #endif
41
42 //
43 // Force Linux <limits.h> to define the *LONG_LONG*
44 //
45 #if __linux__ && _GLIBCPP_USE_LONG_LONG
46 # ifndef __USE_GNU
47 #  define __USE_GNU 1
48 # endif
49 # ifndef _GNU_SOURCE
50 #  define _GNU_SOURCE 1
51 # endif
52 #endif
53
54 #include <limits.h>
55 #include <float.h>
56 #include <stdio.h>
57 #include <signal.h>
58 #include <setjmp.h>
59 #include <math.h>
60 #ifdef _GLIBCPP_USE_WCHAR_T
61 #include <wchar.h>
62 #endif
63
64 // mknumeric_limits will first try to compile this file with
65 // HAVE_SIGSETJMP.  If it fails, then it will try without it.  Some
66 // systems, such as GNU/Linux/sparc, would remain with the signal
67 // blocked if the signal handler uses longjmp instead of siglongjmp.
68 // We assume here setjmp/longjmp will preserve the sigblock mask if
69 // sigsetjmp is not present.
70
71 #if ! HAVE_SIGSETJMP 
72 # define sigjmp_buf jmp_buf 
73 # define sigsetjmp(buf, save) setjmp (buf) 
74 # define siglongjmp(env, ret) longjmp (env, ret) 
75 #endif 
76
77 const char tab[] = "    ";
78 const char tab2[] = "        ";
79 const char* bool_alpha[] = { "false", "true" };
80 const double log10_of_two = .30102999566398119;
81 const int bits_per_byte = CHAR_BIT;
82 const int integer_base_rep = 2;
83
84
85 //
86 // numeric_limits members are all static (as it is usually the case for
87 // traits) and of three kinds: predicates, values and functions.
88 // Actually there is no harm to think of values and functions as being
89 // of the same kind.  Their main purposes are to denote values.
90 //
91
92
93 //
94 // Integer types: bool, char, signed char, unsigned char, wchar_t,
95 // short, unsigned short, int, unsigned, long, unsigned long,
96 // and possibly long long and unsigned long long
97 //
98 // Here ISO 14882 disagrees with LIA-1 in stating bool to be an
99 // integer type.  Therefore itn't suprising to see ambiguity in the
100 // interpretation of some members.  Need to keep track of the discusion
101 // in LWG on this topic.
102 //
103 // Integer types are first promoted to int or long before the actual
104 // arithmetical operations are carried out.  Therefore testing whether
105 // traps occur amounts -- for integer types -- to test whether traps
106 // occur for int, unsigned, long, unsigned long. Furthermore
107 // overflow cannot happen for unsigned integer types.
108
109 sigjmp_buf env;
110
111 /* The prototype of signal() may vary.  Accomodate variations such as
112    void(*)(int) and void(*)(...).  */
113 template <typename signal_handler_type, typename signal_number_type>
114 inline void (*signal_adapter (signal_handler_type
115                               (*signal_func)(signal_number_type,
116                                              signal_handler_type),
117                        signal_number_type arg,
118                        void (*handler)(int)))(int)
119 {
120   return (void (*)(int))(*signal_func)(arg, (signal_handler_type)handler);
121 }
122
123 void signal_handler(int sig) 
124
125 #ifdef __CYGWIN__
126   static sigset_t x;
127   signal_adapter (signal, sig, signal_handler);
128   sigemptyset (&x);
129   sigprocmask(SIG_SETMASK, &x, NULL);
130 #endif /* __CYGWIN__ */
131   siglongjmp(env, sig); 
132 }
133
134 template<typename Operation>
135 bool trapping(const Operation& op)
136 {
137     if (sigsetjmp(env, 1) == 0) op();
138     else return true;
139     return false;
140 }
141
142 template<typename T> struct division_by_zero {
143     void operator() () const
144     {
145         volatile T zero = T();
146         volatile T one = T(1);
147         volatile T infinity = one / zero;
148     }
149 };
150
151 template<typename T> struct overflow {
152     void operator() () const
153     {
154         T i = T(1);
155         T j = T();
156         while (i>j) {
157             j = i;
158             i = i * 2 + 1;
159         }
160     }
161 };
162
163 template<typename T> struct underflow {};
164
165 // traps
166 template<typename T> void traps()
167 {
168     signal_adapter (signal, SIGFPE, signal_handler);
169     signal_adapter (signal, SIGTRAP, signal_handler);
170     bool trap_flag = trapping(division_by_zero<T>());
171     signal_adapter (signal, SIGFPE, signal_handler);
172     signal_adapter (signal, SIGTRAP, signal_handler);
173     trap_flag = trap_flag || trapping(overflow<T>());
174     const char* p = bool_alpha[trap_flag];
175     printf("%s%s = %s;\n", tab2, "static const bool traps", p);    
176 }
177
178 #define SPECIALIZE_TRAPPING(T)                                          \
179 template<> void traps< T >()                                            \
180 {                                                                       \
181     signal_adapter (signal, SIGFPE, signal_handler);                    \
182     signal_adapter (signal, SIGTRAP, signal_handler);                    \
183     const char* p = bool_alpha[trapping(division_by_zero<T>())];        \
184     printf("%s%s = %s;\n", tab2, "static const bool traps", p);         \
185 }
186
187 SPECIALIZE_TRAPPING(unsigned char);
188 SPECIALIZE_TRAPPING(unsigned short);
189 SPECIALIZE_TRAPPING(unsigned int);
190 SPECIALIZE_TRAPPING(unsigned long);
191 #if _GLIBCPP_USE_LONG_LONG
192 SPECIALIZE_TRAPPING(unsigned long long);
193 #endif
194
195 #undef SPECIALIZE_TRAPPING
196
197 template<typename T> struct type_name_trait {
198     static const char type_name[];
199     static const char trait_name[];
200 };
201
202 #define DEFINED_TYPE_NAME(T)                                            \
203 const char type_name_trait< T >::type_name[] = #T;                      \
204 const char type_name_trait< T >::trait_name[] = "numeric_limits<" #T ">";
205
206 DEFINED_TYPE_NAME(bool);
207 DEFINED_TYPE_NAME(char);
208 DEFINED_TYPE_NAME(signed char);
209 DEFINED_TYPE_NAME(unsigned char);
210 DEFINED_TYPE_NAME(wchar_t);
211 DEFINED_TYPE_NAME(short);
212 DEFINED_TYPE_NAME(unsigned short);
213 DEFINED_TYPE_NAME(int);
214 DEFINED_TYPE_NAME(unsigned int);
215 DEFINED_TYPE_NAME(long);
216 DEFINED_TYPE_NAME(unsigned long);
217 #ifdef _GLIBCPP_USE_LONG_LONG
218 DEFINED_TYPE_NAME(long long);
219 DEFINED_TYPE_NAME(unsigned long long);
220 #endif
221 DEFINED_TYPE_NAME(float);
222 DEFINED_TYPE_NAME(double);
223 DEFINED_TYPE_NAME(long double);
224
225 #undef DEFINED_TYPE_NAME
226
227 // declarator
228 template<typename T> struct declarator : type_name_trait<T> {
229     typedef type_name_trait<T> base;
230     static void start()
231     {
232         printf("%s%s %s %s\n", tab, "template<> struct",
233                base::trait_name, "{");
234     }
235
236     static void end()
237     {
238         printf("%s};\n\n", tab);
239     }
240 };
241
242
243 //
244 // Predicates
245 // 
246 template<typename T> struct predicate {
247     static const bool is_signed;
248     static const bool is_integer;
249     static const bool is_exact;
250
251     static const bool has_infinity;
252     static const bool has_quiet_nan;
253     static const bool has_signaling_nan;
254     static const bool has_denorm;
255     static const bool has_denorm_loss;
256
257     static const bool is_iec559;
258     static const bool is_bounded;
259
260     static const bool traps;
261 };
262
263 template<typename T>
264 const bool predicate<T>::is_signed = T(-1) < 0;
265
266 // Non integer types should specialize this
267 template<typename T>
268 const bool predicate<T>::is_integer = true;
269
270 // Non exact types should specialize this;
271 template<typename T>
272 const bool predicate<T>::is_exact = true;
273
274 #define SPECIALIZE_EXACTNESS(T)                                         \
275 const bool predicate< T >::is_integer = false;                          \
276 const bool predicate< T >::is_exact = false
277
278 SPECIALIZE_EXACTNESS(float);
279 SPECIALIZE_EXACTNESS(double);
280 SPECIALIZE_EXACTNESS(long double);
281
282 #undef SPECIALIZE_EXACTNESS
283
284
285 template<typename T>
286 const bool predicate<T>::has_infinity = false;
287
288 template<typename T>
289 const bool predicate<T>::has_quiet_nan = false;
290
291 template<typename T>
292 const bool predicate<T>::has_signaling_nan = false;
293
294 template<typename T>
295 const bool predicate<T>::has_denorm = false;
296
297 template<typename T>
298 const bool predicate<T>::has_denorm_loss = false;
299
300
301
302 // Each type conforming to IEC559 specifications should specialize this.
303 template<typename T>
304 const bool predicate<T>::is_iec559 = false;
305
306 #define SPECIALIZE_IEC559(T)                                            \
307 const bool predicate< T >::is_iec559 = true
308
309 SPECIALIZE_IEC559(bool);
310 SPECIALIZE_IEC559(int);
311 SPECIALIZE_IEC559(unsigned int);
312 SPECIALIZE_IEC559(long);
313 SPECIALIZE_IEC559(unsigned long);
314 #ifdef _GLIBCPP_USE_LONG_LONG
315 SPECIALIZE_IEC559(long long);
316 SPECIALIZE_IEC559(unsigned long long);
317 #endif
318
319 #undef SPECIALIZE_IEC559
320
321 //
322 // Values
323 // 
324
325 template<typename T> struct value {
326     static const char min[];
327     static const char max[];
328
329     static const int digits;
330     static const int digits10;
331     
332     static const int radix;
333     static const char epsilon[];
334     static const char round_error[];
335
336     static const int min_exponent;
337     static const int min_exponent10;
338     static const int max_exponent;
339     static const int max_exponent10;
340 };
341
342 #define DEFINE_EXTREMA(T, m, M)  DO_DEFINE_EXTREMA(T, m, M)
343 #define DO_DEFINE_EXTREMA(T, m, M)                                      \
344 const char value< T >::min[] = #m;                                      \
345 const char value< T >::max[] = #M
346
347 DEFINE_EXTREMA(bool, false, true);
348 DEFINE_EXTREMA(char, CHAR_MIN, CHAR_MAX);
349 DEFINE_EXTREMA(signed char, SCHAR_MIN, SCHAR_MAX);
350 DEFINE_EXTREMA(unsigned char, 0, UCHAR_MAX);
351 #ifdef _GLIBCPP_USE_WCHAR_T
352 DEFINE_EXTREMA(wchar_t, WCHAR_MIN, WCHAR_MAX);
353 #endif
354 DEFINE_EXTREMA(short, SHRT_MIN, SHRT_MAX);
355 DEFINE_EXTREMA(unsigned short, 0, USHRT_MAX);
356 DEFINE_EXTREMA(int, INT_MIN, INT_MAX);
357 DEFINE_EXTREMA(unsigned int, 0, UINT_MAX);
358 DEFINE_EXTREMA(long, LONG_MIN, LONG_MAX);
359 DEFINE_EXTREMA(unsigned long, 0, ULONG_MAX);
360 #ifdef _GLIBCPP_USE_LONG_LONG
361 DEFINE_EXTREMA(long long, LONG_LONG_MIN, LONG_LONG_MAX);
362 DEFINE_EXTREMA(unsigned long long, 0, ULONG_LONG_MAX);
363 #endif
364 DEFINE_EXTREMA(float, FLT_MIN, FLT_MAX);
365 DEFINE_EXTREMA(double, DBL_MIN, DBL_MAX);
366 DEFINE_EXTREMA(long double, LDBL_MIN, LDBL_MAX);
367
368 #undef DEFINE_EXTREMA
369 #undef DO_DEFINE_EXTREMA
370
371 // Non integer types should specialize this
372 template<typename T>
373 const int value<T>::digits =
374       bits_per_byte * sizeof(T) - int(predicate<T>::is_signed);
375
376 // Non integer types should specialize this.  Always two for
377 // integer types.
378 template<typename T>
379 const int value<T>::radix = 2;
380
381 #define SPECIALIZE_DIGITS(T, D, D10)                                    \
382 const int value< T >::digits = D;                                       \
383 const int value< T >::digits10 = D10
384
385 SPECIALIZE_DIGITS(float, FLT_MANT_DIG, FLT_DIG);
386 SPECIALIZE_DIGITS(double, DBL_MANT_DIG, DBL_DIG);
387 SPECIALIZE_DIGITS(long double, LDBL_MANT_DIG, LDBL_DIG);
388
389 #undef SPECIALIZE_DIGITS
390
391
392 #define SPECIALIZE_RADIX(T, R) const int value< T >::radix = R
393
394 SPECIALIZE_RADIX(float, FLT_RADIX);
395 SPECIALIZE_RADIX(double, FLT_RADIX);
396 SPECIALIZE_RADIX(long double, FLT_RADIX);
397
398 #undef SPECIALIZE_RADIX
399
400 // Non integer types should specialize this.  
401 // Unfortunately, systems that don't deal with weak linking correctly
402 // (Ie, hpux and aix), cannot use this sophisticated yet sane method. So,
403 // explicitly instantiate all the data members here so that they will
404 // be happy.
405
406 // sophisticated, sane method
407 #if 0
408 template<typename T>
409 const char value<T>::epsilon[] = "0";
410 #endif
411
412 #define SPECIALIZE_EPSILON(T, E) DO_SPECIALIZE_EPSILON(T, E)
413 #define DO_SPECIALIZE_EPSILON(T, E) const char value< T >::epsilon[] = #E
414
415 // unsophisticated, gross method
416 #if 1
417 SPECIALIZE_EPSILON(bool, 0);
418 SPECIALIZE_EPSILON(char, 0);
419 SPECIALIZE_EPSILON(unsigned char, 0);
420 SPECIALIZE_EPSILON(signed char, 0);
421 SPECIALIZE_EPSILON(wchar_t, 0);
422 SPECIALIZE_EPSILON(short, 0);
423 SPECIALIZE_EPSILON(unsigned short, 0);
424 SPECIALIZE_EPSILON(int, 0);
425 SPECIALIZE_EPSILON(unsigned int, 0);
426 SPECIALIZE_EPSILON(long, 0);
427 SPECIALIZE_EPSILON(unsigned long, 0);
428 SPECIALIZE_EPSILON(long long, 0);
429 SPECIALIZE_EPSILON(unsigned long long, 0);
430 #endif
431
432 SPECIALIZE_EPSILON(float, FLT_EPSILON);
433 SPECIALIZE_EPSILON(double, DBL_EPSILON);
434 SPECIALIZE_EPSILON(long double, LDBL_EPSILON);
435
436 #undef DO_SPECIALIZE_EPSILON
437 #undef SPECIALIZE_EPSILON
438
439
440 // Non integer types should specialize this.  
441 // Unfortunately, systems that don't deal with weak linking correctly
442 // (Ie, hpux and aix), cannot use this sophisticated yet sane method. So,
443 // explicitly instantiate all the data members here so that they will
444 // be happy.
445
446 // sophisticated, sane method
447 #if 0
448 template<typename T>
449 const char value<T>::round_error[] = "0";
450 #endif
451
452 #define SPECIALIZE_ROUND_ERROR(T, R) const char value< T >::round_error[] = #R
453 // unsophisticated, gross method
454 #if 1
455 SPECIALIZE_ROUND_ERROR(bool, 0);
456 SPECIALIZE_ROUND_ERROR(char, 0);
457 SPECIALIZE_ROUND_ERROR(unsigned char, 0);
458 SPECIALIZE_ROUND_ERROR(signed char, 0);
459 SPECIALIZE_ROUND_ERROR(wchar_t, 0);
460 SPECIALIZE_ROUND_ERROR(short, 0);
461 SPECIALIZE_ROUND_ERROR(unsigned short, 0);
462 SPECIALIZE_ROUND_ERROR(int, 0);
463 SPECIALIZE_ROUND_ERROR(unsigned int, 0);
464 SPECIALIZE_ROUND_ERROR(long, 0);
465 SPECIALIZE_ROUND_ERROR(unsigned long, 0);
466 SPECIALIZE_ROUND_ERROR(long long, 0);
467 SPECIALIZE_ROUND_ERROR(unsigned long long, 0);
468 #endif
469
470 SPECIALIZE_ROUND_ERROR(float, 1.0f);
471 SPECIALIZE_ROUND_ERROR(double, 1.0);
472 SPECIALIZE_ROUND_ERROR(long double, 1.0L);
473
474 #undef SPECIALIZE_ROUND_ERROR
475
476
477 template<typename T>
478 const int value<T>::min_exponent = 0;
479
480 template<typename T>
481 const int value<T>::min_exponent10 = 0;
482
483 template<typename T>
484 const int value<T>::max_exponent = 0;
485
486 template<typename T>
487 const int value<T>::max_exponent10 = 0;
488
489 #define SPECIALIZE_EXPONENTS(T, m, m10, M, M10)                         \
490 const int value< T >::min_exponent = m;                                 \
491 const int value< T >::min_exponent10 = m10;                             \
492 const int value< T >::max_exponent = M;                                 \
493 const int value< T >::max_exponent10 = M10
494
495 SPECIALIZE_EXPONENTS(float, FLT_MIN_EXP, FLT_MIN_10_EXP,
496                      FLT_MAX_EXP, FLT_MAX_10_EXP);
497 SPECIALIZE_EXPONENTS(double, DBL_MIN_EXP, DBL_MIN_10_EXP,
498                      DBL_MAX_EXP, DBL_MAX_10_EXP);
499 SPECIALIZE_EXPONENTS(long double, LDBL_MIN_EXP, LDBL_MIN_10_EXP,
500                      LDBL_MAX_EXP, LDBL_MAX_10_EXP);
501
502 #undef SPECIALIZE_EXPONENTS
503
504 //
505 // Functions to output predicates and values.
506 //
507
508 template<typename T> void is_signed()
509 {
510     printf("%s%s = %s;\n", tab2, "static const bool is_signed",
511            bool_alpha[predicate<T>::is_signed]);
512 }
513
514 // a fundamental type is modulo iff it isn't signed
515 template<typename T> void is_modulo()
516 {
517     printf("%s%s = %s;\n", tab2, "static const bool is_modulo",
518            bool_alpha[! predicate<T>::is_signed]);
519 }
520
521 template<typename T>
522 void min()
523 {
524     printf("%s%s%s%s\n%s%s%s%s\n", tab2, "static ", declarator<T>::type_name,
525            " min() throw()", tab2, "{ return ", value<T>::min, "; }");
526 }
527
528 template<typename T>
529 void max()
530 {
531     printf("%s%s%s%s\n%s%s%s%s\n", tab2, "static ", declarator<T>::type_name,
532            " max() throw()", tab2, "{ return ", value<T>::max, "; }");
533 }
534
535 template<typename T>
536 void is_integer()
537 {
538     printf("%s%s = %s;\n", tab2, "static const bool is_integer",
539            bool_alpha[predicate<T>::is_integer]);        
540 }
541
542 template<typename T>
543 void is_exact()
544 {
545     printf("%s%s = %s;\n", tab2, "static const bool is_exact",
546            bool_alpha[predicate<T>::is_exact]);    
547 }
548
549 template<typename T>
550 void digits()
551 {
552     printf("%s%s = %d;\n", tab2, "static const int digits",
553            value<T>::digits);
554 }
555
556 template<typename T>
557 void digits10()
558 {
559     printf("%s%s = %d;\n", tab2, "static const int digits10",
560            int(log10_of_two * value<T>::digits));
561 }
562
563 template<typename T>
564 void radix()
565 {
566     printf("%s%s = %d;\n", tab2, "static const int radix",
567            value<T>::radix);
568 }
569
570 template<typename T>
571 void epsilon()
572 {
573     printf("%s%s %s %s\n%s%s %s%s\n", tab2, "static",
574            declarator<T>::type_name, "epsilon() throw()",
575            tab2, "{ return", value<T>::epsilon, "; }");
576 }
577
578 template<typename T>
579 void round_error()
580 {
581     printf("%s%s %s %s\n%s%s %s%s\n", tab2, "static",
582            declarator<T>::type_name, "round_error() throw()",
583            tab2, "{ return", value<T>::round_error, "; }");
584 }
585
586 template<typename T>
587 void min_exponent()
588 {
589     printf("%s%s = %d;\n", tab2, "static const int min_exponent",
590            value<T>::min_exponent);    
591 }
592
593 template<typename T>
594 void min_exponent10()
595 {
596     printf("%s%s = %d;\n", tab2, "static const int min_exponent10",
597            value<T>::min_exponent10);    
598 }
599
600 template<typename T>
601 void max_exponent()
602 {
603     printf("%s%s = %d;\n", tab2, "static const int max_exponent",
604            value<T>::max_exponent);    
605 }
606
607 template<typename T>
608 void max_exponent10()
609 {
610     printf("%s%s = %d;\n", tab2, "static const int max_exponent10",
611            value<T>::max_exponent10);    
612 }
613
614 template<typename T>
615 void has_infinity()
616 {
617     printf("%s%s = %s;\n", tab2, "static const bool has_infinity",
618            bool_alpha[predicate<T>::has_infinity]);
619 }
620
621 template<typename T>
622 void has_quiet_nan()
623 {
624     printf("%s%s = %s;\n", tab2, "static const bool has_quiet_NaN",
625            bool_alpha[predicate<T>::has_quiet_nan]);
626 }
627
628 template<typename T>
629 void has_signaling_nan()
630 {
631     printf("%s%s = %s;\n", tab2, "static const bool has_signaling_NaN",
632            bool_alpha[predicate<T>::has_signaling_nan]);
633 }
634
635 template<typename T>
636 void has_denorm_loss()
637 {
638     printf("%s%s = %s;\n", tab2, "static const bool has_denorm_loss",
639            bool_alpha[predicate<T>::has_denorm_loss]);
640 }
641
642 template<typename T> struct infinity_trait {
643     static void has_denorm()
644     {
645         printf("%s%s;\n", tab2, "static const float_denorm_style "
646                "has_denorm = denorm_absent");
647     }
648
649     static void infinity()
650     {
651         printf("%s%s %s %s\n%s%s%s%s\n", tab2, "static",
652                declarator<T>::type_name, "infinity() throw()",
653                tab2, "{ return static_cast<", declarator<T>::type_name, 
654                ">(0); }");
655     }
656
657     static void quiet_NaN()
658     {
659         printf("%s%s %s %s\n%s%s%s%s\n", tab2, "static",
660                declarator<T>::type_name, "quiet_NaN() throw()",
661                tab2, "{ return static_cast<", declarator<T>::type_name, 
662                ">(0); }");
663     }
664
665     static void signaling_NaN()
666     {
667         printf("%s%s %s %s\n%s%s%s%s\n", tab2, "static",
668                declarator<T>::type_name, "signaling_NaN() throw()",
669                tab2, "{ return static_cast<", declarator<T>::type_name, 
670                ">(0); }");
671     }
672
673     static void denorm_min()
674     {
675         printf("%s%s %s %s\n%s%s%s%s\n", tab2, "static",
676                declarator<T>::type_name, "denorm_min() throw()",
677                tab2, "{ return static_cast<", declarator<T>::type_name, 
678                ">(0); }");
679     }
680 };
681
682
683 template<typename T>
684 void is_iec559()
685 {
686     printf("%s%s = %s;\n", tab2, "static const bool is_iec559",
687            bool_alpha[predicate<T>::is_iec559]);
688 }
689
690 // tinyness_before
691 template<typename T>
692 void tinyness_before()
693 {
694     printf("%s%s;\n", tab2, "static const bool tinyness_before = false");
695 }
696
697 // round style
698 template<typename T>
699 void round_style()
700 {
701     printf("%s%s;\n", tab2, "static const float_round_style "
702            "round_style = round_toward_zero");    
703 }
704
705
706
707 // type traits
708 template<typename T> struct type_trait {
709     
710     type_trait()
711     {
712         declarator<T>::start();
713         printf("%s%s;\n\n", tab2, "static const bool is_specialized = true");
714         min<T>();
715         max<T>();
716         printf("\n");
717         digits<T>();
718         digits10<T>();
719         is_signed<T>();
720         is_integer<T>();
721         is_exact<T>();
722         radix<T>();
723         epsilon<T>();
724         round_error<T>();
725         printf("\n");
726         min_exponent<T>();
727         min_exponent10<T>();
728         max_exponent<T>();
729         max_exponent10<T>();
730         printf("\n");
731         has_infinity<T>();
732         has_quiet_nan<T>();
733         has_signaling_nan<T>();
734         infinity_trait<T>::has_denorm();
735         has_denorm_loss<T>();
736         printf("\n");
737         infinity_trait<T>::infinity();
738         infinity_trait<T>::quiet_NaN();
739         infinity_trait<T>::signaling_NaN();
740         infinity_trait<T>::denorm_min();
741         printf("\n");
742         is_iec559<T>();
743         printf("%s%s;\n", tab2, "static const bool is_bounded = true");
744         is_modulo<T>();
745         printf("\n");
746         traps<T>();
747         tinyness_before<T>();
748         round_style<T>();
749         declarator<T>::end();
750     }
751 };
752
753 int main()
754 {
755     type_trait<bool>();
756
757     type_trait<char>();
758     type_trait<signed char>();
759     type_trait<unsigned char>();
760 #if defined( _GLIBCPP_USE_WCHAR_T) 
761     type_trait<wchar_t>();
762 #endif
763     
764     type_trait<short>();
765     type_trait<unsigned short>();
766
767     type_trait<int>();
768     type_trait<unsigned int>();
769
770     type_trait<long>();
771     type_trait<unsigned long>();
772
773 #ifdef _GLIBCPP_USE_LONG_LONG
774     type_trait<long long>();
775     type_trait<unsigned long long>();
776 #endif
777
778     type_trait<float>();
779     type_trait<double>();
780     type_trait<long double>();
781
782     // x86/linux gets this weirdness for the min/max functions:
783     // static long double min() throw()
784     // { return (__extension__ ((union __convert_long_double) 
785     // {__convert_long_double_i: {0x0, 0x80000000, 0x1, 0x0}})
786     // .__convert_long_double_d); }
787 }
788
789 // G++ doesn't have support for automatic instantiation of static data
790 // members on platforms that don't have weak symbols.  On AIX, in
791 // particular, static data members must be explicitly instantiated.
792 // So, we explicitly instantiate some of the ones we need.  To save
793 // typing, we don't name the static data members explicitly; we
794 // instead name their containing types.
795
796 #define INSTANTIATIONS(TYPE)                    \
797   template struct predicate<TYPE>;              \
798   template struct value<TYPE>
799
800 INSTANTIATIONS (bool);
801 INSTANTIATIONS (char);
802 INSTANTIATIONS (signed char);
803 INSTANTIATIONS (unsigned char);
804 INSTANTIATIONS (short);
805 INSTANTIATIONS (unsigned short);
806 INSTANTIATIONS (int);
807 INSTANTIATIONS (unsigned int);
808 INSTANTIATIONS (long);
809 INSTANTIATIONS (unsigned long);
810 INSTANTIATIONS (float);
811 INSTANTIATIONS (double);
812 INSTANTIATIONS (long double);
813