nonfinite_num_facets.hpp 18 KB

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