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