]> git.proxmox.com Git - ceph.git/blob - ceph/src/boost/libs/spirit/include/boost/spirit/home/support/detail/math/detail/fp_traits.hpp
bump version to 12.2.2-pve1
[ceph.git] / ceph / src / boost / libs / spirit / include / boost / spirit / home / support / detail / math / detail / fp_traits.hpp
1 // fp_traits.hpp
2
3 #ifndef BOOST_SPIRIT_MATH_FP_TRAITS_HPP
4 #define BOOST_SPIRIT_MATH_FP_TRAITS_HPP
5
6 // Copyright (c) 2006 Johan Rade
7
8 // Distributed under the Boost Software License, Version 1.0.
9 // (See accompanying file LICENSE_1_0.txt
10 // or copy at http://www.boost.org/LICENSE_1_0.txt)
11
12 #if defined(__vms) && defined(__DECCXX) && !__IEEE_FLOAT
13 # error The VAX floating point mode on VMS is not supported.
14 #endif
15
16 #if defined(_MSC_VER)
17 #pragma once
18 #endif
19
20 #include <cstring>
21
22 #include <boost/assert.hpp>
23 #include <boost/cstdint.hpp>
24 #include <boost/detail/endian.hpp>
25 #include <boost/static_assert.hpp>
26 #include <boost/type_traits/is_floating_point.hpp>
27
28 //------------------------------------------------------------------------------
29
30 namespace boost {
31 namespace spirit {
32 namespace math {
33 namespace detail {
34
35 //------------------------------------------------------------------------------
36
37 /*
38 Most processors support three different floating point precisions:
39 single precision (32 bits), double precision (64 bits)
40 and extended double precision (>64 bits)
41
42 Note that the C++ type long double can be implemented
43 both as double precision and extended double precision.
44 */
45
46 struct single_precision_tag {};
47 struct double_precision_tag {};
48 struct extended_double_precision_tag {};
49
50 //------------------------------------------------------------------------------
51
52 /*
53 template<class T, class U> struct fp_traits_impl;
54
55 This is traits class that describes the binary structure of floating
56 point numbers of C++ type T and precision U
57
58 Requirements:
59
60 T = float, double or long double
61 U = single_precision_tag, double_precision_tag
62 or extended_double_precision_tag
63
64 Typedef members:
65
66 bits -- the target type when copying the leading bytes of a floating
67 point number. It is a typedef for uint32_t or uint64_t.
68
69 coverage -- tells us whether all bytes are copied or not.
70 It is a typedef for all_bits or not_all_bits.
71
72 Static data members:
73
74 sign, exponent, flag, mantissa -- bit masks that give the meaning of the bits
75 in the leading bytes.
76
77 Static function members:
78
79 init() -- initializes the static data members, if needed.
80 (Is a no-op in the specialized versions of the template.)
81
82 get_bits(), set_bits() -- provide access to the leading bytes.
83 */
84
85 struct all_bits {};
86 struct not_all_bits {};
87
88 // Generic version -------------------------------------------------------------
89
90 // The generic version uses run time initialization to determine the floating
91 // point format. It is capable of handling most formats,
92 // but not the Motorola 68K extended double precision format.
93
94 // Currently the generic version is used only for extended double precision
95 // on Itanium. In all other cases there are specializations of the template
96 // that use compile time initialization.
97
98 template<class T> struct uint32_t_coverage
99 {
100 typedef not_all_bits type;
101 };
102
103 template<> struct uint32_t_coverage<single_precision_tag>
104 {
105 typedef all_bits type;
106 };
107
108 template<class T, class U> struct fp_traits_impl
109 {
110 typedef uint32_t bits;
111 typedef BOOST_DEDUCED_TYPENAME uint32_t_coverage<U>::type coverage;
112
113 BOOST_STATIC_CONSTANT(uint32_t, sign = 0x80000000);
114 static uint32_t exponent;
115 static uint32_t flag;
116 static uint32_t mantissa;
117
118 static void init()
119 {
120 if(is_init_) return;
121 do_init_();
122 is_init_ = true;
123 }
124
125 static void get_bits(T x, uint32_t& a)
126 {
127 memcpy(&a, reinterpret_cast<const unsigned char*>(&x) + offset_, 4);
128 }
129
130 static void set_bits(T& x, uint32_t a)
131 {
132 memcpy(reinterpret_cast<unsigned char*>(&x) + offset_, &a, 4);
133 }
134
135 private:
136 static size_t offset_;
137 static bool is_init_;
138 static void do_init_();
139 };
140
141 //..............................................................................
142
143 template<class T, class U> uint32_t fp_traits_impl<T,U>::exponent;
144 template<class T, class U> uint32_t fp_traits_impl<T,U>::flag;
145 template<class T, class U> uint32_t fp_traits_impl<T,U>::mantissa;
146 template<class T, class U> size_t fp_traits_impl<T,U>::offset_;
147 template<class T, class U> bool fp_traits_impl<T,U>::is_init_;
148
149 // In a single-threaded program, do_init will be called exactly once.
150 // In a multi-threaded program, do_init may be called simultaneously
151 // by more then one thread. That should not be a problem.
152
153 //..............................................................................
154
155 template<class T, class U> void fp_traits_impl<T,U>::do_init_()
156 {
157 T x = static_cast<T>(3) / static_cast<T>(4);
158 // sign bit = 0
159 // exponent: first and last bit = 0, all other bits = 1
160 // flag bit (if present) = 1
161 // mantissa: first bit = 1, all other bits = 0
162
163 uint32_t a;
164
165 for(size_t k = 0; k <= sizeof(T) - 4; ++k) {
166
167 memcpy(&a, reinterpret_cast<unsigned char*>(&x) + k, 4);
168
169 switch(a) {
170
171 case 0x3f400000: // IEEE single precision format
172
173 offset_ = k;
174 exponent = 0x7f800000;
175 flag = 0x00000000;
176 mantissa = 0x007fffff;
177 return;
178
179 case 0x3fe80000: // IEEE double precision format
180 // and PowerPC extended double precision format
181 offset_ = k;
182 exponent = 0x7ff00000;
183 flag = 0x00000000;
184 mantissa = 0x000fffff;
185 return;
186
187 case 0x3ffe0000: // Motorola extended double precision format
188
189 // Must not get here. Must be handled by specialization.
190 // To get accurate cutoff between normals and subnormals
191 // we must use the flag bit that is in the 5th byte.
192 // Otherwise this cutoff will be off by a factor 2.
193 // If we do get here, then we have failed to detect the Motorola
194 // processor at compile time.
195
196 BOOST_ASSERT(false &&
197 "Failed to detect the Motorola processor at compile time");
198 return;
199
200 case 0x3ffe8000: // IEEE extended double precision format
201 // with 15 exponent bits
202 offset_ = k;
203 exponent = 0x7fff0000;
204 flag = 0x00000000;
205 mantissa = 0x0000ffff;
206 return;
207
208 case 0x3ffec000: // Intel extended double precision format
209
210 offset_ = k;
211 exponent = 0x7fff0000;
212 flag = 0x00008000;
213 mantissa = 0x00007fff;
214 return;
215
216 default:
217 continue;
218 }
219 }
220
221 BOOST_ASSERT(false);
222
223 // Unknown format.
224 }
225
226
227 // float (32 bits) -------------------------------------------------------------
228
229 template<> struct fp_traits_impl<float, single_precision_tag>
230 {
231 typedef uint32_t bits;
232 typedef all_bits coverage;
233
234 BOOST_STATIC_CONSTANT(uint32_t, sign = 0x80000000);
235 BOOST_STATIC_CONSTANT(uint32_t, exponent = 0x7f800000);
236 BOOST_STATIC_CONSTANT(uint32_t, flag = 0x00000000);
237 BOOST_STATIC_CONSTANT(uint32_t, mantissa = 0x007fffff);
238
239 static void init() {}
240 static void get_bits(float x, uint32_t& a) { memcpy(&a, &x, 4); }
241 static void set_bits(float& x, uint32_t a) { memcpy(&x, &a, 4); }
242 };
243
244
245 // double (64 bits) ------------------------------------------------------------
246
247 #if defined(BOOST_NO_INT64_T) || defined(BOOST_NO_INCLASS_MEMBER_INITIALIZATION)
248
249 template<> struct fp_traits_impl<double, double_precision_tag>
250 {
251 typedef uint32_t bits;
252 typedef not_all_bits coverage;
253
254 BOOST_STATIC_CONSTANT(uint32_t, sign = 0x80000000);
255 BOOST_STATIC_CONSTANT(uint32_t, exponent = 0x7ff00000);
256 BOOST_STATIC_CONSTANT(uint32_t, flag = 0);
257 BOOST_STATIC_CONSTANT(uint32_t, mantissa = 0x000fffff);
258
259 static void init() {}
260
261 static void get_bits(double x, uint32_t& a)
262 {
263 memcpy(&a, reinterpret_cast<const unsigned char*>(&x) + offset_, 4);
264 }
265
266 static void set_bits(double& x, uint32_t a)
267 {
268 memcpy(reinterpret_cast<unsigned char*>(&x) + offset_, &a, 4);
269 }
270
271 private:
272
273 #if defined(BOOST_BIG_ENDIAN)
274 BOOST_STATIC_CONSTANT(int, offset_ = 0);
275 #elif defined(BOOST_LITTLE_ENDIAN)
276 BOOST_STATIC_CONSTANT(int, offset_ = 4);
277 #else
278 BOOST_STATIC_ASSERT(false);
279 #endif
280 };
281
282 //..............................................................................
283
284 #else
285
286 template<> struct fp_traits_impl<double, double_precision_tag>
287 {
288 typedef uint64_t bits;
289 typedef all_bits coverage;
290
291 static const uint64_t sign = (uint64_t)0x80000000 << 32;
292 static const uint64_t exponent = (uint64_t)0x7ff00000 << 32;
293 static const uint64_t flag = 0;
294 static const uint64_t mantissa
295 = ((uint64_t)0x000fffff << 32) + (uint64_t)0xffffffff;
296
297 static void init() {}
298 static void get_bits(double x, uint64_t& a) { memcpy(&a, &x, 8); }
299 static void set_bits(double& x, uint64_t a) { memcpy(&x, &a, 8); }
300 };
301
302 #endif
303
304
305 // long double (64 bits) -------------------------------------------------------
306
307 #if defined(BOOST_NO_INT64_T) || defined(BOOST_NO_INCLASS_MEMBER_INITIALIZATION)
308
309 template<> struct fp_traits_impl<long double, double_precision_tag>
310 {
311 typedef uint32_t bits;
312 typedef not_all_bits coverage;
313
314 BOOST_STATIC_CONSTANT(uint32_t, sign = 0x80000000);
315 BOOST_STATIC_CONSTANT(uint32_t, exponent = 0x7ff00000);
316 BOOST_STATIC_CONSTANT(uint32_t, flag = 0);
317 BOOST_STATIC_CONSTANT(uint32_t, mantissa = 0x000fffff);
318
319 static void init() {}
320
321 static void get_bits(long double x, uint32_t& a)
322 {
323 memcpy(&a, reinterpret_cast<const unsigned char*>(&x) + offset_, 4);
324 }
325
326 static void set_bits(long double& x, uint32_t a)
327 {
328 memcpy(reinterpret_cast<unsigned char*>(&x) + offset_, &a, 4);
329 }
330
331 private:
332
333 #if defined(BOOST_BIG_ENDIAN)
334 BOOST_STATIC_CONSTANT(int, offset_ = 0);
335 #elif defined(BOOST_LITTLE_ENDIAN)
336 BOOST_STATIC_CONSTANT(int, offset_ = 4);
337 #else
338 BOOST_STATIC_ASSERT(false);
339 #endif
340 };
341
342 //..............................................................................
343
344 #else
345
346 template<> struct fp_traits_impl<long double, double_precision_tag>
347 {
348 typedef uint64_t bits;
349 typedef all_bits coverage;
350
351 static const uint64_t sign = (uint64_t)0x80000000 << 32;
352 static const uint64_t exponent = (uint64_t)0x7ff00000 << 32;
353 static const uint64_t flag = 0;
354 static const uint64_t mantissa
355 = ((uint64_t)0x000fffff << 32) + (uint64_t)0xffffffff;
356
357 static void init() {}
358 static void get_bits(long double x, uint64_t& a) { memcpy(&a, &x, 8); }
359 static void set_bits(long double& x, uint64_t a) { memcpy(&x, &a, 8); }
360 };
361
362 #endif
363
364
365 // long double (>64 bits), x86 and x64 -----------------------------------------
366
367 #if defined(__i386) || defined(__i386__) || defined(_M_IX86) \
368 || defined(__amd64) || defined(__amd64__) || defined(_M_AMD64) \
369 || defined(__x86_64) || defined(__x86_64__) || defined(_M_X64)
370
371 // Intel extended double precision format (80 bits)
372
373 template<> struct fp_traits_impl<long double, extended_double_precision_tag>
374 {
375 typedef uint32_t bits;
376 typedef not_all_bits coverage;
377
378 BOOST_STATIC_CONSTANT(uint32_t, sign = 0x80000000);
379 BOOST_STATIC_CONSTANT(uint32_t, exponent = 0x7fff0000);
380 BOOST_STATIC_CONSTANT(uint32_t, flag = 0x00008000);
381 BOOST_STATIC_CONSTANT(uint32_t, mantissa = 0x00007fff);
382
383 static void init() {}
384
385 static void get_bits(long double x, uint32_t& a)
386 {
387 memcpy(&a, reinterpret_cast<const unsigned char*>(&x) + 6, 4);
388 }
389
390 static void set_bits(long double& x, uint32_t a)
391 {
392 memcpy(reinterpret_cast<unsigned char*>(&x) + 6, &a, 4);
393 }
394 };
395
396
397 // long double (>64 bits), Itanium ---------------------------------------------
398
399 #elif defined(__ia64) || defined(__ia64__) || defined(_M_IA64)
400
401 // The floating point format is unknown at compile time
402 // No template specialization is provided.
403 // The generic definition is used.
404
405 // The Itanium supports both
406 // the Intel extended double precision format (80 bits) and
407 // the IEEE extended double precision format with 15 exponent bits (128 bits).
408
409
410 // long double (>64 bits), PowerPC ---------------------------------------------
411
412 #elif defined(__powerpc) || defined(__powerpc__) || defined(__POWERPC__) \
413 || defined(__ppc) || defined(__ppc__) || defined(__PPC__)
414
415 // PowerPC extended double precision format (128 bits)
416
417 template<> struct fp_traits_impl<long double, extended_double_precision_tag>
418 {
419 typedef uint32_t bits;
420 typedef not_all_bits coverage;
421
422 BOOST_STATIC_CONSTANT(uint32_t, sign = 0x80000000);
423 BOOST_STATIC_CONSTANT(uint32_t, exponent = 0x7ff00000);
424 BOOST_STATIC_CONSTANT(uint32_t, flag = 0x00000000);
425 BOOST_STATIC_CONSTANT(uint32_t, mantissa = 0x000fffff);
426
427 static void init() {}
428
429 static void get_bits(long double x, uint32_t& a)
430 {
431 memcpy(&a, reinterpret_cast<const unsigned char*>(&x) + offset_, 4);
432 }
433
434 static void set_bits(long double& x, uint32_t a)
435 {
436 memcpy(reinterpret_cast<unsigned char*>(&x) + offset_, &a, 4);
437 }
438
439 private:
440
441 #if defined(BOOST_BIG_ENDIAN)
442 BOOST_STATIC_CONSTANT(int, offset_ = 0);
443 #elif defined(BOOST_LITTLE_ENDIAN)
444 BOOST_STATIC_CONSTANT(int, offset_ = 12);
445 #else
446 BOOST_STATIC_ASSERT(false);
447 #endif
448 };
449
450
451 // long double (>64 bits), Motorola 68K ----------------------------------------
452
453 #elif defined(__m68k) || defined(__m68k__) \
454 || defined(__mc68000) || defined(__mc68000__) \
455
456 // Motorola extended double precision format (96 bits)
457
458 // It is the same format as the Intel extended double precision format,
459 // except that 1) it is big-endian, 2) the 3rd and 4th byte are padding, and
460 // 3) the flag bit is not set for infinity
461
462 template<> struct fp_traits_impl<long double, extended_double_precision_tag>
463 {
464 typedef uint32_t bits;
465 typedef not_all_bits coverage;
466
467 BOOST_STATIC_CONSTANT(uint32_t, sign = 0x80000000);
468 BOOST_STATIC_CONSTANT(uint32_t, exponent = 0x7fff0000);
469 BOOST_STATIC_CONSTANT(uint32_t, flag = 0x00008000);
470 BOOST_STATIC_CONSTANT(uint32_t, mantissa = 0x00007fff);
471
472 static void init() {}
473
474 // copy 1st, 2nd, 5th and 6th byte. 3rd and 4th byte are padding.
475
476 static void get_bits(long double x, uint32_t& a)
477 {
478 memcpy(&a, &x, 2);
479 memcpy(reinterpret_cast<unsigned char*>(&a) + 2,
480 reinterpret_cast<const unsigned char*>(&x) + 4, 2);
481 }
482
483 static void set_bits(long double& x, uint32_t a)
484 {
485 memcpy(&x, &a, 2);
486 memcpy(reinterpret_cast<unsigned char*>(&x) + 4,
487 reinterpret_cast<const unsigned char*>(&a) + 2, 2);
488 }
489 };
490
491
492 // long double (>64 bits), All other processors --------------------------------
493
494 #else
495
496 // IEEE extended double precision format with 15 exponent bits (128 bits)
497
498 template<> struct fp_traits_impl<long double, extended_double_precision_tag>
499 {
500 typedef uint32_t bits;
501 typedef not_all_bits coverage;
502
503 BOOST_STATIC_CONSTANT(uint32_t, sign = 0x80000000);
504 BOOST_STATIC_CONSTANT(uint32_t, exponent = 0x7fff0000);
505 BOOST_STATIC_CONSTANT(uint32_t, flag = 0x00000000);
506 BOOST_STATIC_CONSTANT(uint32_t, mantissa = 0x0000ffff);
507
508 static void init() {}
509
510 static void get_bits(long double x, uint32_t& a)
511 {
512 memcpy(&a, reinterpret_cast<const unsigned char*>(&x) + offset_, 4);
513 }
514
515 static void set_bits(long double& x, uint32_t a)
516 {
517 memcpy(reinterpret_cast<unsigned char*>(&x) + offset_, &a, 4);
518 }
519
520 private:
521
522 #if defined(BOOST_BIG_ENDIAN)
523 BOOST_STATIC_CONSTANT(int, offset_ = 0);
524 #elif defined(BOOST_LITTLE_ENDIAN)
525 BOOST_STATIC_CONSTANT(int, offset_ = 12);
526 #else
527 BOOST_STATIC_ASSERT(false);
528 #endif
529 };
530
531 #endif
532
533
534 //------------------------------------------------------------------------------
535
536 // size_to_precision is a type switch for converting a C++ floating point type
537 // to the corresponding precision type.
538
539 template<int n> struct size_to_precision;
540
541 template<> struct size_to_precision<4>
542 {
543 typedef single_precision_tag type;
544 };
545
546 template<> struct size_to_precision<8>
547 {
548 typedef double_precision_tag type;
549 };
550
551 template<> struct size_to_precision<10>
552 {
553 typedef extended_double_precision_tag type;
554 };
555
556 template<> struct size_to_precision<12>
557 {
558 typedef extended_double_precision_tag type;
559 };
560
561 template<> struct size_to_precision<16>
562 {
563 typedef extended_double_precision_tag type;
564 };
565
566 // fp_traits is a type switch that selects the right fp_traits_impl
567
568 template<class T> struct fp_traits
569 {
570 BOOST_STATIC_ASSERT(boost::is_floating_point<T>::value);
571 typedef BOOST_DEDUCED_TYPENAME size_to_precision<sizeof(T)>::type precision;
572 typedef fp_traits_impl<T, precision> type;
573 };
574
575
576 //------------------------------------------------------------------------------
577
578 } // namespace detail
579 } // namespace math
580 } // namespace spirit
581 } // namespace boost
582
583 #endif