Author: Antonio Cuni <[email protected]>
Branch: fastjson
Changeset: r65051:01e0cc2cf8c8
Date: 2013-06-28 11:48 +0200
http://bitbucket.org/pypy/pypy/changeset/01e0cc2cf8c8/
Log: add support for big numbers which are turned into longs
diff --git a/pypy/module/_fastjson/interp_decoder.py
b/pypy/module/_fastjson/interp_decoder.py
--- a/pypy/module/_fastjson/interp_decoder.py
+++ b/pypy/module/_fastjson/interp_decoder.py
@@ -1,3 +1,4 @@
+import sys
import math
from rpython.rlib.rstring import StringBuilder
from rpython.rlib.objectmodel import specialize
@@ -6,6 +7,8 @@
from pypy.interpreter import unicodehelper
from rpython.rtyper.annlowlevel import llstr, hlunicode
+OVF_DIGITS = len(str(sys.maxint))
+
def is_whitespace(ch):
return ch == ' ' or ch == '\t' or ch == '\r' or ch == '\n'
@@ -53,8 +56,8 @@
self.last_type = TYPE_UNKNOWN
def getslice(self, start, end):
- assert start > 0
- assert end > 0
+ assert start >= 0
+ assert end >= 0
return self.s[start:end]
def skip_whitespace(self, i):
@@ -117,7 +120,20 @@
self._raise("Error when decoding false at char %d", i)
def decode_numeric(self, i):
- i, intval = self.parse_integer(i, allow_leading_0=False)
+ w_res = self.decode_numeric_fast(i)
+ if w_res is self.space.w_None:
+ # possible overflow, reparse it
+ return self.decode_numeric_slow(i)
+ return w_res
+
+ def decode_numeric_fast(self, i):
+ i, ovf_maybe, intval = self.parse_integer(i, allow_leading_0=False)
+ if ovf_maybe:
+ # apparently we get a ~30% slowdown on my microbenchmark if we
+ # return None instead of w_None, probably because the annotation
+ # of the results geta can_be_None=True. We need to check if this
+ # is still true also for the full pypy
+ return self.space.w_None
#
is_float = False
exp = 0
@@ -134,7 +150,7 @@
# check for the optional exponent part
if ch == 'E' or ch == 'e':
is_float = True
- i, exp = self.parse_integer(i+1, allow_leading_0=True)
+ i, ovf_maybe, exp = self.parse_integer(i+1, allow_leading_0=True)
#
self.pos = i
if is_float:
@@ -146,8 +162,21 @@
else:
return self.space.wrap(intval)
+ def decode_numeric_slow(self, i):
+ start = i
+ if self.ll_chars[i] == '-':
+ i += 1
+ while self.ll_chars[i].isdigit():
+ i += 1
+ s = self.getslice(start, i)
+ self.pos = i
+ w_res = self.space.call_function(self.space.w_int, self.space.wrap(s))
+ #assert w_res is not None # XXX check if this brings any speedup in
pypy-c
+ return w_res
+
def parse_integer(self, i, allow_leading_0=False):
"Parse a decimal number with an optional minus sign"
+ start = i
sign = 1
if self.ll_chars[i] == '-':
sign = -1
@@ -156,9 +185,12 @@
i += 1
elif not allow_leading_0 and self.ll_chars[i] == '0':
i += 1
- return i, 0
+ return i, False, 0
i, intval, _ = self.parse_digits(i)
- return i, sign * intval
+ # if the number has more digits than OVF_DIGITS, it might have
+ # overflowed
+ ovf_maybe = (i-start >= OVF_DIGITS)
+ return i, ovf_maybe, sign * intval
parse_integer._always_inline_ = True
def parse_digits(self, i):
diff --git a/pypy/module/_fastjson/test/test__fastjson.py
b/pypy/module/_fastjson/test/test__fastjson.py
--- a/pypy/module/_fastjson/test/test__fastjson.py
+++ b/pypy/module/_fastjson/test/test__fastjson.py
@@ -118,6 +118,8 @@
check('0.123', 0.123)
check('0E3', 0.0)
check('5E0001', 50.0)
+ check(str(1 << 32), 1 << 32)
+ check(str(1 << 64), 1 << 64)
def test_decode_numeric_invalid(self):
import _fastjson
_______________________________________________
pypy-commit mailing list
[email protected]
http://mail.python.org/mailman/listinfo/pypy-commit