Skip to content

Commit 273069f

Browse files
committed
fix int min max
1 parent f23661f commit 273069f

3 files changed

Lines changed: 87 additions & 75 deletions

File tree

src/main/java/com/jsoniter/IterImplNumber.java

Lines changed: 50 additions & 70 deletions
Original file line numberDiff line numberDiff line change
@@ -35,16 +35,14 @@ OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
3535

3636
// TODO: make separate implementation for streaming and non-streaming
3737
class IterImplNumber {
38-
38+
3939
final static int[] digits = new int[256];
4040
private final static int[] intDigits = new int[256];
4141
private final static int[] floatDigits = new int[256];
4242
private final static int END_OF_NUMBER = -2;
4343
private final static int DOT_IN_NUMBER = -3;
4444
private final static int INVALID_CHAR_FOR_NUMBER = -1;
4545
private static final int POW10[] = {1, 10, 100, 1000, 10000, 100000, 1000000};
46-
private final static long LONG_SAFE_TO_MULTIPLY_10 = (Long.MAX_VALUE / 10) - 1;
47-
private final static int INT_SAFE_TO_MULTIPLY_10 = (Integer.MAX_VALUE / 10) - 1;
4846

4947
static {
5048
for (int i = 0; i < digits.length; i++) {
@@ -97,10 +95,11 @@ private static final double readPositiveDouble(final JsonIterator iter) throws I
9795
case DOT_IN_NUMBER:
9896
break non_decimal_loop;
9997
}
100-
if (value > LONG_SAFE_TO_MULTIPLY_10) {
98+
value = (value << 3) + (value << 1) + ind; // value = value * 10 + ind;
99+
if (value < 0) {
100+
// overflow
101101
return readDoubleSlowPath(iter);
102102
}
103-
value = (value << 3) + (value << 1) + ind; // value = value * 10 + ind;
104103
}
105104
if (c == '.') {
106105
i++;
@@ -121,10 +120,11 @@ private static final double readPositiveDouble(final JsonIterator iter) throws I
121120
return readDoubleSlowPath(iter);
122121
}
123122
decimalPlaces++;
124-
if (value > LONG_SAFE_TO_MULTIPLY_10) {
123+
value = (value << 3) + (value << 1) + ind; // value = value * 10 + ind;
124+
if (value < 0) {
125+
// overflow
125126
return readDoubleSlowPath(iter);
126127
}
127-
value = (value << 3) + (value << 1) + ind; // value = value * 10 + ind;
128128
}
129129
}
130130
return readDoubleSlowPath(iter);
@@ -165,10 +165,11 @@ private static final float readPositiveFloat(final JsonIterator iter) throws IOE
165165
case DOT_IN_NUMBER:
166166
break non_decimal_loop;
167167
}
168-
if (value > LONG_SAFE_TO_MULTIPLY_10) {
168+
value = (value << 3) + (value << 1) + ind; // value = value * 10 + ind;
169+
if (value < 0) {
170+
// overflow
169171
return readFloatSlowPath(iter);
170172
}
171-
value = (value << 3) + (value << 1) + ind; // value = value * 10 + ind;
172173
}
173174
if (c == '.') {
174175
i++;
@@ -189,10 +190,11 @@ private static final float readPositiveFloat(final JsonIterator iter) throws IOE
189190
return readFloatSlowPath(iter);
190191
}
191192
decimalPlaces++;
192-
if (value > LONG_SAFE_TO_MULTIPLY_10) {
193+
value = (value << 3) + (value << 1) + ind; // value = value * 10 + ind;
194+
if (value < 0) {
195+
// overflow
193196
return readFloatSlowPath(iter);
194197
}
195-
value = (value << 3) + (value << 1) + ind; // value = value * 10 + ind;
196198
}
197199
}
198200
return readFloatSlowPath(iter);
@@ -208,7 +210,7 @@ public static final float readFloatSlowPath(final JsonIterator iter) throws IOEx
208210

209211
public static final String readNumber(final JsonIterator iter) throws IOException {
210212
int j = 0;
211-
for (;;) {
213+
for (; ; ) {
212214
for (int i = iter.head; i < iter.tail; i++) {
213215
if (j == iter.reusableChars.length) {
214216
char[] newBuf = new char[iter.reusableChars.length * 2];
@@ -247,111 +249,89 @@ public static final String readNumber(final JsonIterator iter) throws IOExceptio
247249
public static final int readInt(final JsonIterator iter) throws IOException {
248250
byte c = IterImpl.nextToken(iter);
249251
if (c == '-') {
250-
return readNegativeInt(iter);
252+
return -readPositiveInt(iter, IterImpl.readByte(iter));
251253
} else {
252254
return readPositiveInt(iter, c);
253255
}
254256
}
255257

256258
public static final int readPositiveInt(final JsonIterator iter, byte c) throws IOException {
257-
int value = intDigits[c];
258-
if (value == 0) {
259+
int ind = intDigits[c];
260+
if (ind == 0) {
259261
return 0;
260262
}
261-
if (value == INVALID_CHAR_FOR_NUMBER) {
263+
if (ind == INVALID_CHAR_FOR_NUMBER) {
262264
throw iter.reportError("readPositiveInt", "expect 0~9");
263265
}
264-
for (;;) {
266+
int value = ind;
267+
for (; ; ) {
265268
for (int i = iter.head; i < iter.tail; i++) {
266-
int ind = intDigits[iter.buf[i]];
269+
ind = intDigits[iter.buf[i]];
267270
if (ind == INVALID_CHAR_FOR_NUMBER) {
268271
iter.head = i;
269272
return value;
270273
}
271-
if (value > INT_SAFE_TO_MULTIPLY_10) {
272-
int value2 = (value << 3) + (value << 1) + ind;
273-
if (value2 < INT_SAFE_TO_MULTIPLY_10 * 10) {
274-
throw iter.reportError("readPositiveInt", "value is too large for int");
274+
value = (value << 3) + (value << 1) + ind;
275+
if (value < 0) {
276+
// overflow
277+
if (value == Integer.MIN_VALUE) {
278+
// if there is more number following, subsequent read will fail anyway
279+
iter.head = i;
280+
return value;
275281
} else {
276-
value = value2;
277-
continue;
282+
throw iter.reportError("readPositiveInt", "value is too large for int");
278283
}
279284
}
280-
value = (value << 3) + (value << 1) + ind;
281285
}
282286
if (!IterImpl.loadMore(iter)) {
283287
return value;
284288
}
285289
}
286290
}
287291

288-
public static final int readNegativeInt(final JsonIterator iter) throws IOException {
289-
byte c = IterImpl.readByte(iter);
292+
public static final long readLong(JsonIterator iter) throws IOException {
293+
byte c = IterImpl.nextToken(iter);
294+
if (c == '-') {
295+
return -readPositiveLong(iter, IterImpl.readByte(iter));
296+
} else {
297+
return readPositiveLong(iter, c);
298+
}
299+
}
300+
301+
public static final long readPositiveLong(final JsonIterator iter, byte c) throws IOException {
290302
int ind = intDigits[c];
291303
if (ind == 0) {
292304
return 0;
293305
}
294306
if (ind == INVALID_CHAR_FOR_NUMBER) {
295-
throw iter.reportError("readNegativeInt", "expect 0~9");
307+
throw iter.reportError("readPositiveInt", "expect 0~9");
296308
}
297-
int value = -ind;
298-
for (;;) {
309+
long value = ind;
310+
for (; ; ) {
299311
for (int i = iter.head; i < iter.tail; i++) {
300312
ind = intDigits[iter.buf[i]];
301313
if (ind == INVALID_CHAR_FOR_NUMBER) {
302314
iter.head = i;
303315
return value;
304316
}
305-
if (value > INT_SAFE_TO_MULTIPLY_10) {
306-
int value2 = (value << 3) + (value << 1) - ind;
307-
if (value2 < INT_SAFE_TO_MULTIPLY_10 * 10) {
308-
throw iter.reportError("readNegativeInt", "value is too large for int");
317+
value = (value << 3) + (value << 1) + ind;
318+
if (value < 0) {
319+
// overflow
320+
if (value == Long.MIN_VALUE) {
321+
// if there is more number following, subsequent read will fail anyway
322+
iter.head = i;
323+
return value;
309324
} else {
310-
value = value2;
311-
continue;
325+
throw iter.reportError("readPositiveLong", "value is too large for long");
312326
}
313327
}
314-
value = (value << 3) + (value << 1) - ind;
315328
}
316329
if (!IterImpl.loadMore(iter)) {
317330
return value;
318331
}
319332
}
320333
}
321334

322-
public static final long readLong(JsonIterator iter) throws IOException {
323-
byte c = IterImpl.nextToken(iter);
324-
if (c == '-') {
325-
return -readUnsignedLong(iter);
326-
} else {
327-
iter.unreadByte();
328-
return readUnsignedLong(iter);
329-
}
330-
}
331-
332-
public static final long readUnsignedLong(JsonIterator iter) throws IOException {
333-
// TODO: throw overflow
334-
byte c = IterImpl.readByte(iter);
335-
int v = digits[c];
336-
if (v == 0) {
337-
return 0;
338-
}
339-
if (v == -1) {
340-
throw iter.reportError("readUnsignedLong", "expect 0~9");
341-
}
342-
long result = 0;
343-
for (; ; ) {
344-
result = result * 10 + v;
345-
c = IterImpl.readByte(iter);
346-
v = digits[c];
347-
if (v == -1) {
348-
iter.unreadByte();
349-
break;
350-
}
351-
}
352-
return result;
353-
}
354-
355335
public static final char readU4(JsonIterator iter) throws IOException {
356336
int v = digits[IterImpl.readByte(iter)];
357337
if (v == -1) {

src/test/java/com/jsoniter/TestFloat.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ public void test_positive_negative() throws IOException {
1919
assertEquals(-12.3d, parseDouble("-12.3,"));
2020
}
2121

22-
public void test_too_large() throws IOException {
22+
public void test_decimal_places() throws IOException {
2323
assertEquals(Long.MAX_VALUE, parseFloat("9223372036854775807,"), 0.01f);
2424
assertEquals(Long.MAX_VALUE, parseDouble("9223372036854775807,"), 0.01f);
2525
assertEquals(9923372036854775807f, parseFloat("9923372036854775807,"), 0.01f);
@@ -36,7 +36,7 @@ public void test_too_large() throws IOException {
3636
public void test_streaming() throws IOException {
3737
isStreaming = true;
3838
test_positive_negative();
39-
test_too_large();
39+
test_decimal_places();
4040
}
4141

4242
private float parseFloat(String input) throws IOException {

src/test/java/com/jsoniter/TestInteger.java

Lines changed: 35 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,19 +11,38 @@ public class TestInteger extends TestCase {
1111

1212
private boolean isStreaming;
1313

14-
public void test_positive_negative() throws IOException {
14+
public void test_positive_negative_int() throws IOException {
1515
assertEquals(4321, parseInt("4321"));
1616
assertEquals(-4321, parseInt("-4321"));
1717
}
1818

19+
public void test_positive_negative_long() throws IOException {
20+
assertEquals(4321L, parseLong("4321"));
21+
assertEquals(-4321L, parseLong("-4321"));
22+
}
23+
1924
public void test_max_min_int() throws IOException {
2025
assertEquals(Integer.MAX_VALUE, parseInt(Integer.toString(Integer.MAX_VALUE)));
26+
assertEquals(Integer.MAX_VALUE - 1, parseInt(Integer.toString(Integer.MAX_VALUE - 1)));
27+
assertEquals(Integer.MIN_VALUE + 1, parseInt(Integer.toString(Integer.MIN_VALUE + 1)));
2128
assertEquals(Integer.MIN_VALUE, parseInt(Integer.toString(Integer.MIN_VALUE)));
2229
}
2330

31+
public void test_max_min_long() throws IOException {
32+
assertEquals(Long.MAX_VALUE, parseLong(Long.toString(Long.MAX_VALUE)));
33+
assertEquals(Long.MAX_VALUE - 1, parseLong(Long.toString(Long.MAX_VALUE - 1)));
34+
assertEquals(Long.MIN_VALUE + 1, parseLong(Long.toString(Long.MIN_VALUE + 1)));
35+
assertEquals(Long.MIN_VALUE, parseLong(Long.toString(Long.MIN_VALUE)));
36+
}
37+
2438
public void test_large_number() throws IOException {
2539
try {
26-
parseInt("123456789123456789");
40+
JsonIterator.deserialize(Integer.toString(Integer.MIN_VALUE) + "1", Integer.class);
41+
fail();
42+
} catch (JsonException e) {
43+
}
44+
try {
45+
JsonIterator.deserialize(Long.toString(Long.MAX_VALUE) + "1", Long.class);
2746
fail();
2847
} catch (JsonException e) {
2948
}
@@ -32,7 +51,10 @@ public void test_large_number() throws IOException {
3251
@Category(StreamingCategory.class)
3352
public void test_streaming() throws IOException {
3453
isStreaming = true;
35-
test_positive_negative();
54+
test_positive_negative_int();
55+
test_positive_negative_long();
56+
test_max_min_int();
57+
test_max_min_long();
3658
test_large_number();
3759
}
3860

@@ -45,4 +67,14 @@ private int parseInt(String input) throws IOException {
4567
return iter.readInt();
4668
}
4769
}
70+
71+
private long parseLong(String input) throws IOException {
72+
if (isStreaming) {
73+
JsonIterator iter = JsonIterator.parse(new ByteArrayInputStream(input.getBytes()), 2);
74+
return iter.readLong();
75+
} else {
76+
JsonIterator iter = JsonIterator.parse(input);
77+
return iter.readLong();
78+
}
79+
}
4880
}

0 commit comments

Comments
 (0)