1 | // Definition of numeric_limits replacement traits P1841R1 -*- C++ -*- |
2 | |
3 | // Copyright (C) 2020-2021 Free Software Foundation, Inc. |
4 | // |
5 | // This file is part of the GNU ISO C++ Library. This library is free |
6 | // software; you can redistribute it and/or modify it under the |
7 | // terms of the GNU General Public License as published by the |
8 | // Free Software Foundation; either version 3, or (at your option) |
9 | // any later version. |
10 | |
11 | // This library is distributed in the hope that it will be useful, |
12 | // but WITHOUT ANY WARRANTY; without even the implied warranty of |
13 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
14 | // GNU General Public License for more details. |
15 | |
16 | // Under Section 7 of GPL version 3, you are granted additional |
17 | // permissions described in the GCC Runtime Library Exception, version |
18 | // 3.1, as published by the Free Software Foundation. |
19 | |
20 | // You should have received a copy of the GNU General Public License and |
21 | // a copy of the GCC Runtime Library Exception along with this program; |
22 | // see the files COPYING3 and COPYING.RUNTIME respectively. If not, see |
23 | // <http://www.gnu.org/licenses/>. |
24 | |
25 | #include <type_traits> |
26 | |
27 | namespace std { |
28 | |
29 | template <template <typename> class _Trait, typename _Tp, typename = void> |
30 | struct __value_exists_impl : false_type {}; |
31 | |
32 | template <template <typename> class _Trait, typename _Tp> |
33 | struct __value_exists_impl<_Trait, _Tp, void_t<decltype(_Trait<_Tp>::value)>> |
34 | : true_type {}; |
35 | |
36 | template <typename _Tp, bool = is_arithmetic_v<_Tp>> |
37 | struct __digits_impl {}; |
38 | |
39 | template <typename _Tp> |
40 | struct __digits_impl<_Tp, true> |
41 | { |
42 | static inline constexpr int value |
43 | = sizeof(_Tp) * __CHAR_BIT__ - is_signed_v<_Tp>; |
44 | }; |
45 | |
46 | template <> |
47 | struct __digits_impl<float, true> |
48 | { static inline constexpr int value = __FLT_MANT_DIG__; }; |
49 | |
50 | template <> |
51 | struct __digits_impl<double, true> |
52 | { static inline constexpr int value = __DBL_MANT_DIG__; }; |
53 | |
54 | template <> |
55 | struct __digits_impl<long double, true> |
56 | { static inline constexpr int value = __LDBL_MANT_DIG__; }; |
57 | |
58 | template <typename _Tp, bool = is_arithmetic_v<_Tp>> |
59 | struct __digits10_impl {}; |
60 | |
61 | template <typename _Tp> |
62 | struct __digits10_impl<_Tp, true> |
63 | { |
64 | // The fraction 643/2136 approximates log10(2) to 7 significant digits. |
65 | static inline constexpr int value = __digits_impl<_Tp>::value * 643L / 2136; |
66 | }; |
67 | |
68 | template <> |
69 | struct __digits10_impl<float, true> |
70 | { static inline constexpr int value = __FLT_DIG__; }; |
71 | |
72 | template <> |
73 | struct __digits10_impl<double, true> |
74 | { static inline constexpr int value = __DBL_DIG__; }; |
75 | |
76 | template <> |
77 | struct __digits10_impl<long double, true> |
78 | { static inline constexpr int value = __LDBL_DIG__; }; |
79 | |
80 | template <typename _Tp, bool = is_arithmetic_v<_Tp>> |
81 | struct __max_digits10_impl {}; |
82 | |
83 | template <typename _Tp> |
84 | struct __max_digits10_impl<_Tp, true> |
85 | { |
86 | static inline constexpr int value |
87 | = is_floating_point_v<_Tp> ? 2 + __digits_impl<_Tp>::value * 643L / 2136 |
88 | : __digits10_impl<_Tp>::value + 1; |
89 | }; |
90 | |
91 | template <typename _Tp> |
92 | struct __max_exponent_impl {}; |
93 | |
94 | template <> |
95 | struct __max_exponent_impl<float> |
96 | { static inline constexpr int value = __FLT_MAX_EXP__; }; |
97 | |
98 | template <> |
99 | struct __max_exponent_impl<double> |
100 | { static inline constexpr int value = __DBL_MAX_EXP__; }; |
101 | |
102 | template <> |
103 | struct __max_exponent_impl<long double> |
104 | { static inline constexpr int value = __LDBL_MAX_EXP__; }; |
105 | |
106 | template <typename _Tp> |
107 | struct __max_exponent10_impl {}; |
108 | |
109 | template <> |
110 | struct __max_exponent10_impl<float> |
111 | { static inline constexpr int value = __FLT_MAX_10_EXP__; }; |
112 | |
113 | template <> |
114 | struct __max_exponent10_impl<double> |
115 | { static inline constexpr int value = __DBL_MAX_10_EXP__; }; |
116 | |
117 | template <> |
118 | struct __max_exponent10_impl<long double> |
119 | { static inline constexpr int value = __LDBL_MAX_10_EXP__; }; |
120 | |
121 | template <typename _Tp> |
122 | struct __min_exponent_impl {}; |
123 | |
124 | template <> |
125 | struct __min_exponent_impl<float> |
126 | { static inline constexpr int value = __FLT_MIN_EXP__; }; |
127 | |
128 | template <> |
129 | struct __min_exponent_impl<double> |
130 | { static inline constexpr int value = __DBL_MIN_EXP__; }; |
131 | |
132 | template <> |
133 | struct __min_exponent_impl<long double> |
134 | { static inline constexpr int value = __LDBL_MIN_EXP__; }; |
135 | |
136 | template <typename _Tp> |
137 | struct __min_exponent10_impl {}; |
138 | |
139 | template <> |
140 | struct __min_exponent10_impl<float> |
141 | { static inline constexpr int value = __FLT_MIN_10_EXP__; }; |
142 | |
143 | template <> |
144 | struct __min_exponent10_impl<double> |
145 | { static inline constexpr int value = __DBL_MIN_10_EXP__; }; |
146 | |
147 | template <> |
148 | struct __min_exponent10_impl<long double> |
149 | { static inline constexpr int value = __LDBL_MIN_10_EXP__; }; |
150 | |
151 | template <typename _Tp, bool = is_arithmetic_v<_Tp>> |
152 | struct __radix_impl {}; |
153 | |
154 | template <typename _Tp> |
155 | struct __radix_impl<_Tp, true> |
156 | { |
157 | static inline constexpr int value |
158 | = is_floating_point_v<_Tp> ? __FLT_RADIX__ : 2; |
159 | }; |
160 | |
161 | // [num.traits.util], numeric utility traits |
162 | template <template <typename> class _Trait, typename _Tp> |
163 | struct __value_exists : __value_exists_impl<_Trait, _Tp> {}; |
164 | |
165 | template <template <typename> class _Trait, typename _Tp> |
166 | inline constexpr bool __value_exists_v = __value_exists<_Trait, _Tp>::value; |
167 | |
168 | template <template <typename> class _Trait, typename _Tp, typename _Up = _Tp> |
169 | inline constexpr _Up |
170 | __value_or(_Up __def = _Up()) noexcept |
171 | { |
172 | if constexpr (__value_exists_v<_Trait, _Tp>) |
173 | return static_cast<_Up>(_Trait<_Tp>::value); |
174 | else |
175 | return __def; |
176 | } |
177 | |
178 | template <typename _Tp, bool = is_arithmetic_v<_Tp>> |
179 | struct __norm_min_impl {}; |
180 | |
181 | template <typename _Tp> |
182 | struct __norm_min_impl<_Tp, true> |
183 | { static inline constexpr _Tp value = 1; }; |
184 | |
185 | template <> |
186 | struct __norm_min_impl<float, true> |
187 | { static inline constexpr float value = __FLT_MIN__; }; |
188 | |
189 | template <> |
190 | struct __norm_min_impl<double, true> |
191 | { static inline constexpr double value = __DBL_MIN__; }; |
192 | |
193 | template <> |
194 | struct __norm_min_impl<long double, true> |
195 | { static inline constexpr long double value = __LDBL_MIN__; }; |
196 | |
197 | template <typename _Tp> |
198 | struct __denorm_min_impl : __norm_min_impl<_Tp> {}; |
199 | |
200 | #if __FLT_HAS_DENORM__ |
201 | template <> |
202 | struct __denorm_min_impl<float> |
203 | { static inline constexpr float value = __FLT_DENORM_MIN__; }; |
204 | #endif |
205 | |
206 | #if __DBL_HAS_DENORM__ |
207 | template <> |
208 | struct __denorm_min_impl<double> |
209 | { static inline constexpr double value = __DBL_DENORM_MIN__; }; |
210 | #endif |
211 | |
212 | #if __LDBL_HAS_DENORM__ |
213 | template <> |
214 | struct __denorm_min_impl<long double> |
215 | { static inline constexpr long double value = __LDBL_DENORM_MIN__; }; |
216 | #endif |
217 | |
218 | template <typename _Tp> |
219 | struct __epsilon_impl {}; |
220 | |
221 | template <> |
222 | struct __epsilon_impl<float> |
223 | { static inline constexpr float value = __FLT_EPSILON__; }; |
224 | |
225 | template <> |
226 | struct __epsilon_impl<double> |
227 | { static inline constexpr double value = __DBL_EPSILON__; }; |
228 | |
229 | template <> |
230 | struct __epsilon_impl<long double> |
231 | { static inline constexpr long double value = __LDBL_EPSILON__; }; |
232 | |
233 | template <typename _Tp, bool = is_arithmetic_v<_Tp>> |
234 | struct __finite_min_impl {}; |
235 | |
236 | template <typename _Tp> |
237 | struct __finite_min_impl<_Tp, true> |
238 | { |
239 | static inline constexpr _Tp value |
240 | = is_unsigned_v<_Tp> ? _Tp() |
241 | : -2 * (_Tp(1) << __digits_impl<_Tp>::value - 1); |
242 | }; |
243 | |
244 | template <> |
245 | struct __finite_min_impl<float, true> |
246 | { static inline constexpr float value = -__FLT_MAX__; }; |
247 | |
248 | template <> |
249 | struct __finite_min_impl<double, true> |
250 | { static inline constexpr double value = -__DBL_MAX__; }; |
251 | |
252 | template <> |
253 | struct __finite_min_impl<long double, true> |
254 | { static inline constexpr long double value = -__LDBL_MAX__; }; |
255 | |
256 | template <typename _Tp, bool = is_arithmetic_v<_Tp>> |
257 | struct __finite_max_impl {}; |
258 | |
259 | template <typename _Tp> |
260 | struct __finite_max_impl<_Tp, true> |
261 | { static inline constexpr _Tp value = ~__finite_min_impl<_Tp>::value; }; |
262 | |
263 | template <> |
264 | struct __finite_max_impl<float, true> |
265 | { static inline constexpr float value = __FLT_MAX__; }; |
266 | |
267 | template <> |
268 | struct __finite_max_impl<double, true> |
269 | { static inline constexpr double value = __DBL_MAX__; }; |
270 | |
271 | template <> |
272 | struct __finite_max_impl<long double, true> |
273 | { static inline constexpr long double value = __LDBL_MAX__; }; |
274 | |
275 | template <typename _Tp> |
276 | struct __infinity_impl {}; |
277 | |
278 | #if __FLT_HAS_INFINITY__ |
279 | template <> |
280 | struct __infinity_impl<float> |
281 | { static inline constexpr float value = __builtin_inff(); }; |
282 | #endif |
283 | |
284 | #if __DBL_HAS_INFINITY__ |
285 | template <> |
286 | struct __infinity_impl<double> |
287 | { static inline constexpr double value = __builtin_inf(); }; |
288 | #endif |
289 | |
290 | #if __LDBL_HAS_INFINITY__ |
291 | template <> |
292 | struct __infinity_impl<long double> |
293 | { static inline constexpr long double value = __builtin_infl(); }; |
294 | #endif |
295 | |
296 | template <typename _Tp> |
297 | struct __quiet_NaN_impl {}; |
298 | |
299 | #if __FLT_HAS_QUIET_NAN__ |
300 | template <> |
301 | struct __quiet_NaN_impl<float> |
302 | { static inline constexpr float value = __builtin_nanf("" ); }; |
303 | #endif |
304 | |
305 | #if __DBL_HAS_QUIET_NAN__ |
306 | template <> |
307 | struct __quiet_NaN_impl<double> |
308 | { static inline constexpr double value = __builtin_nan("" ); }; |
309 | #endif |
310 | |
311 | #if __LDBL_HAS_QUIET_NAN__ |
312 | template <> |
313 | struct __quiet_NaN_impl<long double> |
314 | { static inline constexpr long double value = __builtin_nanl("" ); }; |
315 | #endif |
316 | |
317 | template <typename _Tp, bool = is_floating_point_v<_Tp>> |
318 | struct __reciprocal_overflow_threshold_impl {}; |
319 | |
320 | template <typename _Tp> |
321 | struct __reciprocal_overflow_threshold_impl<_Tp, true> |
322 | { |
323 | // This typically yields a subnormal value. Is this incorrect for |
324 | // flush-to-zero configurations? |
325 | static constexpr _Tp _S_search(_Tp __ok, _Tp __overflows) |
326 | { |
327 | const _Tp __mid = (__ok + __overflows) / 2; |
328 | // 1/__mid without -ffast-math is not a constant expression if it |
329 | // overflows. Therefore divide 1 by the radix before division. |
330 | // Consequently finite_max (the threshold) must be scaled by the |
331 | // same value. |
332 | if (__mid == __ok || __mid == __overflows) |
333 | return __ok; |
334 | else if (_Tp(1) / (__radix_impl<_Tp>::value * __mid) |
335 | <= __finite_max_impl<_Tp>::value / __radix_impl<_Tp>::value) |
336 | return _S_search(ok: __mid, __overflows); |
337 | else |
338 | return _S_search(__ok, overflows: __mid); |
339 | } |
340 | |
341 | static inline constexpr _Tp value |
342 | = _S_search(ok: _Tp(1.01) / __finite_max_impl<_Tp>::value, |
343 | overflows: _Tp(0.99) / __finite_max_impl<_Tp>::value); |
344 | }; |
345 | |
346 | template <typename _Tp, bool = is_floating_point_v<_Tp>> |
347 | struct __round_error_impl {}; |
348 | |
349 | template <typename _Tp> |
350 | struct __round_error_impl<_Tp, true> |
351 | { static inline constexpr _Tp value = 0.5; }; |
352 | |
353 | template <typename _Tp> |
354 | struct __signaling_NaN_impl {}; |
355 | |
356 | #if __FLT_HAS_QUIET_NAN__ |
357 | template <> |
358 | struct __signaling_NaN_impl<float> |
359 | { static inline constexpr float value = __builtin_nansf("" ); }; |
360 | #endif |
361 | |
362 | #if __DBL_HAS_QUIET_NAN__ |
363 | template <> |
364 | struct __signaling_NaN_impl<double> |
365 | { static inline constexpr double value = __builtin_nans("" ); }; |
366 | #endif |
367 | |
368 | #if __LDBL_HAS_QUIET_NAN__ |
369 | template <> |
370 | struct __signaling_NaN_impl<long double> |
371 | { static inline constexpr long double value = __builtin_nansl("" ); }; |
372 | #endif |
373 | |
374 | // [num.traits.val], numeric distinguished value traits |
375 | template <typename _Tp> |
376 | struct __denorm_min : __denorm_min_impl<remove_cv_t<_Tp>> {}; |
377 | |
378 | template <typename _Tp> |
379 | struct __epsilon : __epsilon_impl<remove_cv_t<_Tp>> {}; |
380 | |
381 | template <typename _Tp> |
382 | struct __finite_max : __finite_max_impl<remove_cv_t<_Tp>> {}; |
383 | |
384 | template <typename _Tp> |
385 | struct __finite_min : __finite_min_impl<remove_cv_t<_Tp>> {}; |
386 | |
387 | template <typename _Tp> |
388 | struct __infinity : __infinity_impl<remove_cv_t<_Tp>> {}; |
389 | |
390 | template <typename _Tp> |
391 | struct __norm_min : __norm_min_impl<remove_cv_t<_Tp>> {}; |
392 | |
393 | template <typename _Tp> |
394 | struct __quiet_NaN : __quiet_NaN_impl<remove_cv_t<_Tp>> {}; |
395 | |
396 | template <typename _Tp> |
397 | struct __reciprocal_overflow_threshold |
398 | : __reciprocal_overflow_threshold_impl<remove_cv_t<_Tp>> {}; |
399 | |
400 | template <typename _Tp> |
401 | struct __round_error : __round_error_impl<remove_cv_t<_Tp>> {}; |
402 | |
403 | template <typename _Tp> |
404 | struct __signaling_NaN : __signaling_NaN_impl<remove_cv_t<_Tp>> {}; |
405 | |
406 | template <typename _Tp> |
407 | inline constexpr auto __denorm_min_v = __denorm_min<_Tp>::value; |
408 | |
409 | template <typename _Tp> |
410 | inline constexpr auto __epsilon_v = __epsilon<_Tp>::value; |
411 | |
412 | template <typename _Tp> |
413 | inline constexpr auto __finite_max_v = __finite_max<_Tp>::value; |
414 | |
415 | template <typename _Tp> |
416 | inline constexpr auto __finite_min_v = __finite_min<_Tp>::value; |
417 | |
418 | template <typename _Tp> |
419 | inline constexpr auto __infinity_v = __infinity<_Tp>::value; |
420 | |
421 | template <typename _Tp> |
422 | inline constexpr auto __norm_min_v = __norm_min<_Tp>::value; |
423 | |
424 | template <typename _Tp> |
425 | inline constexpr auto __quiet_NaN_v = __quiet_NaN<_Tp>::value; |
426 | |
427 | template <typename _Tp> |
428 | inline constexpr auto __reciprocal_overflow_threshold_v |
429 | = __reciprocal_overflow_threshold<_Tp>::value; |
430 | |
431 | template <typename _Tp> |
432 | inline constexpr auto __round_error_v = __round_error<_Tp>::value; |
433 | |
434 | template <typename _Tp> |
435 | inline constexpr auto __signaling_NaN_v = __signaling_NaN<_Tp>::value; |
436 | |
437 | // [num.traits.char], numeric characteristics traits |
438 | template <typename _Tp> |
439 | struct __digits : __digits_impl<remove_cv_t<_Tp>> {}; |
440 | |
441 | template <typename _Tp> |
442 | struct __digits10 : __digits10_impl<remove_cv_t<_Tp>> {}; |
443 | |
444 | template <typename _Tp> |
445 | struct __max_digits10 : __max_digits10_impl<remove_cv_t<_Tp>> {}; |
446 | |
447 | template <typename _Tp> |
448 | struct __max_exponent : __max_exponent_impl<remove_cv_t<_Tp>> {}; |
449 | |
450 | template <typename _Tp> |
451 | struct __max_exponent10 : __max_exponent10_impl<remove_cv_t<_Tp>> {}; |
452 | |
453 | template <typename _Tp> |
454 | struct __min_exponent : __min_exponent_impl<remove_cv_t<_Tp>> {}; |
455 | |
456 | template <typename _Tp> |
457 | struct __min_exponent10 : __min_exponent10_impl<remove_cv_t<_Tp>> {}; |
458 | |
459 | template <typename _Tp> |
460 | struct __radix : __radix_impl<remove_cv_t<_Tp>> {}; |
461 | |
462 | template <typename _Tp> |
463 | inline constexpr auto __digits_v = __digits<_Tp>::value; |
464 | |
465 | template <typename _Tp> |
466 | inline constexpr auto __digits10_v = __digits10<_Tp>::value; |
467 | |
468 | template <typename _Tp> |
469 | inline constexpr auto __max_digits10_v = __max_digits10<_Tp>::value; |
470 | |
471 | template <typename _Tp> |
472 | inline constexpr auto __max_exponent_v = __max_exponent<_Tp>::value; |
473 | |
474 | template <typename _Tp> |
475 | inline constexpr auto __max_exponent10_v = __max_exponent10<_Tp>::value; |
476 | |
477 | template <typename _Tp> |
478 | inline constexpr auto __min_exponent_v = __min_exponent<_Tp>::value; |
479 | |
480 | template <typename _Tp> |
481 | inline constexpr auto __min_exponent10_v = __min_exponent10<_Tp>::value; |
482 | |
483 | template <typename _Tp> |
484 | inline constexpr auto __radix_v = __radix<_Tp>::value; |
485 | |
486 | // mkretz's extensions |
487 | // TODO: does GCC tell me? __GCC_IEC_559 >= 2 is not the right answer |
488 | template <typename _Tp> |
489 | struct __has_iec559_storage_format : true_type {}; |
490 | |
491 | template <typename _Tp> |
492 | inline constexpr bool __has_iec559_storage_format_v |
493 | = __has_iec559_storage_format<_Tp>::value; |
494 | |
495 | /* To propose: |
496 | If __has_iec559_behavior<__quiet_NaN, T> is true the following holds: |
497 | - nan == nan is false |
498 | - isnan(nan) is true |
499 | - isnan(nan + x) is true |
500 | - isnan(inf/inf) is true |
501 | - isnan(0/0) is true |
502 | - isunordered(nan, x) is true |
503 | |
504 | If __has_iec559_behavior<__infinity, T> is true the following holds (x is |
505 | neither nan nor inf): |
506 | - isinf(inf) is true |
507 | - isinf(inf + x) is true |
508 | - isinf(1/0) is true |
509 | */ |
510 | template <template <typename> class _Trait, typename _Tp> |
511 | struct __has_iec559_behavior : false_type {}; |
512 | |
513 | template <template <typename> class _Trait, typename _Tp> |
514 | inline constexpr bool __has_iec559_behavior_v |
515 | = __has_iec559_behavior<_Trait, _Tp>::value; |
516 | |
517 | #if !__FINITE_MATH_ONLY__ |
518 | #if __FLT_HAS_QUIET_NAN__ |
519 | template <> |
520 | struct __has_iec559_behavior<__quiet_NaN, float> : true_type {}; |
521 | #endif |
522 | |
523 | #if __DBL_HAS_QUIET_NAN__ |
524 | template <> |
525 | struct __has_iec559_behavior<__quiet_NaN, double> : true_type {}; |
526 | #endif |
527 | |
528 | #if __LDBL_HAS_QUIET_NAN__ |
529 | template <> |
530 | struct __has_iec559_behavior<__quiet_NaN, long double> : true_type {}; |
531 | #endif |
532 | |
533 | #if __FLT_HAS_INFINITY__ |
534 | template <> |
535 | struct __has_iec559_behavior<__infinity, float> : true_type {}; |
536 | #endif |
537 | |
538 | #if __DBL_HAS_INFINITY__ |
539 | template <> |
540 | struct __has_iec559_behavior<__infinity, double> : true_type {}; |
541 | #endif |
542 | |
543 | #if __LDBL_HAS_INFINITY__ |
544 | template <> |
545 | struct __has_iec559_behavior<__infinity, long double> : true_type {}; |
546 | #endif |
547 | |
548 | #ifdef __SUPPORT_SNAN__ |
549 | #if __FLT_HAS_QUIET_NAN__ |
550 | template <> |
551 | struct __has_iec559_behavior<__signaling_NaN, float> : true_type {}; |
552 | #endif |
553 | |
554 | #if __DBL_HAS_QUIET_NAN__ |
555 | template <> |
556 | struct __has_iec559_behavior<__signaling_NaN, double> : true_type {}; |
557 | #endif |
558 | |
559 | #if __LDBL_HAS_QUIET_NAN__ |
560 | template <> |
561 | struct __has_iec559_behavior<__signaling_NaN, long double> : true_type {}; |
562 | #endif |
563 | |
564 | #endif |
565 | #endif // __FINITE_MATH_ONLY__ |
566 | |
567 | } // namespace std |
568 | |