File indexing completed on 2025-01-30 09:46:08
0001 #ifndef BOOST_MATH_NONFINITE_NUM_FACETS_HPP
0002 #define BOOST_MATH_NONFINITE_NUM_FACETS_HPP
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
0017
0018
0019
0020
0021 #include <cstring>
0022 #include <ios>
0023 #include <limits>
0024 #include <locale>
0025 #include <boost/math/tools/throw_exception.hpp>
0026 #include <boost/math/special_functions/fpclassify.hpp>
0027 #include <boost/math/special_functions/sign.hpp>
0028
0029 #ifdef _MSC_VER
0030 # pragma warning(push)
0031 # pragma warning(disable : 4127)
0032 # pragma warning(disable : 4706)
0033 #endif
0034
0035 namespace boost {
0036 namespace math {
0037
0038
0039
0040 const int legacy = 0x1;
0041 const int signed_zero = 0x2;
0042 const int trap_infinity = 0x4;
0043
0044
0045
0046
0047 const int trap_nan = 0x8;
0048
0049
0050
0051
0052
0053
0054
0055 template<
0056 class CharType,
0057 class OutputIterator = std::ostreambuf_iterator<CharType>
0058 >
0059 class nonfinite_num_put : public std::num_put<CharType, OutputIterator>
0060 {
0061 public:
0062 explicit nonfinite_num_put(int flags = 0) : flags_(flags) {}
0063
0064 protected:
0065 virtual OutputIterator do_put(
0066 OutputIterator it, std::ios_base& iosb, CharType fill, double val) const
0067 {
0068 put_and_reset_width(it, iosb, fill, val);
0069 return it;
0070 }
0071
0072 virtual OutputIterator do_put(
0073 OutputIterator it, std::ios_base& iosb, CharType fill, long double val) const
0074 {
0075 put_and_reset_width(it, iosb, fill, val);
0076 return it;
0077 }
0078
0079 private:
0080 template<class ValType> void put_and_reset_width(
0081 OutputIterator& it, std::ios_base& iosb,
0082 CharType fill, ValType val) const
0083 {
0084 put_impl(it, iosb, fill, val);
0085 iosb.width(0);
0086 }
0087
0088 template<class ValType> void put_impl(
0089 OutputIterator& it, std::ios_base& iosb,
0090 CharType fill, ValType val) const
0091 {
0092 static const CharType prefix_plus[2] = { '+', '\0' };
0093 static const CharType prefix_minus[2] = { '-', '\0' };
0094 static const CharType body_inf[4] = { 'i', 'n', 'f', '\0' };
0095 static const CharType body_nan[4] = { 'n', 'a', 'n', '\0' };
0096 static const CharType* null_string = 0;
0097
0098 switch((boost::math::fpclassify)(val))
0099 {
0100
0101 case FP_INFINITE:
0102 if(flags_ & trap_infinity)
0103 {
0104 BOOST_MATH_THROW_EXCEPTION(std::ios_base::failure("Infinity"));
0105 }
0106 else if((boost::math::signbit)(val))
0107 {
0108 put_num_and_fill(it, iosb, prefix_minus, body_inf, fill, val);
0109 }
0110 else if(iosb.flags() & std::ios_base::showpos)
0111 {
0112 put_num_and_fill(it, iosb, prefix_plus, body_inf, fill, val);
0113 }
0114 else
0115 {
0116 put_num_and_fill(it, iosb, null_string, body_inf, fill, val);
0117 }
0118 break;
0119
0120 case FP_NAN:
0121 if(flags_ & trap_nan)
0122 {
0123 BOOST_MATH_THROW_EXCEPTION(std::ios_base::failure("NaN"));
0124 }
0125 else if((boost::math::signbit)(val))
0126 {
0127 put_num_and_fill(it, iosb, prefix_minus, body_nan, fill, val);
0128 }
0129 else if(iosb.flags() & std::ios_base::showpos)
0130 {
0131 put_num_and_fill(it, iosb, prefix_plus, body_nan, fill, val);
0132 }
0133 else
0134 {
0135 put_num_and_fill(it, iosb, null_string, body_nan, fill, val);
0136 }
0137 break;
0138
0139 case FP_ZERO:
0140 if((flags_ & signed_zero) && ((boost::math::signbit)(val)))
0141 {
0142
0143
0144 std::basic_ostringstream<CharType> zeros;
0145
0146
0147 zeros.flags(iosb.flags());
0148 zeros.unsetf(std::ios::showpos);
0149 zeros.precision(iosb.precision());
0150
0151 zeros.fill(static_cast<char>(fill));
0152 zeros << ValType(0);
0153 put_num_and_fill(it, iosb, prefix_minus, zeros.str().c_str(), fill, val);
0154 }
0155 else
0156 {
0157 put_num_and_fill(it, iosb, null_string, null_string, fill, val);
0158 }
0159 break;
0160
0161 default:
0162 it = std::num_put<CharType, OutputIterator>::do_put(it, iosb, fill, val);
0163 break;
0164 }
0165 }
0166
0167 template<class ValType>
0168 void put_num_and_fill(
0169 OutputIterator& it, std::ios_base& iosb, const CharType* prefix,
0170 const CharType* body, CharType fill, ValType val) const
0171 {
0172 int prefix_length = prefix ? (int)std::char_traits<CharType>::length(prefix) : 0;
0173 int body_length = body ? (int)std::char_traits<CharType>::length(body) : 0;
0174 int width = prefix_length + body_length;
0175 std::ios_base::fmtflags adjust = iosb.flags() & std::ios_base::adjustfield;
0176 const std::ctype<CharType>& ct
0177 = std::use_facet<std::ctype<CharType> >(iosb.getloc());
0178
0179 if(body || prefix)
0180 {
0181 if(adjust != std::ios_base::internal && adjust != std::ios_base::left)
0182 put_fill(it, iosb, fill, width);
0183 }
0184
0185 if(prefix)
0186 {
0187 while(*prefix)
0188 *it = *(prefix++);
0189 iosb.width( iosb.width() - prefix_length );
0190 width -= prefix_length;
0191 }
0192
0193 if(body)
0194 {
0195 if(adjust == std::ios_base::internal)
0196 {
0197 put_fill(it, iosb, fill, width);
0198 }
0199 if(iosb.flags() & std::ios_base::uppercase)
0200 {
0201 while(*body)
0202 *it = ct.toupper(*(body++));
0203 }
0204 else
0205 {
0206 while(*body)
0207 *it = *(body++);
0208 }
0209
0210 if(adjust == std::ios_base::left)
0211 put_fill(it, iosb, fill, width);
0212 }
0213 else
0214 {
0215 it = std::num_put<CharType, OutputIterator>::do_put(it, iosb, fill, val);
0216 }
0217 }
0218
0219 void put_fill(
0220 OutputIterator& it, std::ios_base& iosb, CharType fill, int width) const
0221 {
0222 for(std::streamsize i = iosb.width() - static_cast<std::streamsize>(width); i > 0; --i)
0223 *it = fill;
0224 }
0225
0226 const int flags_;
0227 };
0228
0229
0230
0231
0232 template<
0233 class CharType,
0234 class InputIterator = std::istreambuf_iterator<CharType>
0235 >
0236 class nonfinite_num_get : public std::num_get<CharType, InputIterator>
0237 {
0238
0239 public:
0240 explicit nonfinite_num_get(int flags = 0) : flags_(flags)
0241 {}
0242
0243 protected:
0244 virtual InputIterator do_get(
0245 InputIterator it, InputIterator end, std::ios_base& iosb,
0246 std::ios_base::iostate& state, float& val) const
0247 {
0248 get_and_check_eof(it, end, iosb, state, val);
0249 return it;
0250 }
0251
0252 virtual InputIterator do_get(
0253 InputIterator it, InputIterator end, std::ios_base& iosb,
0254 std::ios_base::iostate& state, double& val) const
0255 {
0256 get_and_check_eof(it, end, iosb, state, val);
0257 return it;
0258 }
0259
0260 virtual InputIterator do_get(
0261 InputIterator it, InputIterator end, std::ios_base& iosb,
0262 std::ios_base::iostate& state, long double& val) const
0263 {
0264 get_and_check_eof(it, end, iosb, state, val);
0265 return it;
0266 }
0267
0268
0269
0270 private:
0271 template<class ValType> static ValType positive_nan()
0272 {
0273
0274 return (boost::math::copysign)(
0275 std::numeric_limits<ValType>::quiet_NaN(), static_cast<ValType>(1)
0276 );
0277
0278 }
0279
0280 template<class ValType> void get_and_check_eof
0281 (
0282 InputIterator& it, InputIterator end, std::ios_base& iosb,
0283 std::ios_base::iostate& state, ValType& val
0284 ) const
0285 {
0286 get_signed(it, end, iosb, state, val);
0287 if(it == end)
0288 state |= std::ios_base::eofbit;
0289 }
0290
0291 template<class ValType> void get_signed
0292 (
0293 InputIterator& it, InputIterator end, std::ios_base& iosb,
0294 std::ios_base::iostate& state, ValType& val
0295 ) const
0296 {
0297 const std::ctype<CharType>& ct
0298 = std::use_facet<std::ctype<CharType> >(iosb.getloc());
0299
0300 char c = peek_char(it, end, ct);
0301
0302 bool negative = (c == '-');
0303
0304 if(negative || c == '+')
0305 {
0306 ++it;
0307 c = peek_char(it, end, ct);
0308 if(c == '-' || c == '+')
0309 {
0310 state |= std::ios_base::failbit;
0311 return;
0312 }
0313 }
0314
0315 get_unsigned(it, end, iosb, ct, state, val);
0316
0317 if(negative)
0318 {
0319 val = (boost::math::changesign)(val);
0320 }
0321 }
0322
0323 template<class ValType> void get_unsigned
0324 (
0325
0326 InputIterator& it, InputIterator end, std::ios_base& iosb,
0327 const std::ctype<CharType>& ct,
0328 std::ios_base::iostate& state, ValType& val
0329 ) const
0330 {
0331 switch(peek_char(it, end, ct))
0332 {
0333 case 'i':
0334 get_i(it, end, ct, state, val);
0335 break;
0336
0337 case 'n':
0338 get_n(it, end, ct, state, val);
0339 break;
0340
0341 case 'q':
0342 case 's':
0343 get_q(it, end, ct, state, val);
0344 break;
0345
0346 default:
0347 it = std::num_get<CharType, InputIterator>::do_get(
0348 it, end, iosb, state, val);
0349 if((flags_ & legacy) && val == static_cast<ValType>(1)
0350 && peek_char(it, end, ct) == '#')
0351 get_one_hash(it, end, ct, state, val);
0352 break;
0353 }
0354 }
0355
0356
0357
0358 template<class ValType> void get_i
0359 (
0360 InputIterator& it, InputIterator end, const std::ctype<CharType>& ct,
0361 std::ios_base::iostate& state, ValType& val
0362 ) const
0363 {
0364 if(!std::numeric_limits<ValType>::has_infinity
0365 || (flags_ & trap_infinity))
0366 {
0367 state |= std::ios_base::failbit;
0368 return;
0369 }
0370
0371 ++it;
0372 if(!match_string(it, end, ct, "nf"))
0373 {
0374 state |= std::ios_base::failbit;
0375 return;
0376 }
0377
0378 if(peek_char(it, end, ct) != 'i')
0379 {
0380 val = std::numeric_limits<ValType>::infinity();
0381 return;
0382 }
0383
0384 ++it;
0385 if(!match_string(it, end, ct, "nity"))
0386 {
0387 state |= std::ios_base::failbit;
0388 return;
0389 }
0390
0391 val = std::numeric_limits<ValType>::infinity();
0392 }
0393
0394 template<class ValType> void get_n
0395 (
0396 InputIterator& it, InputIterator end, const std::ctype<CharType>& ct,
0397 std::ios_base::iostate& state, ValType& val
0398 ) const
0399 {
0400 if(!std::numeric_limits<ValType>::has_quiet_NaN
0401 || (flags_ & trap_nan)) {
0402 state |= std::ios_base::failbit;
0403 return;
0404 }
0405
0406 ++it;
0407 if(!match_string(it, end, ct, "an"))
0408 {
0409 state |= std::ios_base::failbit;
0410 return;
0411 }
0412
0413 switch(peek_char(it, end, ct)) {
0414 case 'q':
0415 case 's':
0416 if(flags_ & legacy)
0417 ++it;
0418 break;
0419
0420 case '(':
0421 {
0422 ++it;
0423 char c;
0424 while((c = peek_char(it, end, ct))
0425 && c != ')' && c != ' ' && c != '\n' && c != '\t')
0426 ++it;
0427 if(c != ')')
0428 {
0429 state |= std::ios_base::failbit;
0430 return;
0431 }
0432 ++it;
0433 break;
0434 }
0435
0436 default:
0437 break;
0438 }
0439
0440 val = positive_nan<ValType>();
0441 }
0442
0443 template<class ValType> void get_q
0444 (
0445 InputIterator& it, InputIterator end, const std::ctype<CharType>& ct,
0446 std::ios_base::iostate& state, ValType& val
0447 ) const
0448 {
0449 if(!std::numeric_limits<ValType>::has_quiet_NaN
0450 || (flags_ & trap_nan) || !(flags_ & legacy))
0451 {
0452 state |= std::ios_base::failbit;
0453 return;
0454 }
0455
0456 ++it;
0457 if(!match_string(it, end, ct, "nan"))
0458 {
0459 state |= std::ios_base::failbit;
0460 return;
0461 }
0462
0463 val = positive_nan<ValType>();
0464 }
0465
0466 template<class ValType> void get_one_hash
0467 (
0468 InputIterator& it, InputIterator end, const std::ctype<CharType>& ct,
0469 std::ios_base::iostate& state, ValType& val
0470 ) const
0471 {
0472
0473 ++it;
0474 switch(peek_char(it, end, ct))
0475 {
0476 case 'i':
0477 get_one_hash_i(it, end, ct, state, val);
0478 return;
0479
0480 case 'q':
0481 case 's':
0482 if(std::numeric_limits<ValType>::has_quiet_NaN
0483 && !(flags_ & trap_nan))
0484 {
0485 ++it;
0486 if(match_string(it, end, ct, "nan"))
0487 {
0488
0489
0490
0491
0492 val = positive_nan<ValType>();
0493 return;
0494 }
0495 }
0496 break;
0497
0498 default:
0499 break;
0500 }
0501
0502 state |= std::ios_base::failbit;
0503 }
0504
0505 template<class ValType> void get_one_hash_i
0506 (
0507 InputIterator& it, InputIterator end, const std::ctype<CharType>& ct,
0508 std::ios_base::iostate& state, ValType& val
0509 ) const
0510 {
0511 ++it;
0512
0513 if(peek_char(it, end, ct) == 'n')
0514 {
0515 ++it;
0516 switch(peek_char(it, end, ct))
0517 {
0518 case 'f':
0519 if(std::numeric_limits<ValType>::has_infinity
0520 && !(flags_ & trap_infinity))
0521 {
0522 ++it;
0523 val = std::numeric_limits<ValType>::infinity();
0524 return;
0525 }
0526 break;
0527
0528 case 'd':
0529 if(std::numeric_limits<ValType>::has_quiet_NaN
0530 && !(flags_ & trap_nan))
0531 {
0532 ++it;
0533 val = positive_nan<ValType>();
0534 return;
0535 }
0536 break;
0537
0538 default:
0539 break;
0540 }
0541 }
0542
0543 state |= std::ios_base::failbit;
0544 }
0545
0546
0547
0548 char peek_char
0549 (
0550 InputIterator& it, InputIterator end,
0551 const std::ctype<CharType>& ct
0552 ) const
0553 {
0554 if(it == end) return 0;
0555 return ct.narrow(ct.tolower(*it), 0);
0556 }
0557
0558 bool match_string
0559 (
0560
0561
0562 InputIterator& it, InputIterator end,
0563 const std::ctype<CharType>& ct,
0564 const char* s
0565 ) const
0566 {
0567 while(it != end && *s && *s == ct.narrow(ct.tolower(*it), 0))
0568 {
0569 ++s;
0570 ++it;
0571 }
0572 return !*s;
0573 }
0574
0575 const int flags_;
0576 };
0577
0578
0579
0580 }
0581 }
0582
0583 #ifdef _MSC_VER
0584 # pragma warning(pop)
0585 #endif
0586
0587 #endif
0588