/usr/include/boost/spirit/home/classic/core/primitives/impl
Edit: /usr/include/boost/spirit/home/classic/core/primitives/impl/numerics.ipp (16890B)
/*=============================================================================
Copyright (c) 1998-2003 Joel de Guzman
Copyright (c) 2001-2003 Hartmut Kaiser
http://spirit.sourceforge.net/
Use, modification and distribution is subject to the Boost Software
License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
http://www.boost.org/LICENSE_1_0.txt)
=============================================================================*/
#ifndef BOOST_SPIRIT_NUMERICS_IPP
#define BOOST_SPIRIT_NUMERICS_IPP
#include
#include
namespace boost { namespace spirit {
BOOST_SPIRIT_CLASSIC_NAMESPACE_BEGIN
struct sign_parser; // forward declaration only
namespace impl
{
///////////////////////////////////////////////////////////////////////
//
// Extract the prefix sign (- or +)
//
///////////////////////////////////////////////////////////////////////
template
bool
extract_sign(ScannerT const& scan, std::size_t& count)
{
// Extract the sign
count = 0;
bool neg = *scan == '-';
if (neg || (*scan == '+'))
{
++scan;
++count;
return neg;
}
return false;
}
///////////////////////////////////////////////////////////////////////
//
// Traits class for radix specific number conversion
//
// Convert a digit from character representation, ch, to binary
// representation, returned in val.
// Returns whether the conversion was successful.
//
// template static bool digit(CharT ch, T& val);
//
///////////////////////////////////////////////////////////////////////
template
struct radix_traits;
////////////////////////////////// Binary
template<>
struct radix_traits<2>
{
template
static bool digit(CharT ch, T& val)
{
val = ch - '0';
return ('0' == ch || '1' == ch);
}
};
////////////////////////////////// Octal
template<>
struct radix_traits<8>
{
template
static bool digit(CharT ch, T& val)
{
val = ch - '0';
return ('0' <= ch && ch <= '7');
}
};
////////////////////////////////// Decimal
template<>
struct radix_traits<10>
{
template
static bool digit(CharT ch, T& val)
{
val = ch - '0';
return impl::isdigit_(ch);
}
};
////////////////////////////////// Hexadecimal
template<>
struct radix_traits<16>
{
template
static bool digit(CharT ch, T& val)
{
if (radix_traits<10>::digit(ch, val))
return true;
CharT lc = impl::tolower_(ch);
if ('a' <= lc && lc <= 'f')
{
val = lc - 'a' + 10;
return true;
}
return false;
}
};
///////////////////////////////////////////////////////////////////////
//
// Helper templates for encapsulation of radix specific
// conversion of an input string to an integral value.
//
// main entry point:
//
// extract_int
// ::f(first, last, n, count);
//
// The template parameter Radix represents the radix of the
// number contained in the parsed string. The template
// parameter MinDigits specifies the minimum digits to
// accept. The template parameter MaxDigits specifies the
// maximum digits to parse. A -1 value for MaxDigits will
// make it parse an arbitrarilly large number as long as the
// numeric type can hold it. Accumulate is either
// positive_accumulate (default) for parsing positive
// numbers or negative_accumulate otherwise.
// Checking is only performed when std::numeric_limits::
// is_specialized is true. Otherwise, there's no way to
// do the check.
//
// scan.first and scan.last are iterators as usual (i.e.
// first is mutable and is moved forward when a match is
// found), n is a variable that holds the number (passed by
// reference). The number of parsed characters is added to
// count (also passed by reference)
//
// NOTE:
// Returns a non-match, if the number to parse
// overflows (or underflows) the used type.
//
// BEWARE:
// the parameters 'n' and 'count' should be properly
// initialized before calling this function.
//
///////////////////////////////////////////////////////////////////////
#if defined(BOOST_MSVC)
#pragma warning(push)
#pragma warning(disable:4127) //conditional expression is constant
#endif
template
struct positive_accumulate
{
// Use this accumulator if number is positive
static bool add(T& n, T digit)
{
if (std::numeric_limits::is_specialized)
{
static T const max = (std::numeric_limits::max)();
static T const max_div_radix = max/Radix;
if (n > max_div_radix)
return false;
n *= Radix;
if (n > max - digit)
return false;
n += digit;
return true;
}
else
{
n *= Radix;
n += digit;
return true;
}
}
};
template
struct negative_accumulate
{
// Use this accumulator if number is negative
static bool add(T& n, T digit)
{
if (std::numeric_limits::is_specialized)
{
typedef std::numeric_limits num_limits;
static T const min =
(!num_limits::is_integer && num_limits::is_signed && num_limits::has_denorm) ?
-(num_limits::max)() : (num_limits::min)();
static T const min_div_radix = min/Radix;
if (n < min_div_radix)
return false;
n *= Radix;
if (n < min + digit)
return false;
n -= digit;
return true;
}
else
{
n *= Radix;
n -= digit;
return true;
}
}
};
template
inline bool allow_more_digits(std::size_t i)
{
return i < MaxDigits;
}
template <>
inline bool allow_more_digits<-1>(std::size_t)
{
return true;
}
//////////////////////////////////
template <
int Radix, unsigned MinDigits, int MaxDigits,
typename Accumulate
>
struct extract_int
{
template
static bool
f(ScannerT& scan, T& n, std::size_t& count)
{
std::size_t i = 0;
T digit;
while( allow_more_digits(i) && !scan.at_end() &&
radix_traits::digit(*scan, digit) )
{
if (!Accumulate::add(n, digit))
return false; // Overflow
++i, ++scan, ++count;
}
return i >= MinDigits;
}
};
///////////////////////////////////////////////////////////////////////
//
// uint_parser_impl class
//
///////////////////////////////////////////////////////////////////////
template <
typename T = unsigned,
int Radix = 10,
unsigned MinDigits = 1,
int MaxDigits = -1
>
struct uint_parser_impl
: parser >
{
typedef uint_parser_impl self_t;
template
struct result
{
typedef typename match_result::type type;
};
template
typename parser_result::type
parse(ScannerT const& scan) const
{
if (!scan.at_end())
{
T n = 0;
std::size_t count = 0;
typename ScannerT::iterator_t save = scan.first;
if (extract_int >::f(scan, n, count))
{
return scan.create_match(count, n, save, scan.first);
}
// return no-match if number overflows
}
return scan.no_match();
}
};
///////////////////////////////////////////////////////////////////////
//
// int_parser_impl class
//
///////////////////////////////////////////////////////////////////////
template <
typename T = unsigned,
int Radix = 10,
unsigned MinDigits = 1,
int MaxDigits = -1
>
struct int_parser_impl
: parser >
{
typedef int_parser_impl self_t;
template
struct result
{
typedef typename match_result::type type;
};
template
typename parser_result::type
parse(ScannerT const& scan) const
{
typedef extract_int > extract_int_neg_t;
typedef extract_int > extract_int_pos_t;
if (!scan.at_end())
{
T n = 0;
std::size_t count = 0;
typename ScannerT::iterator_t save = scan.first;
bool hit = impl::extract_sign(scan, count);
if (hit)
hit = extract_int_neg_t::f(scan, n, count);
else
hit = extract_int_pos_t::f(scan, n, count);
if (hit)
return scan.create_match(count, n, save, scan.first);
else
scan.first = save;
// return no-match if number overflows or underflows
}
return scan.no_match();
}
};
///////////////////////////////////////////////////////////////////////
//
// real_parser_impl class
//
///////////////////////////////////////////////////////////////////////
template
struct real_parser_impl
{
typedef real_parser_impl