Ticket #1077: numeric.ipp.patch
File numeric.ipp.patch, 12.0 KB (added by , 15 years ago) |
---|
-
numerics.
old new 11 11 #define BOOST_SPIRIT_NUMERICS_IPP 12 12 13 13 #include <cmath> 14 #include <limits> 14 15 15 16 #if defined(BOOST_NO_STDC_NAMESPACE) 16 17 # define BOOST_SPIRIT_IMPL_STD_NS … … 50 51 // 51 52 // Traits class for radix specific number conversion 52 53 // 53 // Test the validity of a single character: 54 // Convert a digit from character representation, ch, to binary 55 // representation, returned in val. 56 // Returns whether the conversion was successful. 54 57 // 55 // template<typename CharT> static bool is_valid(CharT ch); 56 // 57 // Convert a digit from character representation to binary 58 // representation: 59 // 60 // template<typename CharT> static int digit(CharT ch); 58 // template<typename CharT> static bool digit(CharT ch, T& val); 61 59 // 62 60 /////////////////////////////////////////////////////////////////////// 63 61 template<const int Radix> … … 67 65 template<> 68 66 struct radix_traits<2> 69 67 { 70 template<typename CharT >71 static bool is_valid(CharT ch)68 template<typename CharT, typename T> 69 static bool digit(CharT ch, T& val) 72 70 { 71 val = ch - '0'; 73 72 return ('0' == ch || '1' == ch); 74 73 } 75 76 template<typename CharT>77 static int digit(CharT ch)78 {79 return ch - '0';80 }81 74 }; 82 75 83 76 ////////////////////////////////// Octal 84 77 template<> 85 78 struct radix_traits<8> 86 79 { 87 template<typename CharT >88 static bool is_valid(CharT ch)80 template<typename CharT, typename T> 81 static bool digit(CharT ch, T& val) 89 82 { 83 val = ch - '0'; 90 84 return ('0' <= ch && ch <= '7'); 91 85 } 92 93 template<typename CharT>94 static int digit(CharT ch)95 {96 return ch - '0';97 }98 86 }; 99 87 100 88 ////////////////////////////////// Decimal 101 89 template<> 102 90 struct radix_traits<10> 103 91 { 104 template<typename CharT >105 static bool is_valid(CharT ch)92 template<typename CharT, typename T> 93 static bool digit(CharT ch, T& val) 106 94 { 95 val = ch - '0'; 107 96 return impl::isdigit_(ch); 108 97 } 109 110 template<typename CharT>111 static int digit(CharT ch)112 {113 return ch - '0';114 }115 98 }; 116 99 117 100 ////////////////////////////////// Hexadecimal 118 101 template<> 119 102 struct radix_traits<16> 120 103 { 121 template<typename CharT >122 static bool is_valid(CharT ch)104 template<typename CharT, typename T> 105 static bool digit(CharT ch, T& val) 123 106 { 124 return impl::isxdigit_(ch);125 }107 if (radix_traits<10>::digit(ch, val)) 108 return true; 126 109 127 template<typename CharT> 128 static int digit(CharT ch) 129 { 130 if (impl::isdigit_(ch)) 131 return ch - '0'; 132 return impl::tolower_(ch) - 'a' + 10; 110 CharT lc = impl::tolower_(ch); 111 if ('a' <= lc && lc <= 'f') 112 { 113 val = lc - 'a' + 10; 114 return true; 115 } 116 return false; 133 117 } 134 118 }; 135 119 … … 161 145 // 162 146 // NOTE: 163 147 // Returns a non-match, if the number to parse 164 // overflows (or underflows) the used integral type. 165 // Overflow (or underflow) is detected when an 166 // operation wraps a value from its maximum to its 167 // minimum (or vice-versa). For example, overflow 168 // occurs when the result of the expression n * x is 169 // less than n (assuming n is positive and x is 170 // greater than 1). 148 // overflows (or underflows) the used type. 171 149 // 172 150 // BEWARE: 173 151 // the parameters 'n' and 'count' should be properly 174 152 // initialized before calling this function. 175 153 // 176 154 /////////////////////////////////////////////////////////////////////// 177 template < int Radix>155 template <typename T, int Radix> 178 156 struct positive_accumulate 179 157 { 180 158 // Use this accumulator if number is positive 181 182 template <typename T> 183 static bool check(T const& n, T const& prev) 159 static bool add(T& n, T digit) 184 160 { 185 return n < prev; 186 } 187 188 template <typename T, typename CharT> 189 static void add(T& n, CharT ch) 190 { 191 n += radix_traits<Radix>::digit(ch); 161 static T const max = (std::numeric_limits<T>::max)(); 162 static T const max_div_radix = max/Radix; 163 164 if (n > max_div_radix) 165 return false; 166 n *= Radix; 167 168 if (n > max - digit) 169 return false; 170 n += digit; 171 172 return true; 192 173 } 193 174 }; 194 195 template < int Radix>175 176 template <typename T, int Radix> 196 177 struct negative_accumulate 197 178 { 198 179 // Use this accumulator if number is negative 199 200 template <typename T> 201 static bool check(T const& n, T const& prev) 202 { 203 return n > prev; 204 } 205 206 template <typename T, typename CharT> 207 static void add(T& n, CharT ch) 180 static bool add(T& n, T digit) 208 181 { 209 n -= radix_traits<Radix>::digit(ch); 210 } 211 }; 212 213 template <int Radix, typename Accumulate> 214 struct extract_int_base 215 { 216 // Common code for extract_int specializations 217 template <typename ScannerT, typename T> 218 static bool 219 f(ScannerT& scan, T& n) 220 { 221 T prev = n; 182 typedef std::numeric_limits<T> num_limits; 183 static T const min = 184 (!num_limits::is_integer && num_limits::is_signed && num_limits::has_denorm) ? 185 -(num_limits::max)() : (num_limits::min)(); 186 static T const min_div_radix = min/Radix; 187 188 if (n < min_div_radix) 189 return false; 222 190 n *= Radix; 223 if (Accumulate::check(n, prev)) 224 return false; // over/underflow! 225 prev = n; 226 Accumulate::add(n, *scan); 227 if (Accumulate::check(n, prev)) 228 return false; // over/underflow! 191 192 if (n < min + digit) 193 return false; 194 n -= digit; 195 229 196 return true; 230 197 } 231 198 }; 232 199 233 template <bool Bounded> 234 struct extract_int_ 235 { 236 template < 237 int Radix, 238 unsigned MinDigits, 239 int MaxDigits, 240 typename Accumulate 241 > 242 struct apply 243 { 244 typedef extract_int_base<Radix, Accumulate> base; 245 typedef radix_traits<Radix> check; 246 247 template <typename ScannerT, typename T> 248 static bool 249 f(ScannerT& scan, T& n, std::size_t& count) 250 { 251 std::size_t i = 0; 252 for (; (i < MaxDigits) && !scan.at_end() 253 && check::is_valid(*scan); 254 ++i, ++scan, ++count) 255 { 256 if (!base::f(scan, n)) 257 return false; // over/underflow! 258 } 259 return i >= MinDigits; 260 } 261 }; 262 }; 263 200 template <int MaxDigits> 201 inline bool allow_more_digits(std::size_t i) 202 { 203 return i < MaxDigits; 204 } 205 264 206 template <> 265 struct extract_int_<false>207 inline bool allow_more_digits<-1>(std::size_t) 266 208 { 267 template < 268 int Radix, 269 unsigned MinDigits, 270 int MaxDigits, 271 typename Accumulate 272 > 273 struct apply 274 { 275 typedef extract_int_base<Radix, Accumulate> base; 276 typedef radix_traits<Radix> check; 277 278 template <typename ScannerT, typename T> 279 static bool 280 f(ScannerT& scan, T& n, std::size_t& count) 281 { 282 std::size_t i = 0; 283 for (; !scan.at_end() && check::is_valid(*scan); 284 ++i, ++scan, ++count) 285 { 286 if (!base::f(scan, n)) 287 return false; // over/underflow! 288 } 289 return i >= MinDigits; 290 } 291 }; 292 }; 293 209 return true; 210 } 211 294 212 ////////////////////////////////// 295 213 template < 296 214 int Radix, unsigned MinDigits, int MaxDigits, 297 typename Accumulate = positive_accumulate<Radix>215 typename Accumulate 298 216 > 299 217 struct extract_int 300 218 { … … 302 220 static bool 303 221 f(ScannerT& scan, T& n, std::size_t& count) 304 222 { 305 typedef typename extract_int_<(MaxDigits >= 0)>::template 306 apply<Radix, MinDigits, MaxDigits, Accumulate> extractor; 307 return extractor::f(scan, n, count); 223 std::size_t i = 0; 224 T digit; 225 while( allow_more_digits<MaxDigits>(i) && !scan.at_end() && 226 radix_traits<Radix>::digit(*scan, digit) ) 227 { 228 if (!Accumulate::add(n, digit)) 229 return false; // Overflow 230 ++i, ++scan, ++count; 231 } 232 return i >= MinDigits; 308 233 } 309 234 }; 310 235 … … 339 264 T n = 0; 340 265 std::size_t count = 0; 341 266 typename ScannerT::iterator_t save = scan.first; 342 if (extract_int<Radix, MinDigits, MaxDigits >::343 f(scan, n, count))267 if (extract_int<Radix, MinDigits, MaxDigits, 268 positive_accumulate<T, Radix> >::f(scan, n, count)) 344 269 { 345 270 return scan.create_match(count, n, save, scan.first); 346 271 } … … 377 302 parse(ScannerT const& scan) const 378 303 { 379 304 typedef extract_int<Radix, MinDigits, MaxDigits, 380 negative_accumulate< Radix> > extract_int_neg_t;381 typedef extract_int<Radix, MinDigits, MaxDigits >382 extract_int_pos_t;305 negative_accumulate<T, Radix> > extract_int_neg_t; 306 typedef extract_int<Radix, MinDigits, MaxDigits, 307 positive_accumulate<T, Radix> > extract_int_pos_t; 383 308 384 309 if (!scan.at_end()) 385 310 {