]> git.proxmox.com Git - ceph.git/blame - ceph/src/boost/libs/spirit/include/boost/spirit/home/x3/support/numeric_utils/detail/extract_int.hpp
bump version to 12.2.2-pve1
[ceph.git] / ceph / src / boost / libs / spirit / include / boost / spirit / home / x3 / support / numeric_utils / detail / extract_int.hpp
CommitLineData
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
41namespace 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