Skip to content

Commit a321881

Browse files
committed
test readFloat
1 parent 08899a1 commit a321881

4 files changed

Lines changed: 106 additions & 64 deletions

File tree

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

Lines changed: 49 additions & 61 deletions
Original file line numberDiff line numberDiff line change
@@ -36,20 +36,32 @@ OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
3636
class IterImplNumber {
3737

3838
final static int[] digits = new int[256];
39+
final static int[] zeroToNineDigits = new int[256];
40+
final static int END_OF_NUMBER = -2;
41+
final static int DOT_IN_NUMBER = -3;
42+
final static int INVALID_CHAR_FOR_NUMBER = -1;
43+
private static final int POW10[] = {1, 10, 100, 1000, 10000, 100000, 1000000};
3944

4045
static {
4146
for (int i = 0; i < digits.length; i++) {
42-
digits[i] = -1;
47+
digits[i] = INVALID_CHAR_FOR_NUMBER;
48+
zeroToNineDigits[i] = INVALID_CHAR_FOR_NUMBER;
4349
}
4450
for (int i = '0'; i <= '9'; ++i) {
4551
digits[i] = (i - '0');
52+
zeroToNineDigits[i] = (i - '0');
4653
}
4754
for (int i = 'a'; i <= 'f'; ++i) {
4855
digits[i] = ((i - 'a') + 10);
4956
}
5057
for (int i = 'A'; i <= 'F'; ++i) {
5158
digits[i] = ((i - 'A') + 10);
5259
}
60+
zeroToNineDigits[','] = END_OF_NUMBER;
61+
zeroToNineDigits[']'] = END_OF_NUMBER;
62+
zeroToNineDigits['}'] = END_OF_NUMBER;
63+
zeroToNineDigits[' '] = END_OF_NUMBER;
64+
zeroToNineDigits['.'] = DOT_IN_NUMBER;
5365
}
5466

5567
public static final double readDouble(JsonIterator iter) throws IOException {
@@ -147,84 +159,61 @@ public static final double readDoubleSlowPath(JsonIterator iter) throws IOExcept
147159

148160
public static final float readFloat(JsonIterator iter) throws IOException {
149161
final byte c = IterImpl.nextToken(iter);
150-
// when re-read using slowpath, it should include the first byte
151-
iter.unreadByte();
152162
if (c == '-') {
153-
// skip '-' by + 1
154-
return readNegativeFloat(iter, iter.head + 1);
163+
return -readPositiveFloat(iter);
164+
} else {
165+
iter.unreadByte();
166+
return readPositiveFloat(iter);
155167
}
156-
return readPositiveFloat(iter, iter.head);
157168
}
158169

159-
private static final float readPositiveFloat(JsonIterator iter, int start) throws IOException {
160-
long value = 0;
161-
byte c = ' ';
162-
int i = start;
163-
for (; i < iter.tail; i++) {
164-
c = iter.buf[i];
165-
if (c == ',' || c == '}' || c == ']' || c == ' ') {
166-
iter.head = i;
167-
return value;
168-
}
169-
if (c == '.') break;
170-
final int ind = digits[c];
171-
value = (value << 3) + (value << 1) + ind;
172-
if (ind < 0 || ind > 9) {
173-
return readFloatSlowPath(iter);
174-
}
175-
}
176-
if (c == '.') {
177-
i++;
178-
long div = 1;
179-
for (; i < iter.tail; i++) {
180-
c = iter.buf[i];
181-
if (c == ',' || c == '}' || c == ']' || c == ' ') {
182-
iter.head = i;
183-
return value / (float) div;
184-
}
185-
final int ind = digits[c];
186-
div = (div << 3) + (div << 1);
187-
value = (value << 3) + (value << 1) + ind;
188-
if (ind < 0 || ind > 9) {
189-
return readFloatSlowPath(iter);
190-
}
191-
}
192-
}
193-
return readFloatSlowPath(iter);
194-
}
170+
private final static long SAFE_TO_MULTIPLY_10 = (Long.MAX_VALUE / 10) - 10;
195171

196-
private static final float readNegativeFloat(JsonIterator iter, int start) throws IOException {
197-
long value = 0;
172+
private static final float readPositiveFloat(JsonIterator iter) throws IOException {
173+
long value = 0; // without the dot
198174
byte c = ' ';
199-
int i = start;
175+
int i = iter.head;
176+
non_decimal_loop:
200177
for (; i < iter.tail; i++) {
201178
c = iter.buf[i];
202-
if (c == ',' || c == '}' || c == ']' || c == ' ') {
203-
iter.head = i;
204-
return value;
179+
final int ind = zeroToNineDigits[c];
180+
switch (ind) {
181+
case INVALID_CHAR_FOR_NUMBER:
182+
return readFloatSlowPath(iter);
183+
case END_OF_NUMBER:
184+
iter.head = i;
185+
return value;
186+
case DOT_IN_NUMBER:
187+
break non_decimal_loop;
205188
}
206-
if (c == '.') break;
207-
final int ind = digits[c];
208-
value = (value << 3) + (value << 1) - ind;
209-
if (ind < 0 || ind > 9) {
189+
if (value > SAFE_TO_MULTIPLY_10) {
210190
return readFloatSlowPath(iter);
211191
}
192+
value = (value << 3) + (value << 1) + ind; // value = value * 10 + ind;
212193
}
213194
if (c == '.') {
214195
i++;
215-
long div = 1;
196+
int decimalPlaces = 0;
216197
for (; i < iter.tail; i++) {
217198
c = iter.buf[i];
218-
if (c == ',' || c == '}' || c == ']' || c == ' ') {
219-
iter.head = i;
220-
return value / (float) div;
199+
final int ind = zeroToNineDigits[c];
200+
switch (ind) {
201+
case END_OF_NUMBER:
202+
if (decimalPlaces > 0 && decimalPlaces < POW10.length) {
203+
iter.head = i;
204+
return value / (float) POW10[decimalPlaces];
205+
}
206+
// too many decimal places
207+
return readFloatSlowPath(iter);
208+
case INVALID_CHAR_FOR_NUMBER:
209+
case DOT_IN_NUMBER:
210+
return readFloatSlowPath(iter);
221211
}
222-
final int ind = digits[c];
223-
div = (div << 3) + (div << 1);
224-
value = (value << 3) + (value << 1) - ind;
225-
if (ind < 0 || ind > 9) {
212+
decimalPlaces++;
213+
if (value > SAFE_TO_MULTIPLY_10) {
226214
return readFloatSlowPath(iter);
227215
}
216+
value = (value << 3) + (value << 1) + ind; // value = value * 10 + ind;
228217
}
229218
}
230219
return readFloatSlowPath(iter);
@@ -248,7 +237,6 @@ public static final String readNumber(JsonIterator iter) throws IOException {
248237
}
249238
switch (c) {
250239
case '-':
251-
case '+':
252240
case '.':
253241
case 'e':
254242
case 'E':

src/main/java/com/jsoniter/output/JsonStream.java

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,6 @@ public class JsonStream extends OutputStream {
1414
public int indentionStep = defaultIndentionStep;
1515
private int indention = 0;
1616
private OutputStream out;
17-
char[] reusableChars = new char[32];
1817
private static final byte[] NULL = "null".getBytes();
1918
private static final byte[] TRUE = "true".getBytes();
2019
private static final byte[] FALSE = "false".getBytes();

src/test/java/com/jsoniter/TestDemo.java

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -124,10 +124,23 @@ public void test_iterator() throws IOException {
124124
assertNull(iter.readObject()); // end object
125125
}
126126

127-
public void test_lazy() throws IOException {
128-
JsonStream.setMode(EncodingMode.DYNAMIC_MODE);
127+
public void test_any_is_fun() throws IOException {
129128
Any any = JsonIterator.deserialize("{'numbers': ['1', '2', ['3', '4']]}".replace('\'', '"'));
130129
any.get("numbers").asList().add(Any.wrap("hello"));
131130
assertEquals("{'numbers':['1', '2', ['3', '4'],'hello']}".replace('\'', '"'), JsonStream.serialize(any));
131+
any = JsonIterator.deserialize("{'error': 'failed'}".replace('\'', '"'));
132+
assertFalse(any.toBoolean("success"));
133+
any = JsonIterator.deserialize("{'success': true}".replace('\'', '"'));
134+
assertTrue(any.toBoolean("success"));
135+
any = JsonIterator.deserialize("{'success': 'false'}".replace('\'', '"'));
136+
assertFalse(any.toBoolean("success"));
137+
any = JsonIterator.deserialize("[{'score':100}, {'score':102}]".replace('\'', '"'));
138+
assertEquals("[100,102]", JsonStream.serialize(any.get('*', "score")));
139+
any = JsonIterator.deserialize("[{'score':100}, {'score':[102]}]".replace('\'', '"'));
140+
assertEquals("[{},{'score':102}]".replace('\'', '"'), JsonStream.serialize(any.get('*', '*', 0)));
141+
any = JsonIterator.deserialize("[{'score':100}, {'score':102}]".replace('\'', '"'));
142+
assertEquals(Long.class, any.get(0, "score").object().getClass());
143+
any = JsonIterator.deserialize("[{'score':100}, {'score':102}]".replace('\'', '"'));
144+
assertEquals(ValueType.INVALID, any.get(0, "score", "number").valueType());
132145
}
133146
}
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
package com.jsoniter;
2+
3+
import junit.framework.TestCase;
4+
import org.junit.experimental.categories.Category;
5+
6+
import java.io.ByteArrayInputStream;
7+
import java.io.IOException;
8+
9+
public class TestFloat extends TestCase {
10+
11+
private boolean isStreaming;
12+
13+
public void test_positive_negative() throws IOException {
14+
// positive
15+
assertEquals(12.3f, parseFloat("12.3,"));
16+
// negative
17+
assertEquals(-12.3f, parseFloat("-12.3,"));
18+
}
19+
20+
public void test_too_large() throws IOException {
21+
assertEquals(Long.MAX_VALUE, parseFloat("9223372036854775807,"), 0.01f);
22+
assertEquals(9923372036854775807f, parseFloat("9923372036854775807,"), 0.01f);
23+
assertEquals(720368.54775807f, parseFloat("720368.54775807,"), 0.01f);
24+
assertEquals(72036.854775807f, parseFloat("72036.854775807,"), 0.01f);
25+
assertEquals(720368.54775807f, parseFloat("720368.547758075,"), 0.01f);
26+
}
27+
28+
@Category(StreamingCategory.class)
29+
public void test_streaming() throws IOException {
30+
isStreaming = true;
31+
test_positive_negative();
32+
test_too_large();
33+
}
34+
35+
private float parseFloat(String input) throws IOException {
36+
if (isStreaming) {
37+
return JsonIterator.parse(new ByteArrayInputStream(input.getBytes()), 2).readFloat();
38+
} else {
39+
return JsonIterator.parse(input).readFloat();
40+
}
41+
}
42+
}

0 commit comments

Comments
 (0)