extract_int.hpp 17 KB

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