Skip to content

Commit 648e227

Browse files
committed
add Base64FloatSupport
1 parent 78ed4d0 commit 648e227

6 files changed

Lines changed: 294 additions & 125 deletions

File tree

src/main/java/com/jsoniter/CodegenImplNative.java

Lines changed: 15 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -196,19 +196,22 @@ private static String genReadOp(String cacheKey, Type valueType) {
196196
// if cache key is for field, and there is no field decoder specified
197197
// update cache key for normal type
198198
cacheKey = TypeLiteral.create(valueType).getDecoderCacheKey();
199-
if (valueType instanceof Class) {
200-
Class clazz = (Class) valueType;
201-
String nativeRead = NATIVE_READS.get(clazz.getCanonicalName());
202-
if (nativeRead != null) {
203-
return nativeRead;
199+
decoder = JsoniterSpi.getDecoder(cacheKey);
200+
if (decoder == null) {
201+
if (valueType instanceof Class) {
202+
Class clazz = (Class) valueType;
203+
String nativeRead = NATIVE_READS.get(clazz.getCanonicalName());
204+
if (nativeRead != null) {
205+
return nativeRead;
206+
}
207+
}
208+
Codegen.getDecoder(cacheKey, valueType);
209+
if (Codegen.canStaticAccess(cacheKey)) {
210+
return String.format("%s.decode_(iter)", cacheKey);
211+
} else {
212+
// can not use static "decode_" method to access, go through codegen cache
213+
return String.format("com.jsoniter.CodegenAccess.read(\"%s\", iter)", cacheKey);
204214
}
205-
}
206-
Codegen.getDecoder(cacheKey, valueType);
207-
if (Codegen.canStaticAccess(cacheKey)) {
208-
return String.format("%s.decode_(iter)", cacheKey);
209-
} else {
210-
// can not use static "decode_" method to access, go through codegen cache
211-
return String.format("com.jsoniter.CodegenAccess.read(\"%s\", iter)", cacheKey);
212215
}
213216
}
214217
if (valueType == boolean.class) {

src/main/java/com/jsoniter/extra/Base64.java

Lines changed: 41 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
package com.jsoniter.extra;
22

3+
import com.jsoniter.JsonIterator;
4+
import com.jsoniter.Slice;
35
import com.jsoniter.output.JsonStream;
46

57
import java.io.IOException;
@@ -75,8 +77,8 @@
7577

7678
abstract class Base64 {
7779
private static final char[] CA = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/".toCharArray();
78-
private static final byte[] BA;
79-
private static final int[] IA = new int[256];
80+
static final byte[] BA;
81+
static final int[] IA = new int[256];
8082
static {
8183
Arrays.fill(IA, -1);
8284
for (int i = 0, iS = CA.length; i < iS; i++) {
@@ -151,33 +153,43 @@ static int encodeToBytes(byte[] sArr, JsonStream stream) throws IOException {
151153
return dLen;
152154
}
153155

154-
// static int encodeToBytes(long sArr, JsonStream stream) throws IOException {
155-
// final int sLen = 8;
156-
//
157-
// final int eLen = (sLen / 3) * 3; // Length of even 24-bits.
158-
// final int dLen = ((sLen - 1) / 3 + 1) << 2; // Returned character count
159-
//
160-
// // Encode even 24-bits
161-
// for (int s = 0; s < eLen;) {
162-
// // Copy next three bytes into lower 24 bits of int, paying attension to sign.
163-
// int i = (sArr[s++] & 0xff) << 16 | (sArr[s++] & 0xff) << 8 | (sArr[s++] & 0xff);
164-
//
165-
// // Encode the int into four chars
166-
// stream.write(BA[(i >>> 18) & 0x3f], BA[(i >>> 12) & 0x3f], BA[(i >>> 6) & 0x3f], BA[i & 0x3f]);
167-
// }
168-
//
169-
// // Pad and encode last bits if source isn't even 24 bits.
170-
// int left = sLen - eLen; // 0 - 2.
171-
// if (left > 0) {
172-
// // Prepare the int
173-
// int i = ((sArr[eLen] & 0xff) << 10) | (left == 2 ? ((sArr[sLen - 1] & 0xff) << 2) : 0);
174-
//
175-
// // Set last four chars
176-
// stream.write(BA[i >> 12], BA[(i >>> 6) & 0x3f], left == 2 ? BA[i & 0x3f] : (byte)'=', (byte)'=');
177-
// }
178-
//
179-
// return dLen;
180-
// }
156+
static void encodeLongBits(long bits, JsonStream stream) throws IOException {
157+
int i = (int) bits;
158+
byte b1 = BA[(i >>> 18) & 0x3f];
159+
byte b2 = BA[(i >>> 12) & 0x3f];
160+
byte b3 = BA[(i >>> 6) & 0x3f];
161+
byte b4 = BA[i & 0x3f];
162+
stream.write((byte)'"', b1, b2, b3, b4);
163+
bits = bits >>> 24;
164+
i = (int) bits;
165+
b1 = BA[(i >>> 18) & 0x3f];
166+
b2 = BA[(i >>> 12) & 0x3f];
167+
b3 = BA[(i >>> 6) & 0x3f];
168+
b4 = BA[i & 0x3f];
169+
stream.write(b1, b2, b3, b4);
170+
bits = (bits >>> 24) << 2;
171+
i = (int) bits;
172+
b1 = BA[i >> 12];
173+
b2 = BA[(i >>> 6) & 0x3f];
174+
b3 = BA[i & 0x3f];
175+
stream.write(b1, b2, b3, (byte)'"');
176+
}
177+
178+
static long decodeLongBits(JsonIterator iter) throws IOException {
179+
Slice slice = iter.readStringAsSlice();
180+
if (slice.len() != 11) {
181+
throw iter.reportError("decodeLongBits", "must be 11 bytes for long bits encoded double");
182+
}
183+
byte[] encoded = slice.data();
184+
int sIx = slice.head();
185+
long i = IA[encoded[sIx++]] << 18 | IA[encoded[sIx++]] << 12 | IA[encoded[sIx++]] << 6 | IA[encoded[sIx++]];
186+
long bits = i;
187+
i = IA[encoded[sIx++]] << 18 | IA[encoded[sIx++]] << 12 | IA[encoded[sIx++]] << 6 | IA[encoded[sIx++]];
188+
bits = i << 24 | bits;
189+
i = IA[encoded[sIx++]] << 12 | IA[encoded[sIx++]] << 6 | IA[encoded[sIx]];
190+
bits = i << 46 | bits;
191+
return bits;
192+
}
181193

182194
static int findEnd(final byte[] sArr, final int start) {
183195
for (int i = start; i < sArr.length; i++)
Lines changed: 224 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,224 @@
1+
package com.jsoniter.extra;
2+
3+
import com.jsoniter.CodegenAccess;
4+
import com.jsoniter.JsonIterator;
5+
import com.jsoniter.Slice;
6+
import com.jsoniter.any.Any;
7+
import com.jsoniter.output.JsonStream;
8+
import com.jsoniter.spi.Decoder;
9+
import com.jsoniter.spi.Encoder;
10+
import com.jsoniter.spi.JsonException;
11+
import com.jsoniter.spi.JsoniterSpi;
12+
13+
import java.io.IOException;
14+
15+
/**
16+
* encode float/double as base64, faster than PreciseFloatSupport
17+
*/
18+
public class Base64FloatSupport {
19+
20+
final static int[] DIGITS = new int[256];
21+
final static int[] HEX = new int[]{'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'};
22+
final static int[] DEC = new int[127];
23+
24+
static {
25+
for (int i = 0; i < 256; i++) {
26+
DIGITS[i] = HEX[i >> 4] << 8 | HEX[i & 0xf];
27+
}
28+
DEC['0'] = 0;
29+
DEC['1'] = 1;
30+
DEC['2'] = 2;
31+
DEC['3'] = 3;
32+
DEC['4'] = 4;
33+
DEC['5'] = 5;
34+
DEC['6'] = 6;
35+
DEC['7'] = 7;
36+
DEC['8'] = 8;
37+
DEC['9'] = 9;
38+
DEC['a'] = 10;
39+
DEC['b'] = 11;
40+
DEC['c'] = 12;
41+
DEC['d'] = 13;
42+
DEC['e'] = 14;
43+
DEC['f'] = 15;
44+
}
45+
46+
private static boolean enabled;
47+
48+
public static synchronized void enableEncodersAndDecoders() {
49+
if (enabled) {
50+
throw new JsonException("BinaryFloatSupport.enable can only be called once");
51+
}
52+
enabled = true;
53+
enableDecoders();
54+
JsoniterSpi.registerTypeEncoder(Double.class, new Encoder() {
55+
@Override
56+
public void encode(Object obj, JsonStream stream) throws IOException {
57+
Double number = (Double) obj;
58+
long bits = Double.doubleToRawLongBits(number.doubleValue());
59+
Base64.encodeLongBits(bits, stream);
60+
}
61+
62+
@Override
63+
public Any wrap(Object obj) {
64+
Double number = (Double) obj;
65+
return Any.wrap(number.doubleValue());
66+
}
67+
});
68+
JsoniterSpi.registerTypeEncoder(double.class, new Encoder.DoubleEncoder() {
69+
@Override
70+
public void encodeDouble(double obj, JsonStream stream) throws IOException {
71+
long bits = Double.doubleToRawLongBits(obj);
72+
Base64.encodeLongBits(bits, stream);
73+
}
74+
});
75+
JsoniterSpi.registerTypeEncoder(Float.class, new Encoder() {
76+
@Override
77+
public void encode(Object obj, JsonStream stream) throws IOException {
78+
Float number = (Float) obj;
79+
long bits = Double.doubleToRawLongBits(number.doubleValue());
80+
Base64.encodeLongBits(bits, stream);
81+
}
82+
83+
@Override
84+
public Any wrap(Object obj) {
85+
Float number = (Float) obj;
86+
return Any.wrap(number.floatValue());
87+
}
88+
});
89+
JsoniterSpi.registerTypeEncoder(float.class, new Encoder.FloatEncoder() {
90+
@Override
91+
public void encodeFloat(float obj, JsonStream stream) throws IOException {
92+
long bits = Double.doubleToRawLongBits(obj);
93+
Base64.encodeLongBits(bits, stream);
94+
}
95+
});
96+
}
97+
98+
public static void enableDecoders() {
99+
JsoniterSpi.registerTypeDecoder(Double.class, new Decoder() {
100+
@Override
101+
public Object decode(JsonIterator iter) throws IOException {
102+
byte token = CodegenAccess.nextToken(iter);
103+
CodegenAccess.unreadByte(iter);
104+
if (token == '"') {
105+
return Double.longBitsToDouble(Base64.decodeLongBits(iter));
106+
} else {
107+
return iter.readDouble();
108+
}
109+
}
110+
});
111+
JsoniterSpi.registerTypeDecoder(double.class, new Decoder.DoubleDecoder() {
112+
@Override
113+
public double decodeDouble(JsonIterator iter) throws IOException {
114+
byte token = CodegenAccess.nextToken(iter);
115+
CodegenAccess.unreadByte(iter);
116+
if (token == '"') {
117+
return Double.longBitsToDouble(Base64.decodeLongBits(iter));
118+
}else {
119+
return iter.readDouble();
120+
}
121+
}
122+
});
123+
JsoniterSpi.registerTypeDecoder(Float.class, new Decoder() {
124+
@Override
125+
public Object decode(JsonIterator iter) throws IOException {
126+
byte token = CodegenAccess.nextToken(iter);
127+
CodegenAccess.unreadByte(iter);
128+
if (token == '"') {
129+
return (float)Double.longBitsToDouble(Base64.decodeLongBits(iter));
130+
}else {
131+
return (float)iter.readDouble();
132+
}
133+
}
134+
});
135+
JsoniterSpi.registerTypeDecoder(float.class, new Decoder.FloatDecoder() {
136+
@Override
137+
public float decodeFloat(JsonIterator iter) throws IOException {
138+
byte token = CodegenAccess.nextToken(iter);
139+
CodegenAccess.unreadByte(iter);
140+
if (token == '"') {
141+
return (float)Double.longBitsToDouble(Base64.decodeLongBits(iter));
142+
}else {
143+
return (float)iter.readDouble();
144+
}
145+
}
146+
});
147+
}
148+
149+
private static long readLongBits(JsonIterator iter) throws IOException {
150+
Slice slice = iter.readStringAsSlice();
151+
byte[] data = slice.data();
152+
long val = 0;
153+
for (int i = slice.head(); i < slice.tail(); i++) {
154+
byte b = data[i];
155+
val = val << 4 | DEC[b];
156+
}
157+
return val;
158+
}
159+
160+
private static void writeLongBits(long bits, JsonStream stream) throws IOException {
161+
int digit = DIGITS[(int) (bits & 0xff)];
162+
byte b2 = (byte) (digit >> 8);
163+
byte b1 = (byte) digit;
164+
bits = bits >> 8;
165+
if (bits == 0) {
166+
stream.write((byte) '"', b2, b1, (byte) '"');
167+
}
168+
digit = DIGITS[(int) (bits & 0xff)];
169+
byte b4 = (byte) (digit >> 8);
170+
byte b3 = (byte) digit;
171+
bits = bits >> 8;
172+
if (bits == 0) {
173+
stream.write((byte) '"', b4, b3, b2, b1, (byte) '"');
174+
}
175+
digit = DIGITS[(int) (bits & 0xff)];
176+
byte b6 = (byte) (digit >> 8);
177+
byte b5 = (byte) digit;
178+
bits = bits >> 8;
179+
if (bits == 0) {
180+
stream.write((byte) '"', b6, b5, b4, b3);
181+
stream.write(b2, b1, (byte) '"');
182+
}
183+
digit = DIGITS[(int) (bits & 0xff)];
184+
byte b8 = (byte) (digit >> 8);
185+
byte b7 = (byte) digit;
186+
bits = bits >> 8;
187+
if (bits == 0) {
188+
stream.write((byte) '"', b8, b7, b6, b5, b4);
189+
stream.write(b3, b2, b1, (byte) '"');
190+
}
191+
digit = DIGITS[(int) (bits & 0xff)];
192+
byte b10 = (byte) (digit >> 8);
193+
byte b9 = (byte) digit;
194+
bits = bits >> 8;
195+
if (bits == 0) {
196+
stream.write((byte) '"', b10, b9, b8, b7, b6);
197+
stream.write(b5, b4, b3, b2, b1, (byte) '"');
198+
}
199+
digit = DIGITS[(int) (bits & 0xff)];
200+
byte b12 = (byte) (digit >> 8);
201+
byte b11 = (byte) digit;
202+
bits = bits >> 8;
203+
if (bits == 0) {
204+
stream.write((byte) '"', b12, b11, b10, b9, b8);
205+
stream.write(b7, b6, b5, b4, b3, b2);
206+
stream.write(b1, (byte) '"');
207+
}
208+
digit = DIGITS[(int) (bits & 0xff)];
209+
byte b14 = (byte) (digit >> 8);
210+
byte b13 = (byte) digit;
211+
bits = bits >> 8;
212+
if (bits == 0) {
213+
stream.write((byte) '"', b14, b13, b12, b11, b10);
214+
stream.write(b9, b8, b7, b6, b5, b4);
215+
stream.write(b3, b2, b1, (byte) '"');
216+
}
217+
digit = DIGITS[(int) (bits & 0xff)];
218+
byte b16 = (byte) (digit >> 8);
219+
byte b15 = (byte) digit;
220+
stream.write((byte) '"', b16, b15, b14, b13, b12);
221+
stream.write(b11, b10, b9, b8, b7, b6);
222+
stream.write(b5, b4, b3, b2, b1, (byte) '"');
223+
}
224+
}

0 commit comments

Comments
 (0)