numeric_utils.hpp 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517
  1. /*=============================================================================
  2. Copyright (c) 2001-2011 Joel de Guzman
  3. Copyright (c) 2001-2011 Hartmut Kaiser
  4. Copyright (c) 2011 Jan Frederick Eick
  5. Copyright (c) 2011 Christopher Jefferson
  6. Copyright (c) 2006 Stephen Nutt
  7. Distributed under the Boost Software License, Version 1.0. (See accompanying
  8. file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
  9. =============================================================================*/
  10. #ifndef BOOST_SPIRIT_QI_NUMERIC_DETAIL_NUMERIC_UTILS_HPP
  11. #define BOOST_SPIRIT_QI_NUMERIC_DETAIL_NUMERIC_UTILS_HPP
  12. #if defined(_MSC_VER)
  13. #pragma once
  14. #endif
  15. #include <boost/spirit/home/support/unused.hpp>
  16. #include <boost/spirit/home/qi/detail/attributes.hpp>
  17. #include <boost/spirit/home/support/char_encoding/ascii.hpp>
  18. #include <boost/spirit/home/support/numeric_traits.hpp>
  19. #include <boost/preprocessor/repetition/repeat.hpp>
  20. #include <boost/preprocessor/iteration/local.hpp>
  21. #include <boost/preprocessor/comparison/less.hpp>
  22. #include <boost/preprocessor/control/if.hpp>
  23. #include <boost/preprocessor/seq/elem.hpp>
  24. #include <boost/utility/enable_if.hpp>
  25. #include <boost/type_traits/is_integral.hpp>
  26. #include <boost/type_traits/is_signed.hpp>
  27. #include <boost/mpl/bool.hpp>
  28. #include <boost/mpl/and.hpp>
  29. #include <boost/limits.hpp>
  30. #include <boost/static_assert.hpp>
  31. #include <iterator> // for std::iterator_traits
  32. #if defined(BOOST_MSVC)
  33. # pragma warning(push)
  34. # pragma warning(disable: 4127) // conditional expression is constant
  35. #endif
  36. #if !defined(SPIRIT_NUMERICS_LOOP_UNROLL)
  37. # define SPIRIT_NUMERICS_LOOP_UNROLL 3
  38. #endif
  39. namespace boost { namespace spirit { namespace qi { namespace detail
  40. {
  41. ///////////////////////////////////////////////////////////////////////////
  42. //
  43. // The maximum radix digits that can be represented without
  44. // overflow:
  45. //
  46. // template<typename T, unsigned Radix>
  47. // struct digits_traits::value;
  48. //
  49. ///////////////////////////////////////////////////////////////////////////
  50. template <typename T, unsigned Radix>
  51. struct digits_traits;
  52. template <int Digits, unsigned Radix>
  53. struct digits2_to_n;
  54. // lookup table for log2(x) : 2 <= x <= 36
  55. #define BOOST_SPIRIT_LOG2 (#error)(#error) \
  56. (1000000)(1584960)(2000000)(2321920)(2584960)(2807350) \
  57. (3000000)(3169920)(3321920)(3459430)(3584960)(3700430) \
  58. (3807350)(3906890)(4000000)(4087460)(4169920)(4247920) \
  59. (4321920)(4392310)(4459430)(4523560)(4584960)(4643850) \
  60. (4700430)(4754880)(4807350)(4857980)(4906890)(4954190) \
  61. (5000000)(5044390)(5087460)(5129280)(5169925) \
  62. /***/
  63. #define BOOST_PP_LOCAL_MACRO(Radix) \
  64. template <int Digits> struct digits2_to_n<Digits, Radix> \
  65. { \
  66. BOOST_STATIC_CONSTANT(int, value = static_cast<int>( \
  67. (Digits * 1000000) / \
  68. BOOST_PP_SEQ_ELEM(Radix, BOOST_SPIRIT_LOG2))); \
  69. }; \
  70. /***/
  71. #define BOOST_PP_LOCAL_LIMITS (2, 36)
  72. #include BOOST_PP_LOCAL_ITERATE()
  73. #undef BOOST_SPIRIT_LOG2
  74. template <typename T, unsigned Radix>
  75. struct digits_traits : digits2_to_n<std::numeric_limits<T>::digits, Radix>
  76. {
  77. BOOST_STATIC_ASSERT(std::numeric_limits<T>::radix == 2);
  78. };
  79. template <typename T>
  80. struct digits_traits<T, 10>
  81. {
  82. static int const value = std::numeric_limits<T>::digits10;
  83. };
  84. ///////////////////////////////////////////////////////////////////////////
  85. //
  86. // Traits class for radix specific number conversion
  87. //
  88. // Test the validity of a single character:
  89. //
  90. // template<typename Char> static bool is_valid(Char ch);
  91. //
  92. // Convert a digit from character representation to binary
  93. // representation:
  94. //
  95. // template<typename Char> static int digit(Char ch);
  96. //
  97. ///////////////////////////////////////////////////////////////////////////
  98. template <unsigned Radix>
  99. struct radix_traits
  100. {
  101. template <typename Char>
  102. inline static bool is_valid(Char ch)
  103. {
  104. return (ch >= '0' && ch <= (Radix > 10 ? '9' : static_cast<Char>('0' + Radix -1)))
  105. || (Radix > 10 && ch >= 'a' && ch <= static_cast<Char>('a' + Radix -10 -1))
  106. || (Radix > 10 && ch >= 'A' && ch <= static_cast<Char>('A' + Radix -10 -1));
  107. }
  108. template <typename Char>
  109. inline static unsigned digit(Char ch)
  110. {
  111. if (Radix <= 10 || (ch >= '0' && ch <= '9'))
  112. return ch - '0';
  113. return spirit::char_encoding::ascii::tolower(ch) - 'a' + 10;
  114. }
  115. };
  116. ///////////////////////////////////////////////////////////////////////////
  117. // positive_accumulator/negative_accumulator: Accumulator policies for
  118. // extracting integers. Use positive_accumulator if number is positive.
  119. // Use negative_accumulator if number is negative.
  120. ///////////////////////////////////////////////////////////////////////////
  121. template <unsigned Radix>
  122. struct positive_accumulator
  123. {
  124. template <typename T, typename Char>
  125. inline static void add(T& n, Char ch, mpl::false_) // unchecked add
  126. {
  127. const int digit = radix_traits<Radix>::digit(ch);
  128. n = n * T(Radix) + T(digit);
  129. }
  130. template <typename T, typename Char>
  131. inline static bool add(T& n, Char ch, mpl::true_) // checked add
  132. {
  133. // Ensure n *= Radix will not overflow
  134. T const max = (std::numeric_limits<T>::max)();
  135. T const val = max / Radix;
  136. if (n > val)
  137. return false;
  138. T tmp = n * Radix;
  139. // Ensure n += digit will not overflow
  140. const int digit = radix_traits<Radix>::digit(ch);
  141. if (tmp > max - digit)
  142. return false;
  143. n = tmp + static_cast<T>(digit);
  144. return true;
  145. }
  146. };
  147. template <unsigned Radix>
  148. struct negative_accumulator
  149. {
  150. template <typename T, typename Char>
  151. inline static void add(T& n, Char ch, mpl::false_) // unchecked subtract
  152. {
  153. const int digit = radix_traits<Radix>::digit(ch);
  154. n = n * T(Radix) - T(digit);
  155. }
  156. template <typename T, typename Char>
  157. inline static bool add(T& n, Char ch, mpl::true_) // checked subtract
  158. {
  159. // Ensure n *= Radix will not underflow
  160. T const min = (std::numeric_limits<T>::min)();
  161. T const val = min / T(Radix);
  162. if (n < val)
  163. return false;
  164. T tmp = n * Radix;
  165. // Ensure n -= digit will not underflow
  166. int const digit = radix_traits<Radix>::digit(ch);
  167. if (tmp < min + digit)
  168. return false;
  169. n = tmp - static_cast<T>(digit);
  170. return true;
  171. }
  172. };
  173. ///////////////////////////////////////////////////////////////////////////
  174. // Common code for extract_int::parse specializations
  175. ///////////////////////////////////////////////////////////////////////////
  176. template <unsigned Radix, typename Accumulator, int MaxDigits, bool AlwaysCheckOverflow>
  177. struct int_extractor
  178. {
  179. template <typename Char, typename T>
  180. inline static bool
  181. call(Char ch, std::size_t count, T& n, mpl::true_)
  182. {
  183. std::size_t const overflow_free = digits_traits<T, Radix>::value - 1;
  184. if (!AlwaysCheckOverflow && (count < overflow_free))
  185. {
  186. Accumulator::add(n, ch, mpl::false_());
  187. }
  188. else
  189. {
  190. if (!Accumulator::add(n, ch, mpl::true_()))
  191. return false; // over/underflow!
  192. }
  193. return true;
  194. }
  195. template <typename Char, typename T>
  196. inline static bool
  197. call(Char ch, std::size_t /*count*/, T& n, mpl::false_)
  198. {
  199. // no need to check for overflow
  200. Accumulator::add(n, ch, mpl::false_());
  201. return true;
  202. }
  203. template <typename Char>
  204. inline static bool
  205. call(Char /*ch*/, std::size_t /*count*/, unused_type, mpl::false_)
  206. {
  207. return true;
  208. }
  209. template <typename Char, typename T>
  210. inline static bool
  211. call(Char ch, std::size_t count, T& n)
  212. {
  213. return call(ch, count, n
  214. , mpl::bool_<
  215. ( (MaxDigits < 0)
  216. || (MaxDigits > digits_traits<T, Radix>::value)
  217. )
  218. && traits::check_overflow<T>::value
  219. >()
  220. );
  221. }
  222. };
  223. ///////////////////////////////////////////////////////////////////////////
  224. // End of loop checking: check if the number of digits
  225. // being parsed exceeds MaxDigits. Note: if MaxDigits == -1
  226. // we don't do any checking.
  227. ///////////////////////////////////////////////////////////////////////////
  228. template <int MaxDigits>
  229. struct check_max_digits
  230. {
  231. inline static bool
  232. call(std::size_t count)
  233. {
  234. return count < MaxDigits; // bounded
  235. }
  236. };
  237. template <>
  238. struct check_max_digits<-1>
  239. {
  240. inline static bool
  241. call(std::size_t /*count*/)
  242. {
  243. return true; // unbounded
  244. }
  245. };
  246. ///////////////////////////////////////////////////////////////////////////
  247. // extract_int: main code for extracting integers
  248. ///////////////////////////////////////////////////////////////////////////
  249. #define SPIRIT_NUMERIC_INNER_LOOP(z, x, data) \
  250. if (!check_max_digits<MaxDigits>::call(count + leading_zeros) \
  251. || it == last) \
  252. { \
  253. break; \
  254. } \
  255. ch = *it; \
  256. if (!radix_check::is_valid(ch)) \
  257. { \
  258. break; \
  259. } \
  260. if (!extractor::call(ch, count, val)) \
  261. { \
  262. if (IgnoreOverflowDigits) \
  263. { \
  264. first = it; \
  265. } \
  266. traits::assign_to(val, attr); \
  267. return IgnoreOverflowDigits; \
  268. } \
  269. ++it; \
  270. ++count; \
  271. /**/
  272. template <
  273. typename T, unsigned Radix, unsigned MinDigits, int MaxDigits
  274. , typename Accumulator = positive_accumulator<Radix>
  275. , bool Accumulate = false
  276. , bool IgnoreOverflowDigits = false
  277. >
  278. struct extract_int
  279. {
  280. #if BOOST_WORKAROUND(BOOST_MSVC, >= 1400)
  281. # pragma warning(push)
  282. # pragma warning(disable: 4127) // conditional expression is constant
  283. #endif
  284. template <typename Iterator, typename Attribute>
  285. inline static bool
  286. parse_main(
  287. Iterator& first
  288. , Iterator const& last
  289. , Attribute& attr)
  290. {
  291. typedef radix_traits<Radix> radix_check;
  292. typedef int_extractor<Radix, Accumulator, MaxDigits, Accumulate> extractor;
  293. typedef typename std::iterator_traits<Iterator>::value_type char_type;
  294. Iterator it = first;
  295. std::size_t leading_zeros = 0;
  296. if (!Accumulate)
  297. {
  298. // skip leading zeros
  299. while (it != last && *it == '0' && (MaxDigits < 0 || leading_zeros < static_cast< std::size_t >(MaxDigits)))
  300. {
  301. ++it;
  302. ++leading_zeros;
  303. }
  304. }
  305. typedef typename
  306. traits::attribute_type<Attribute>::type
  307. attribute_type;
  308. attribute_type val = Accumulate ? attr : attribute_type(0);
  309. std::size_t count = 0;
  310. char_type ch;
  311. while (true)
  312. {
  313. BOOST_PP_REPEAT(
  314. SPIRIT_NUMERICS_LOOP_UNROLL
  315. , SPIRIT_NUMERIC_INNER_LOOP, _)
  316. }
  317. if (count + leading_zeros >= MinDigits)
  318. {
  319. traits::assign_to(val, attr);
  320. first = it;
  321. return true;
  322. }
  323. return false;
  324. }
  325. #if BOOST_WORKAROUND(BOOST_MSVC, >= 1400)
  326. # pragma warning(pop)
  327. #endif
  328. template <typename Iterator>
  329. inline static bool
  330. parse(
  331. Iterator& first
  332. , Iterator const& last
  333. , unused_type)
  334. {
  335. T n = 0; // must calculate value to detect over/underflow
  336. return parse_main(first, last, n);
  337. }
  338. template <typename Iterator, typename Attribute>
  339. inline static bool
  340. parse(
  341. Iterator& first
  342. , Iterator const& last
  343. , Attribute& attr)
  344. {
  345. return parse_main(first, last, attr);
  346. }
  347. };
  348. #undef SPIRIT_NUMERIC_INNER_LOOP
  349. ///////////////////////////////////////////////////////////////////////////
  350. // extract_int: main code for extracting integers
  351. // common case where MinDigits == 1 and MaxDigits = -1
  352. ///////////////////////////////////////////////////////////////////////////
  353. #define SPIRIT_NUMERIC_INNER_LOOP(z, x, data) \
  354. if (it == last) \
  355. { \
  356. break; \
  357. } \
  358. ch = *it; \
  359. if (!radix_check::is_valid(ch)) \
  360. { \
  361. break; \
  362. } \
  363. if (!extractor::call(ch, count, val)) \
  364. { \
  365. traits::assign_to(val, attr); \
  366. return false; \
  367. } \
  368. ++it; \
  369. ++count; \
  370. /**/
  371. template <typename T, unsigned Radix, typename Accumulator, bool Accumulate>
  372. struct extract_int<T, Radix, 1, -1, Accumulator, Accumulate>
  373. {
  374. #if BOOST_WORKAROUND(BOOST_MSVC, >= 1400)
  375. # pragma warning(push)
  376. # pragma warning(disable: 4127) // conditional expression is constant
  377. #endif
  378. template <typename Iterator, typename Attribute>
  379. inline static bool
  380. parse_main(
  381. Iterator& first
  382. , Iterator const& last
  383. , Attribute& attr)
  384. {
  385. typedef radix_traits<Radix> radix_check;
  386. typedef int_extractor<Radix, Accumulator, -1, Accumulate> extractor;
  387. typedef typename std::iterator_traits<Iterator>::value_type char_type;
  388. Iterator it = first;
  389. std::size_t count = 0;
  390. if (!Accumulate)
  391. {
  392. // skip leading zeros
  393. while (it != last && *it == '0')
  394. {
  395. ++it;
  396. ++count;
  397. }
  398. if (it == last)
  399. {
  400. if (count == 0) // must have at least one digit
  401. return false;
  402. traits::assign_to(0, attr);
  403. first = it;
  404. return true;
  405. }
  406. }
  407. typedef typename
  408. traits::attribute_type<Attribute>::type
  409. attribute_type;
  410. attribute_type val = Accumulate ? attr : attribute_type(0);
  411. char_type ch = *it;
  412. if (!radix_check::is_valid(ch) || !extractor::call(ch, 0, val))
  413. {
  414. if (count == 0) // must have at least one digit
  415. return false;
  416. traits::assign_to(val, attr);
  417. first = it;
  418. return true;
  419. }
  420. // count = 0; $$$ verify: I think this is wrong $$$
  421. ++it;
  422. while (true)
  423. {
  424. BOOST_PP_REPEAT(
  425. SPIRIT_NUMERICS_LOOP_UNROLL
  426. , SPIRIT_NUMERIC_INNER_LOOP, _)
  427. }
  428. traits::assign_to(val, attr);
  429. first = it;
  430. return true;
  431. }
  432. #if BOOST_WORKAROUND(BOOST_MSVC, >= 1400)
  433. # pragma warning(pop)
  434. #endif
  435. template <typename Iterator>
  436. inline static bool
  437. parse(
  438. Iterator& first
  439. , Iterator const& last
  440. , unused_type)
  441. {
  442. T n = 0; // must calculate value to detect over/underflow
  443. return parse_main(first, last, n);
  444. }
  445. template <typename Iterator, typename Attribute>
  446. inline static bool
  447. parse(
  448. Iterator& first
  449. , Iterator const& last
  450. , Attribute& attr)
  451. {
  452. return parse_main(first, last, attr);
  453. }
  454. };
  455. #undef SPIRIT_NUMERIC_INNER_LOOP
  456. }}}}
  457. #if defined(BOOST_MSVC)
  458. # pragma warning(pop)
  459. #endif
  460. #endif