]> git.proxmox.com Git - ceph.git/blob - ceph/src/boost/libs/math/include/boost/math/special_functions/nonfinite_num_facets.hpp
bump version to 12.2.2-pve1
[ceph.git] / ceph / src / boost / libs / math / include / boost / math / special_functions / nonfinite_num_facets.hpp
1 #ifndef BOOST_MATH_NONFINITE_NUM_FACETS_HPP
2 #define BOOST_MATH_NONFINITE_NUM_FACETS_HPP
3
4 // Copyright 2006 Johan Rade
5 // Copyright 2012 K R Walker
6 // Copyright 2011, 2012 Paul A. Bristow
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 /*
13 \file
14
15 \brief non_finite_num facets for C99 standard output of infinity and NaN.
16
17 \details See fuller documentation at Boost.Math Facets
18 for Floating-Point Infinities and NaNs.
19 */
20
21 #include <cstring>
22 #include <ios>
23 #include <limits>
24 #include <locale>
25
26 #include <boost/version.hpp>
27 #include <boost/throw_exception.hpp>
28
29 #include <boost/math/special_functions/fpclassify.hpp>
30 #include <boost/math/special_functions/sign.hpp>
31
32 #ifdef _MSC_VER
33 # pragma warning(push)
34 # pragma warning(disable : 4127) // conditional expression is constant.
35 # pragma warning(disable : 4706) // assignment within conditional expression.
36 #endif
37
38 namespace boost {
39 namespace math {
40
41 // flags (enums can be ORed together) -----------------------------------
42
43 const int legacy = 0x1; //!< get facet will recognize most string representations of infinity and NaN.
44 const int signed_zero = 0x2; //!< put facet will distinguish between positive and negative zero.
45 const int trap_infinity = 0x4; /*!< put facet will throw an exception of type std::ios_base::failure
46 when an attempt is made to format positive or negative infinity.
47 get will set the fail bit of the stream when an attempt is made
48 to parse a string that represents positive or negative sign infinity.
49 */
50 const int trap_nan = 0x8; /*!< put facet will throw an exception of type std::ios_base::failure
51 when an attempt is made to format positive or negative NaN.
52 get will set the fail bit of the stream when an attempt is made
53 to parse a string that represents positive or negative sign infinity.
54 */
55
56 // class nonfinite_num_put -----------------------------------------------------
57
58 template<
59 class CharType,
60 class OutputIterator = std::ostreambuf_iterator<CharType>
61 >
62 class nonfinite_num_put : public std::num_put<CharType, OutputIterator>
63 {
64 public:
65 explicit nonfinite_num_put(int flags = 0) : flags_(flags) {}
66
67 protected:
68 virtual OutputIterator do_put(
69 OutputIterator it, std::ios_base& iosb, CharType fill, double val) const
70 {
71 put_and_reset_width(it, iosb, fill, val);
72 return it;
73 }
74
75 virtual OutputIterator do_put(
76 OutputIterator it, std::ios_base& iosb, CharType fill, long double val) const
77 {
78 put_and_reset_width(it, iosb, fill, val);
79 return it;
80 }
81
82 private:
83 template<class ValType> void put_and_reset_width(
84 OutputIterator& it, std::ios_base& iosb,
85 CharType fill, ValType val) const
86 {
87 put_impl(it, iosb, fill, val);
88 iosb.width(0);
89 }
90
91 template<class ValType> void put_impl(
92 OutputIterator& it, std::ios_base& iosb,
93 CharType fill, ValType val) const
94 {
95 static const CharType prefix_plus[2] = { '+', '\0' };
96 static const CharType prefix_minus[2] = { '-', '\0' };
97 static const CharType body_inf[4] = { 'i', 'n', 'f', '\0' };
98 static const CharType body_nan[4] = { 'n', 'a', 'n', '\0' };
99 static const CharType* null_string = 0;
100
101 switch((boost::math::fpclassify)(val))
102 {
103
104 case FP_INFINITE:
105 if(flags_ & trap_infinity)
106 {
107 BOOST_THROW_EXCEPTION(std::ios_base::failure("Infinity"));
108 }
109 else if((boost::math::signbit)(val))
110 { // negative infinity.
111 put_num_and_fill(it, iosb, prefix_minus, body_inf, fill, val);
112 }
113 else if(iosb.flags() & std::ios_base::showpos)
114 { // Explicit "+inf" wanted.
115 put_num_and_fill(it, iosb, prefix_plus, body_inf, fill, val);
116 }
117 else
118 { // just "inf" wanted.
119 put_num_and_fill(it, iosb, null_string, body_inf, fill, val);
120 }
121 break;
122
123 case FP_NAN:
124 if(flags_ & trap_nan)
125 {
126 BOOST_THROW_EXCEPTION(std::ios_base::failure("NaN"));
127 }
128 else if((boost::math::signbit)(val))
129 { // negative so "-nan".
130 put_num_and_fill(it, iosb, prefix_minus, body_nan, fill, val);
131 }
132 else if(iosb.flags() & std::ios_base::showpos)
133 { // explicit "+nan" wanted.
134 put_num_and_fill(it, iosb, prefix_plus, body_nan, fill, val);
135 }
136 else
137 { // Just "nan".
138 put_num_and_fill(it, iosb, null_string, body_nan, fill, val);
139 }
140 break;
141
142 case FP_ZERO:
143 if((flags_ & signed_zero) && ((boost::math::signbit)(val)))
144 { // Flag set to distinguish between positive and negative zero.
145 // But string "0" should have stuff after decimal point if setprecision and/or exp format.
146
147 std::basic_ostringstream<CharType> zeros; // Needs to be CharType version.
148
149 // Copy flags, fill, width and precision.
150 zeros.flags(iosb.flags());
151 zeros.unsetf(std::ios::showpos); // Ignore showpos because must be negative.
152 zeros.precision(iosb.precision());
153 //zeros.width is set by put_num_and_fill
154 zeros.fill(static_cast<char>(fill));
155 zeros << ValType(0);
156 put_num_and_fill(it, iosb, prefix_minus, zeros.str().c_str(), fill, val);
157 }
158 else
159 { // Output the platform default for positive and negative zero.
160 put_num_and_fill(it, iosb, null_string, null_string, fill, val);
161 }
162 break;
163
164 default: // Normal non-zero finite value.
165 it = std::num_put<CharType, OutputIterator>::do_put(it, iosb, fill, val);
166 break;
167 }
168 }
169
170 template<class ValType>
171 void put_num_and_fill(
172 OutputIterator& it, std::ios_base& iosb, const CharType* prefix,
173 const CharType* body, CharType fill, ValType val) const
174 {
175 int prefix_length = prefix ? (int)std::char_traits<CharType>::length(prefix) : 0;
176 int body_length = body ? (int)std::char_traits<CharType>::length(body) : 0;
177 int width = prefix_length + body_length;
178 std::ios_base::fmtflags adjust = iosb.flags() & std::ios_base::adjustfield;
179 const std::ctype<CharType>& ct
180 = std::use_facet<std::ctype<CharType> >(iosb.getloc());
181
182 if(body || prefix)
183 { // adjust == std::ios_base::right, so leading fill needed.
184 if(adjust != std::ios_base::internal && adjust != std::ios_base::left)
185 put_fill(it, iosb, fill, width);
186 }
187
188 if(prefix)
189 { // Adjust width for prefix.
190 while(*prefix)
191 *it = *(prefix++);
192 iosb.width( iosb.width() - prefix_length );
193 width -= prefix_length;
194 }
195
196 if(body)
197 { //
198 if(adjust == std::ios_base::internal)
199 { // Put fill between sign and digits.
200 put_fill(it, iosb, fill, width);
201 }
202 if(iosb.flags() & std::ios_base::uppercase)
203 {
204 while(*body)
205 *it = ct.toupper(*(body++));
206 }
207 else
208 {
209 while(*body)
210 *it = *(body++);
211 }
212
213 if(adjust == std::ios_base::left)
214 put_fill(it, iosb, fill, width);
215 }
216 else
217 {
218 it = std::num_put<CharType, OutputIterator>::do_put(it, iosb, fill, val);
219 }
220 }
221
222 void put_fill(
223 OutputIterator& it, std::ios_base& iosb, CharType fill, int width) const
224 { // Insert fill chars.
225 for(std::streamsize i = iosb.width() - static_cast<std::streamsize>(width); i > 0; --i)
226 *it = fill;
227 }
228
229 private:
230 const int flags_;
231 };
232
233
234 // class nonfinite_num_get ------------------------------------------------------
235
236 template<
237 class CharType,
238 class InputIterator = std::istreambuf_iterator<CharType>
239 >
240 class nonfinite_num_get : public std::num_get<CharType, InputIterator>
241 {
242
243 public:
244 explicit nonfinite_num_get(int flags = 0) : flags_(flags)
245 {}
246
247 protected: // float, double and long double versions of do_get.
248 virtual InputIterator do_get(
249 InputIterator it, InputIterator end, std::ios_base& iosb,
250 std::ios_base::iostate& state, float& val) const
251 {
252 get_and_check_eof(it, end, iosb, state, val);
253 return it;
254 }
255
256 virtual InputIterator do_get(
257 InputIterator it, InputIterator end, std::ios_base& iosb,
258 std::ios_base::iostate& state, double& val) const
259 {
260 get_and_check_eof(it, end, iosb, state, val);
261 return it;
262 }
263
264 virtual InputIterator do_get(
265 InputIterator it, InputIterator end, std::ios_base& iosb,
266 std::ios_base::iostate& state, long double& val) const
267 {
268 get_and_check_eof(it, end, iosb, state, val);
269 return it;
270 }
271
272 //..............................................................................
273
274 private:
275 template<class ValType> static ValType positive_nan()
276 {
277 // On some platforms quiet_NaN() may be negative.
278 return (boost::math::copysign)(
279 std::numeric_limits<ValType>::quiet_NaN(), static_cast<ValType>(1)
280 );
281 // static_cast<ValType>(1) added Paul A. Bristow 5 Apr 11
282 }
283
284 template<class ValType> void get_and_check_eof
285 (
286 InputIterator& it, InputIterator end, std::ios_base& iosb,
287 std::ios_base::iostate& state, ValType& val
288 ) const
289 {
290 get_signed(it, end, iosb, state, val);
291 if(it == end)
292 state |= std::ios_base::eofbit;
293 }
294
295 template<class ValType> void get_signed
296 (
297 InputIterator& it, InputIterator end, std::ios_base& iosb,
298 std::ios_base::iostate& state, ValType& val
299 ) const
300 {
301 const std::ctype<CharType>& ct
302 = std::use_facet<std::ctype<CharType> >(iosb.getloc());
303
304 char c = peek_char(it, end, ct);
305
306 bool negative = (c == '-');
307
308 if(negative || c == '+')
309 {
310 ++it;
311 c = peek_char(it, end, ct);
312 if(c == '-' || c == '+')
313 { // Without this check, "++5" etc would be accepted.
314 state |= std::ios_base::failbit;
315 return;
316 }
317 }
318
319 get_unsigned(it, end, iosb, ct, state, val);
320
321 if(negative)
322 {
323 val = (boost::math::changesign)(val);
324 }
325 } // void get_signed
326
327 template<class ValType> void get_unsigned
328 ( //! Get an unsigned floating-point value into val,
329 //! but checking for letters indicating non-finites.
330 InputIterator& it, InputIterator end, std::ios_base& iosb,
331 const std::ctype<CharType>& ct,
332 std::ios_base::iostate& state, ValType& val
333 ) const
334 {
335 switch(peek_char(it, end, ct))
336 {
337 case 'i':
338 get_i(it, end, ct, state, val);
339 break;
340
341 case 'n':
342 get_n(it, end, ct, state, val);
343 break;
344
345 case 'q':
346 case 's':
347 get_q(it, end, ct, state, val);
348 break;
349
350 default: // Got a normal floating-point value into val.
351 it = std::num_get<CharType, InputIterator>::do_get(
352 it, end, iosb, state, val);
353 if((flags_ & legacy) && val == static_cast<ValType>(1)
354 && peek_char(it, end, ct) == '#')
355 get_one_hash(it, end, ct, state, val);
356 break;
357 }
358 } // get_unsigned
359
360 //..........................................................................
361
362 template<class ValType> void get_i
363 ( // Get the rest of all strings starting with 'i', expect "inf", "infinity".
364 InputIterator& it, InputIterator end, const std::ctype<CharType>& ct,
365 std::ios_base::iostate& state, ValType& val
366 ) const
367 {
368 if(!std::numeric_limits<ValType>::has_infinity
369 || (flags_ & trap_infinity))
370 {
371 state |= std::ios_base::failbit;
372 return;
373 }
374
375 ++it;
376 if(!match_string(it, end, ct, "nf"))
377 {
378 state |= std::ios_base::failbit;
379 return;
380 }
381
382 if(peek_char(it, end, ct) != 'i')
383 {
384 val = std::numeric_limits<ValType>::infinity(); // "inf"
385 return;
386 }
387
388 ++it;
389 if(!match_string(it, end, ct, "nity"))
390 { // Expected "infinity"
391 state |= std::ios_base::failbit;
392 return;
393 }
394
395 val = std::numeric_limits<ValType>::infinity(); // "infinity"
396 } // void get_i
397
398 template<class ValType> void get_n
399 ( // Get expected strings after 'n', "nan", "nanq", "nans", "nan(...)"
400 InputIterator& it, InputIterator end, const std::ctype<CharType>& ct,
401 std::ios_base::iostate& state, ValType& val
402 ) const
403 {
404 if(!std::numeric_limits<ValType>::has_quiet_NaN
405 || (flags_ & trap_nan)) {
406 state |= std::ios_base::failbit;
407 return;
408 }
409
410 ++it;
411 if(!match_string(it, end, ct, "an"))
412 {
413 state |= std::ios_base::failbit;
414 return;
415 }
416
417 switch(peek_char(it, end, ct)) {
418 case 'q':
419 case 's':
420 if(flags_ && legacy)
421 ++it;
422 break; // "nanq", "nans"
423
424 case '(': // Optional payload field in (...) follows.
425 {
426 ++it;
427 char c;
428 while((c = peek_char(it, end, ct))
429 && c != ')' && c != ' ' && c != '\n' && c != '\t')
430 ++it;
431 if(c != ')')
432 { // Optional payload field terminator missing!
433 state |= std::ios_base::failbit;
434 return;
435 }
436 ++it;
437 break; // "nan(...)"
438 }
439
440 default:
441 break; // "nan"
442 }
443
444 val = positive_nan<ValType>();
445 } // void get_n
446
447 template<class ValType> void get_q
448 ( // Get expected rest of string starting with 'q': "qnan".
449 InputIterator& it, InputIterator end, const std::ctype<CharType>& ct,
450 std::ios_base::iostate& state, ValType& val
451 ) const
452 {
453 if(!std::numeric_limits<ValType>::has_quiet_NaN
454 || (flags_ & trap_nan) || !(flags_ & legacy))
455 {
456 state |= std::ios_base::failbit;
457 return;
458 }
459
460 ++it;
461 if(!match_string(it, end, ct, "nan"))
462 {
463 state |= std::ios_base::failbit;
464 return;
465 }
466
467 val = positive_nan<ValType>(); // "QNAN"
468 } // void get_q
469
470 template<class ValType> void get_one_hash
471 ( // Get expected string after having read "1.#": "1.#IND", "1.#QNAN", "1.#SNAN".
472 InputIterator& it, InputIterator end, const std::ctype<CharType>& ct,
473 std::ios_base::iostate& state, ValType& val
474 ) const
475 {
476
477 ++it;
478 switch(peek_char(it, end, ct))
479 {
480 case 'i': // from IND (indeterminate), considered same a QNAN.
481 get_one_hash_i(it, end, ct, state, val); // "1.#IND"
482 return;
483
484 case 'q': // from QNAN
485 case 's': // from SNAN - treated the same as QNAN.
486 if(std::numeric_limits<ValType>::has_quiet_NaN
487 && !(flags_ & trap_nan))
488 {
489 ++it;
490 if(match_string(it, end, ct, "nan"))
491 { // "1.#QNAN", "1.#SNAN"
492 // ++it; // removed as caused assert() cannot increment iterator).
493 // (match_string consumes string, so not needed?).
494 // https://svn.boost.org/trac/boost/ticket/5467
495 // Change in nonfinite_num_facet.hpp Paul A. Bristow 11 Apr 11 makes legacy_test.cpp work OK.
496 val = positive_nan<ValType>(); // "1.#QNAN"
497 return;
498 }
499 }
500 break;
501
502 default:
503 break;
504 }
505
506 state |= std::ios_base::failbit;
507 } // void get_one_hash
508
509 template<class ValType> void get_one_hash_i
510 ( // Get expected strings after 'i', "1.#INF", 1.#IND".
511 InputIterator& it, InputIterator end, const std::ctype<CharType>& ct,
512 std::ios_base::iostate& state, ValType& val
513 ) const
514 {
515 ++it;
516
517 if(peek_char(it, end, ct) == 'n')
518 {
519 ++it;
520 switch(peek_char(it, end, ct))
521 {
522 case 'f': // "1.#INF"
523 if(std::numeric_limits<ValType>::has_infinity
524 && !(flags_ & trap_infinity))
525 {
526 ++it;
527 val = std::numeric_limits<ValType>::infinity();
528 return;
529 }
530 break;
531
532 case 'd': // 1.#IND"
533 if(std::numeric_limits<ValType>::has_quiet_NaN
534 && !(flags_ & trap_nan))
535 {
536 ++it;
537 val = positive_nan<ValType>();
538 return;
539 }
540 break;
541
542 default:
543 break;
544 }
545 }
546
547 state |= std::ios_base::failbit;
548 } // void get_one_hash_i
549
550 //..........................................................................
551
552 char peek_char
553 ( //! \return next char in the input buffer, ensuring lowercase (but do not 'consume' char).
554 InputIterator& it, InputIterator end,
555 const std::ctype<CharType>& ct
556 ) const
557 {
558 if(it == end) return 0;
559 return ct.narrow(ct.tolower(*it), 0); // Always tolower to ensure case insensitive.
560 }
561
562 bool match_string
563 ( //! Match remaining chars to expected string (case insensitive),
564 //! consuming chars that match OK.
565 //! \return true if matched expected string, else false.
566 InputIterator& it, InputIterator end,
567 const std::ctype<CharType>& ct,
568 const char* s
569 ) const
570 {
571 while(it != end && *s && *s == ct.narrow(ct.tolower(*it), 0))
572 {
573 ++s;
574 ++it; //
575 }
576 return !*s;
577 } // bool match_string
578
579 private:
580 const int flags_;
581 }; //
582
583 //------------------------------------------------------------------------------
584
585 } // namespace math
586 } // namespace boost
587
588 #ifdef _MSC_VER
589 # pragma warning(pop)
590 #endif
591
592 #endif // BOOST_MATH_NONFINITE_NUM_FACETS_HPP
593