nonfinite_num_facets.hpp 18 KB

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