1 /*============================================================================= 2 Copyright (c) 2001-2019 Joel de Guzman 3 Copyright (c) 2001-2011 Hartmut Kaiser 4 5 Distributed under the Boost Software License, Version 1.0. (See accompanying 6 file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) 7 ==============================================================================*/ 8 #ifndef BOOST_SPIRIT_QI_NUMERIC_REAL_POLICIES_HPP 9 #define BOOST_SPIRIT_QI_NUMERIC_REAL_POLICIES_HPP 10 11 #if defined(_MSC_VER) 12 #pragma once 13 #endif 14 15 #include <boost/spirit/home/qi/numeric/numeric_utils.hpp> 16 #include <boost/spirit/home/qi/detail/string_parse.hpp> 17 #include <boost/type_traits/is_floating_point.hpp> 18 19 namespace boost { namespace spirit { namespace traits 20 { 21 // So that we won't exceed the capacity of the underlying type T, 22 // we limit the number of digits parsed to its max_digits10. 23 // By default, the value is -1 which tells spirit to parse an 24 // unbounded number of digits. 25 26 template <typename T, typename Enable = void> 27 struct max_digits10 28 { 29 static int const value = -1; // unbounded 30 }; 31 32 template <typename T> 33 struct max_digits10<T 34 , typename enable_if_c<(is_floating_point<T>::value)>::type> 35 { 36 static int const digits = std::numeric_limits<T>::digits; 37 static int const value = 2 + (digits * 30103l) / 100000l; 38 }; 39 }}} 40 41 namespace boost { namespace spirit { namespace qi 42 { 43 /////////////////////////////////////////////////////////////////////////// 44 // Default (unsigned) real number policies 45 /////////////////////////////////////////////////////////////////////////// 46 template <typename T> 47 struct ureal_policies 48 { 49 // Versioning 50 typedef mpl::int_<2> version; 51 52 // trailing dot policy suggested by Gustavo Guerra 53 static bool const allow_leading_dot = true; 54 static bool const allow_trailing_dot = true; 55 static bool const expect_dot = false; 56 57 template <typename Iterator> 58 static bool parse_signboost::spirit::qi::ureal_policies59 parse_sign(Iterator& /*first*/, Iterator const& /*last*/) 60 { 61 return false; 62 } 63 64 template <typename Iterator, typename Attribute> 65 static bool parse_nboost::spirit::qi::ureal_policies66 parse_n(Iterator& first, Iterator const& last, Attribute& attr_) 67 { 68 typedef extract_uint<Attribute, 10, 1 69 , traits::max_digits10<T>::value // See notes on max_digits10 above 70 , false, true> 71 extract_uint; 72 return extract_uint::call(first, last, attr_); 73 } 74 75 // ignore_excess_digits (required for version > 1 API) 76 template <typename Iterator> 77 static std::size_t ignore_excess_digitsboost::spirit::qi::ureal_policies78 ignore_excess_digits(Iterator& first, Iterator const& last) 79 { 80 Iterator save = first; 81 if (extract_uint<unused_type, 10, 1, -1>::call(first, last, unused)) 82 return static_cast<std::size_t>(std::distance(save, first)); 83 return 0; 84 } 85 86 template <typename Iterator> 87 static bool parse_dotboost::spirit::qi::ureal_policies88 parse_dot(Iterator& first, Iterator const& last) 89 { 90 if (first == last || *first != '.') 91 return false; 92 ++first; 93 return true; 94 } 95 96 template <typename Iterator, typename Attribute> 97 static bool parse_frac_nboost::spirit::qi::ureal_policies98 parse_frac_n(Iterator& first, Iterator const& last, Attribute& attr_, int& frac_digits) 99 { 100 Iterator savef = first; 101 bool r = extract_uint<Attribute, 10, 1, -1, true, true>::call(first, last, attr_); 102 if (r) 103 { 104 #if defined(_MSC_VER) && _MSC_VER < 1900 105 # pragma warning(push) 106 # pragma warning(disable: 4127) // conditional expression is constant 107 #endif 108 // Optimization note: don't compute frac_digits if T is 109 // an unused_type. This should be optimized away by the compiler. 110 if (!is_same<T, unused_type>::value) 111 frac_digits = 112 static_cast<int>(std::distance(savef, first)); 113 #if defined(_MSC_VER) && _MSC_VER < 1900 114 # pragma warning(pop) 115 #endif 116 // ignore extra (non-significant digits) 117 extract_uint<unused_type, 10, 1, -1>::call(first, last, unused); 118 } 119 return r; 120 } 121 122 template <typename Iterator> 123 static bool parse_expboost::spirit::qi::ureal_policies124 parse_exp(Iterator& first, Iterator const& last) 125 { 126 if (first == last || (*first != 'e' && *first != 'E')) 127 return false; 128 ++first; 129 return true; 130 } 131 132 template <typename Iterator> 133 static bool parse_exp_nboost::spirit::qi::ureal_policies134 parse_exp_n(Iterator& first, Iterator const& last, int& attr_) 135 { 136 return extract_int<int, 10, 1, -1>::call(first, last, attr_); 137 } 138 139 /////////////////////////////////////////////////////////////////////// 140 // The parse_nan() and parse_inf() functions get called whenever 141 // a number to parse does not start with a digit (after having 142 // successfully parsed an optional sign). 143 // 144 // The functions should return true if a Nan or Inf has been found. In 145 // this case the attr should be set to the matched value (NaN or 146 // Inf). The optional sign will be automatically applied afterwards. 147 // 148 // The default implementation below recognizes representations of NaN 149 // and Inf as mandated by the C99 Standard and as proposed for 150 // inclusion into the C++0x Standard: nan, nan(...), inf and infinity 151 // (the matching is performed case-insensitively). 152 /////////////////////////////////////////////////////////////////////// 153 template <typename Iterator, typename Attribute> 154 static bool parse_nanboost::spirit::qi::ureal_policies155 parse_nan(Iterator& first, Iterator const& last, Attribute& attr_) 156 { 157 if (first == last) 158 return false; // end of input reached 159 160 if (*first != 'n' && *first != 'N') 161 return false; // not "nan" 162 163 // nan[(...)] ? 164 if (detail::string_parse("nan", "NAN", first, last, unused)) 165 { 166 if (first != last && *first == '(') 167 { 168 // skip trailing (...) part 169 Iterator i = first; 170 171 while (++i != last && *i != ')') 172 ; 173 if (i == last) 174 return false; // no trailing ')' found, give up 175 176 first = ++i; 177 } 178 attr_ = std::numeric_limits<T>::quiet_NaN(); 179 return true; 180 } 181 return false; 182 } 183 184 template <typename Iterator, typename Attribute> 185 static bool parse_infboost::spirit::qi::ureal_policies186 parse_inf(Iterator& first, Iterator const& last, Attribute& attr_) 187 { 188 if (first == last) 189 return false; // end of input reached 190 191 if (*first != 'i' && *first != 'I') 192 return false; // not "inf" 193 194 // inf or infinity ? 195 if (detail::string_parse("inf", "INF", first, last, unused)) 196 { 197 // skip allowed 'inity' part of infinity 198 detail::string_parse("inity", "INITY", first, last, unused); 199 attr_ = std::numeric_limits<T>::infinity(); 200 return true; 201 } 202 return false; 203 } 204 }; 205 206 /////////////////////////////////////////////////////////////////////////// 207 // Default (signed) real number policies 208 /////////////////////////////////////////////////////////////////////////// 209 template <typename T> 210 struct real_policies : ureal_policies<T> 211 { 212 template <typename Iterator> 213 static bool parse_signboost::spirit::qi::real_policies214 parse_sign(Iterator& first, Iterator const& last) 215 { 216 return extract_sign(first, last); 217 } 218 }; 219 220 template <typename T> 221 struct strict_ureal_policies : ureal_policies<T> 222 { 223 static bool const expect_dot = true; 224 }; 225 226 template <typename T> 227 struct strict_real_policies : real_policies<T> 228 { 229 static bool const expect_dot = true; 230 }; 231 }}} 232 233 #endif 234