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