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