/Src/Dependencies/Boost/boost/spirit/home/classic/core/primitives/impl/numerics.ipp

http://hadesmem.googlecode.com/ · C++ Header · 478 lines · 323 code · 55 blank · 100 comment · 41 complexity · 6304de337af2e304c58d6562e06aa5c4 MD5 · raw file

  1. /*=============================================================================
  2. Copyright (c) 1998-2003 Joel de Guzman
  3. Copyright (c) 2001-2003 Hartmut Kaiser
  4. http://spirit.sourceforge.net/
  5. Use, modification and distribution is subject to the Boost Software
  6. License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
  7. http://www.boost.org/LICENSE_1_0.txt)
  8. =============================================================================*/
  9. #ifndef BOOST_SPIRIT_NUMERICS_IPP
  10. #define BOOST_SPIRIT_NUMERICS_IPP
  11. #include <boost/config/no_tr1/cmath.hpp>
  12. #include <limits>
  13. namespace boost { namespace spirit {
  14. BOOST_SPIRIT_CLASSIC_NAMESPACE_BEGIN
  15. struct sign_parser; // forward declaration only
  16. namespace impl
  17. {
  18. ///////////////////////////////////////////////////////////////////////
  19. //
  20. // Extract the prefix sign (- or +)
  21. //
  22. ///////////////////////////////////////////////////////////////////////
  23. template <typename ScannerT>
  24. bool
  25. extract_sign(ScannerT const& scan, std::size_t& count)
  26. {
  27. // Extract the sign
  28. count = 0;
  29. bool neg = *scan == '-';
  30. if (neg || (*scan == '+'))
  31. {
  32. ++scan;
  33. ++count;
  34. return neg;
  35. }
  36. return false;
  37. }
  38. ///////////////////////////////////////////////////////////////////////
  39. //
  40. // Traits class for radix specific number conversion
  41. //
  42. // Convert a digit from character representation, ch, to binary
  43. // representation, returned in val.
  44. // Returns whether the conversion was successful.
  45. //
  46. // template<typename CharT> static bool digit(CharT ch, T& val);
  47. //
  48. ///////////////////////////////////////////////////////////////////////
  49. template<const int Radix>
  50. struct radix_traits;
  51. ////////////////////////////////// Binary
  52. template<>
  53. struct radix_traits<2>
  54. {
  55. template<typename CharT, typename T>
  56. static bool digit(CharT ch, T& val)
  57. {
  58. val = ch - '0';
  59. return ('0' == ch || '1' == ch);
  60. }
  61. };
  62. ////////////////////////////////// Octal
  63. template<>
  64. struct radix_traits<8>
  65. {
  66. template<typename CharT, typename T>
  67. static bool digit(CharT ch, T& val)
  68. {
  69. val = ch - '0';
  70. return ('0' <= ch && ch <= '7');
  71. }
  72. };
  73. ////////////////////////////////// Decimal
  74. template<>
  75. struct radix_traits<10>
  76. {
  77. template<typename CharT, typename T>
  78. static bool digit(CharT ch, T& val)
  79. {
  80. val = ch - '0';
  81. return impl::isdigit_(ch);
  82. }
  83. };
  84. ////////////////////////////////// Hexadecimal
  85. template<>
  86. struct radix_traits<16>
  87. {
  88. template<typename CharT, typename T>
  89. static bool digit(CharT ch, T& val)
  90. {
  91. if (radix_traits<10>::digit(ch, val))
  92. return true;
  93. CharT lc = impl::tolower_(ch);
  94. if ('a' <= lc && lc <= 'f')
  95. {
  96. val = lc - 'a' + 10;
  97. return true;
  98. }
  99. return false;
  100. }
  101. };
  102. ///////////////////////////////////////////////////////////////////////
  103. //
  104. // Helper templates for encapsulation of radix specific
  105. // conversion of an input string to an integral value.
  106. //
  107. // main entry point:
  108. //
  109. // extract_int<Radix, MinDigits, MaxDigits, Accumulate>
  110. // ::f(first, last, n, count);
  111. //
  112. // The template parameter Radix represents the radix of the
  113. // number contained in the parsed string. The template
  114. // parameter MinDigits specifies the minimum digits to
  115. // accept. The template parameter MaxDigits specifies the
  116. // maximum digits to parse. A -1 value for MaxDigits will
  117. // make it parse an arbitrarilly large number as long as the
  118. // numeric type can hold it. Accumulate is either
  119. // positive_accumulate<Radix> (default) for parsing positive
  120. // numbers or negative_accumulate<Radix> otherwise.
  121. // Checking is only performed when std::numeric_limits<T>::
  122. // is_specialized is true. Otherwise, there's no way to
  123. // do the check.
  124. //
  125. // scan.first and scan.last are iterators as usual (i.e.
  126. // first is mutable and is moved forward when a match is
  127. // found), n is a variable that holds the number (passed by
  128. // reference). The number of parsed characters is added to
  129. // count (also passed by reference)
  130. //
  131. // NOTE:
  132. // Returns a non-match, if the number to parse
  133. // overflows (or underflows) the used type.
  134. //
  135. // BEWARE:
  136. // the parameters 'n' and 'count' should be properly
  137. // initialized before calling this function.
  138. //
  139. ///////////////////////////////////////////////////////////////////////
  140. #if defined(BOOST_MSVC)
  141. #pragma warning(push)
  142. #pragma warning(disable:4127) //conditional expression is constant
  143. #endif
  144. template <typename T, int Radix>
  145. struct positive_accumulate
  146. {
  147. // Use this accumulator if number is positive
  148. static bool add(T& n, T digit)
  149. {
  150. if (std::numeric_limits<T>::is_specialized)
  151. {
  152. static T const max = (std::numeric_limits<T>::max)();
  153. static T const max_div_radix = max/Radix;
  154. if (n > max_div_radix)
  155. return false;
  156. n *= Radix;
  157. if (n > max - digit)
  158. return false;
  159. n += digit;
  160. return true;
  161. }
  162. else
  163. {
  164. n *= Radix;
  165. n += digit;
  166. return true;
  167. }
  168. }
  169. };
  170. template <typename T, int Radix>
  171. struct negative_accumulate
  172. {
  173. // Use this accumulator if number is negative
  174. static bool add(T& n, T digit)
  175. {
  176. if (std::numeric_limits<T>::is_specialized)
  177. {
  178. typedef std::numeric_limits<T> num_limits;
  179. static T const min =
  180. (!num_limits::is_integer && num_limits::is_signed && num_limits::has_denorm) ?
  181. -(num_limits::max)() : (num_limits::min)();
  182. static T const min_div_radix = min/Radix;
  183. if (n < min_div_radix)
  184. return false;
  185. n *= Radix;
  186. if (n < min + digit)
  187. return false;
  188. n -= digit;
  189. return true;
  190. }
  191. else
  192. {
  193. n *= Radix;
  194. n -= digit;
  195. return true;
  196. }
  197. }
  198. };
  199. template <int MaxDigits>
  200. inline bool allow_more_digits(std::size_t i)
  201. {
  202. return i < MaxDigits;
  203. }
  204. template <>
  205. inline bool allow_more_digits<-1>(std::size_t)
  206. {
  207. return true;
  208. }
  209. //////////////////////////////////
  210. template <
  211. int Radix, unsigned MinDigits, int MaxDigits,
  212. typename Accumulate
  213. >
  214. struct extract_int
  215. {
  216. template <typename ScannerT, typename T>
  217. static bool
  218. f(ScannerT& scan, T& n, std::size_t& count)
  219. {
  220. std::size_t i = 0;
  221. T digit;
  222. while( allow_more_digits<MaxDigits>(i) && !scan.at_end() &&
  223. radix_traits<Radix>::digit(*scan, digit) )
  224. {
  225. if (!Accumulate::add(n, digit))
  226. return false; // Overflow
  227. ++i, ++scan, ++count;
  228. }
  229. return i >= MinDigits;
  230. }
  231. };
  232. ///////////////////////////////////////////////////////////////////////
  233. //
  234. // uint_parser_impl class
  235. //
  236. ///////////////////////////////////////////////////////////////////////
  237. template <
  238. typename T = unsigned,
  239. int Radix = 10,
  240. unsigned MinDigits = 1,
  241. int MaxDigits = -1
  242. >
  243. struct uint_parser_impl
  244. : parser<uint_parser_impl<T, Radix, MinDigits, MaxDigits> >
  245. {
  246. typedef uint_parser_impl<T, Radix, MinDigits, MaxDigits> self_t;
  247. template <typename ScannerT>
  248. struct result
  249. {
  250. typedef typename match_result<ScannerT, T>::type type;
  251. };
  252. template <typename ScannerT>
  253. typename parser_result<self_t, ScannerT>::type
  254. parse(ScannerT const& scan) const
  255. {
  256. if (!scan.at_end())
  257. {
  258. T n = 0;
  259. std::size_t count = 0;
  260. typename ScannerT::iterator_t save = scan.first;
  261. if (extract_int<Radix, MinDigits, MaxDigits,
  262. positive_accumulate<T, Radix> >::f(scan, n, count))
  263. {
  264. return scan.create_match(count, n, save, scan.first);
  265. }
  266. // return no-match if number overflows
  267. }
  268. return scan.no_match();
  269. }
  270. };
  271. ///////////////////////////////////////////////////////////////////////
  272. //
  273. // int_parser_impl class
  274. //
  275. ///////////////////////////////////////////////////////////////////////
  276. template <
  277. typename T = unsigned,
  278. int Radix = 10,
  279. unsigned MinDigits = 1,
  280. int MaxDigits = -1
  281. >
  282. struct int_parser_impl
  283. : parser<int_parser_impl<T, Radix, MinDigits, MaxDigits> >
  284. {
  285. typedef int_parser_impl<T, Radix, MinDigits, MaxDigits> self_t;
  286. template <typename ScannerT>
  287. struct result
  288. {
  289. typedef typename match_result<ScannerT, T>::type type;
  290. };
  291. template <typename ScannerT>
  292. typename parser_result<self_t, ScannerT>::type
  293. parse(ScannerT const& scan) const
  294. {
  295. typedef extract_int<Radix, MinDigits, MaxDigits,
  296. negative_accumulate<T, Radix> > extract_int_neg_t;
  297. typedef extract_int<Radix, MinDigits, MaxDigits,
  298. positive_accumulate<T, Radix> > extract_int_pos_t;
  299. if (!scan.at_end())
  300. {
  301. T n = 0;
  302. std::size_t count = 0;
  303. typename ScannerT::iterator_t save = scan.first;
  304. bool hit = impl::extract_sign(scan, count);
  305. if (hit)
  306. hit = extract_int_neg_t::f(scan, n, count);
  307. else
  308. hit = extract_int_pos_t::f(scan, n, count);
  309. if (hit)
  310. return scan.create_match(count, n, save, scan.first);
  311. else
  312. scan.first = save;
  313. // return no-match if number overflows or underflows
  314. }
  315. return scan.no_match();
  316. }
  317. };
  318. ///////////////////////////////////////////////////////////////////////
  319. //
  320. // real_parser_impl class
  321. //
  322. ///////////////////////////////////////////////////////////////////////
  323. template <typename RT, typename T, typename RealPoliciesT>
  324. struct real_parser_impl
  325. {
  326. typedef real_parser_impl<RT, T, RealPoliciesT> self_t;
  327. template <typename ScannerT>
  328. RT parse_main(ScannerT const& scan) const
  329. {
  330. if (scan.at_end())
  331. return scan.no_match();
  332. typename ScannerT::iterator_t save = scan.first;
  333. typedef typename parser_result<sign_parser, ScannerT>::type
  334. sign_match_t;
  335. typedef typename parser_result<chlit<>, ScannerT>::type
  336. exp_match_t;
  337. sign_match_t sign_match = RealPoliciesT::parse_sign(scan);
  338. std::size_t count = sign_match ? sign_match.length() : 0;
  339. bool neg = sign_match.has_valid_attribute() ?
  340. sign_match.value() : false;
  341. RT n_match = RealPoliciesT::parse_n(scan);
  342. T n = n_match.has_valid_attribute() ?
  343. n_match.value() : T(0);
  344. bool got_a_number = n_match;
  345. exp_match_t e_hit;
  346. if (!got_a_number && !RealPoliciesT::allow_leading_dot)
  347. return scan.no_match();
  348. else
  349. count += n_match.length();
  350. if (neg)
  351. n = -n;
  352. if (RealPoliciesT::parse_dot(scan))
  353. {
  354. // We got the decimal point. Now we will try to parse
  355. // the fraction if it is there. If not, it defaults
  356. // to zero (0) only if we already got a number.
  357. if (RT hit = RealPoliciesT::parse_frac_n(scan))
  358. {
  359. #if !defined(BOOST_NO_STDC_NAMESPACE)
  360. using namespace std; // allow for ADL to find pow()
  361. #endif
  362. hit.value(hit.value()
  363. * pow(T(10), T(-hit.length())));
  364. if (neg)
  365. n -= hit.value();
  366. else
  367. n += hit.value();
  368. count += hit.length() + 1;
  369. }
  370. else if (!got_a_number ||
  371. !RealPoliciesT::allow_trailing_dot)
  372. return scan.no_match();
  373. e_hit = RealPoliciesT::parse_exp(scan);
  374. }
  375. else
  376. {
  377. // We have reached a point where we
  378. // still haven't seen a number at all.
  379. // We return early with a no-match.
  380. if (!got_a_number)
  381. return scan.no_match();
  382. // If we must expect a dot and we didn't see
  383. // an exponent, return early with a no-match.
  384. e_hit = RealPoliciesT::parse_exp(scan);
  385. if (RealPoliciesT::expect_dot && !e_hit)
  386. return scan.no_match();
  387. }
  388. if (e_hit)
  389. {
  390. // We got the exponent prefix. Now we will try to parse the
  391. // actual exponent. It is an error if it is not there.
  392. if (RT e_n_hit = RealPoliciesT::parse_exp_n(scan))
  393. {
  394. #if !defined(BOOST_NO_STDC_NAMESPACE)
  395. using namespace std; // allow for ADL to find pow()
  396. #endif
  397. n *= pow(T(10), T(e_n_hit.value()));
  398. count += e_n_hit.length() + e_hit.length();
  399. }
  400. else
  401. {
  402. // Oops, no exponent, return a no-match
  403. return scan.no_match();
  404. }
  405. }
  406. return scan.create_match(count, n, save, scan.first);
  407. }
  408. template <typename ScannerT>
  409. static RT parse(ScannerT const& scan)
  410. {
  411. static self_t this_;
  412. return impl::implicit_lexeme_parse<RT>(this_, scan, scan);
  413. }
  414. };
  415. #if defined(BOOST_MSVC)
  416. #pragma warning(pop)
  417. #endif
  418. } // namespace impl
  419. ///////////////////////////////////////////////////////////////////////////////
  420. BOOST_SPIRIT_CLASSIC_NAMESPACE_END
  421. }} // namespace boost::spirit
  422. #endif