├── .idea ├── .name ├── .gitignore ├── codeStyles │ ├── codeStyleConfig.xml │ └── Project.xml ├── vcs.xml ├── encodings.xml ├── modules.xml ├── inspectionProfiles │ └── Project_Default.xml └── misc.xml ├── .gitignore ├── .settings ├── org.eclipse.core.runtime.prefs ├── org.eclipse.core.resources.prefs ├── org.eclipse.jdt.ui.prefs └── org.eclipse.jdt.core.prefs ├── lib └── org.eclipse.jdt.annotation-2.2.600.jar ├── README.md ├── .project ├── .classpath ├── test └── jason │ ├── TestJdk16.java │ ├── TestJsonParser.java │ ├── TestJson5.java │ ├── TestStringParser.java │ ├── JsonToken.java │ ├── TestNumberParser.java │ ├── TestWriter.java │ ├── Test.java │ └── Wast.java ├── LICENSE ├── jason.iml └── src └── jason ├── Json.java └── JsonWriter.java /.idea/.name: -------------------------------------------------------------------------------- 1 | jason -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /bin/ 2 | /out/ 3 | /classes/ 4 | /*.jar 5 | ~$* 6 | -------------------------------------------------------------------------------- /.settings/org.eclipse.core.runtime.prefs: -------------------------------------------------------------------------------- 1 | eclipse.preferences.version=1 2 | line.separator=\n 3 | -------------------------------------------------------------------------------- /.idea/.gitignore: -------------------------------------------------------------------------------- 1 | # Default ignored files 2 | /shelf/ 3 | /uiDesigner.xml 4 | /workspace.xml 5 | -------------------------------------------------------------------------------- /.settings/org.eclipse.core.resources.prefs: -------------------------------------------------------------------------------- 1 | eclipse.preferences.version=1 2 | encoding/=UTF-8 3 | -------------------------------------------------------------------------------- /lib/org.eclipse.jdt.annotation-2.2.600.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dwing4g/jason/HEAD/lib/org.eclipse.jdt.annotation-2.2.600.jar -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # jason 2 | An ultra fast and lightweight JSON parser and binder 3 | 4 | ## benchmark(Chinese): 5 | https://zhuanlan.zhihu.com/p/108486101 6 | -------------------------------------------------------------------------------- /.idea/codeStyles/codeStyleConfig.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 5 | -------------------------------------------------------------------------------- /.idea/vcs.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /.idea/encodings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /.idea/modules.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /.project: -------------------------------------------------------------------------------- 1 | 2 | 3 | jason 4 | 5 | 6 | 7 | 8 | 9 | org.eclipse.jdt.core.javabuilder 10 | 11 | 12 | 13 | 14 | 15 | org.eclipse.jdt.core.javanature 16 | 17 | 18 | -------------------------------------------------------------------------------- /.classpath: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /test/jason/TestJdk16.java: -------------------------------------------------------------------------------- 1 | package jason; 2 | 3 | public class TestJdk16 { 4 | record Record(int v, String s) { 5 | } 6 | 7 | public static void test1() throws ReflectiveOperationException { 8 | Record r = new Record(123, "abc"); 9 | String json = JsonWriter.local().clear().write(r).toString(); 10 | // System.out.println(json); // {"v":123,"s":"abc"} 11 | Record r2 = JsonReader.local().buf(json).parse(Record.class); 12 | Test.assertEquals(r, r2); 13 | } 14 | 15 | public static void main(String[] args) throws ReflectiveOperationException { 16 | test1(); 17 | System.out.println(TestJdk16.class.getSimpleName() + ": 1 test OK!"); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /test/jason/TestJsonParser.java: -------------------------------------------------------------------------------- 1 | package jason; 2 | 3 | public final class TestJsonParser { 4 | public static class C { 5 | int a; 6 | String b; 7 | C c; 8 | } 9 | 10 | public static void main(String[] args) throws ReflectiveOperationException { 11 | byte[] bytes = "{\"b\":\"xyz\", \"a\":123,\"c\":{\"a\":456,\"b\":\"abc\"}}".getBytes(); 12 | long v = 0; 13 | long t = System.nanoTime(); 14 | JsonReader jr = new JsonReader(); 15 | for (int i = 0; i < 10_000_000; ++i) { 16 | C c = jr.buf(bytes).parse(C.class); 17 | if (c == null) 18 | throw new RuntimeException(); 19 | v += c.a + c.c.a; 20 | } 21 | System.out.println(TestJsonParser.class.getSimpleName() + ": " + v + ", " + 22 | (System.nanoTime() - t) / 1_000_000 + " ms"); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020 dwing4g 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /.idea/codeStyles/Project.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 24 | -------------------------------------------------------------------------------- /jason.iml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | -------------------------------------------------------------------------------- /test/jason/TestJson5.java: -------------------------------------------------------------------------------- 1 | package jason; 2 | 3 | import java.util.LinkedHashMap; 4 | import java.util.Map; 5 | 6 | public final class TestJson5 { 7 | private static int checkCount = 0; 8 | 9 | private static void checkObj(String json5, String resJson) throws ReflectiveOperationException { 10 | final Map map = JsonReader.local().buf(json5).parseMap(new LinkedHashMap<>()); 11 | final String res = JsonWriter.local().clear().setFlags(0x10_0000).setNoQuoteKey(true).write(map).toString(); 12 | if (!res.equals(resJson)) 13 | throw new AssertionError("unmatched: " + json5 + " <---> " + res); 14 | checkCount++; 15 | } 16 | 17 | public static void main(String[] args) throws ReflectiveOperationException { 18 | checkObj("{'a':1}", "{a:1}"); 19 | checkObj("{a:1}", "{a:1}"); 20 | checkObj("{$_:1,_$:2,a\\u200C:3}", "{$_:1,_$:2,a\u200C:3}"); 21 | checkObj("{中文key\\0:9}", "{中文key\\u0000:9}"); 22 | checkObj("{\\u0061\\u0062:1,\\u0024\\u005F:2,\\u005F\\u0024:3}", "{ab:1,$_:2,_$:3}"); 23 | checkObj("{abc:1,def:2,,,}", "{abc:1,def:2}"); 24 | checkObj("{a:{b:2,},}", "{a:{b:2}}"); 25 | checkObj("{a:+5,b:+1.23e,c:+1.23e+1,d:-.5,e:-5.,f:-0.,g:-.,h:.}", "{a:5,b:1.23,c:12.3,d:-0.5,e:-5.0,f:-0.0,g:-0.0,h:0.0}"); 26 | checkObj("{a:Infinity,b:-infinity,c:Inf,d:NaN,e:nan}", "{a:Infinity,b:-Infinity,c:Infinity,d:NaN,e:NaN}"); 27 | System.out.println(TestJson5.class.getSimpleName() + ": " + checkCount + " TESTS OK!"); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /test/jason/TestStringParser.java: -------------------------------------------------------------------------------- 1 | package jason; 2 | 3 | import java.nio.charset.StandardCharsets; 4 | 5 | public final class TestStringParser { 6 | public static void main(String[] args) { 7 | String[] strs = {"\"\"", "\"abc\"", "\"abcdefghijklmn\"", "\"\\\"\\\\\\/\\b\\f\\n\\r\\t\"", 8 | "\"\\u0123\\u4567\\u89ab\\ucdef\"", "\"opqrst\\r\\nuvwxyz\"", "\"《汉字》\"", 9 | "\"\\u0030\\'\\uABCD\\u00EF\""}; 10 | //noinspection UnnecessaryUnicodeEscape 11 | String[] chks = {"", "abc", "abcdefghijklmn", "\"\\/\b\f\n\r\t", "\u0123\u4567\u89ab\ucdef", 12 | "opqrst\r\nuvwxyz", "《汉字》", "\u0030'\uABCD\u00EF"}; 13 | byte[][] tests = new byte[8][]; 14 | for (int i = 0; i < 8; i++) 15 | tests[i] = strs[i].getBytes(StandardCharsets.UTF_8); 16 | 17 | JsonReader jr = new JsonReader(); 18 | for (int j = 0; j < 8; j++) { 19 | String s = jr.buf(tests[j]).parseString(); 20 | if (!s.equals(chks[j])) { 21 | System.err.println("ERROR! j=" + j + ':'); 22 | for (int i = 0; i < s.length(); i++) 23 | System.out.format(" %4X", (int)s.charAt(i)); 24 | System.out.println(); 25 | for (int i = 0; i < chks[j].length(); i++) 26 | System.out.format(" %4X", (int)chks[j].charAt(i)); 27 | System.out.println(); 28 | return; 29 | } 30 | } 31 | long r = 0; 32 | for (int i = 0; i < 2_000_000; i++) 33 | for (int j = 0; j < 8; j++) { 34 | String s = jr.buf(tests[j]).parseString(); 35 | r += s.length(); 36 | } 37 | System.out.println(TestStringParser.class.getSimpleName() + ": " + r); // 102000000 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /.idea/inspectionProfiles/Project_Default.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 30 | -------------------------------------------------------------------------------- /test/jason/JsonToken.java: -------------------------------------------------------------------------------- 1 | package jason; 2 | 3 | public final class JsonToken { 4 | public static final int TYPE_SHIFT = 30; 5 | public static final int TYPE_PRIMITIVE = 0; // number, boolean(true/false) or null 6 | public static final int TYPE_STRING = 1 << TYPE_SHIFT; 7 | public static final int TYPE_ARRAY = 2 << TYPE_SHIFT; 8 | public static final int TYPE_OBJECT = 3 << TYPE_SHIFT; 9 | public static final int TYPE_MASK = 3 << TYPE_SHIFT; 10 | public static final int SIZE_MASK = ~TYPE_MASK; 11 | 12 | /** 13 | * Reference: original C implement: jsmn 14 | * 15 | * @param in json string (readonly byte array) 16 | * @param inPos start offset from json array 17 | * @param inLen length from json array offset 18 | * @param out output: {type|size, start, end, parent}* 19 | * @return updated outPos(>=0) or -1-outPos(<0) for error 20 | */ 21 | public static int parse(final byte[] in, int inPos, final int inLen, final int[] out) { 22 | int outPos = 0, parentPos = -1; 23 | for (final int inEnd = inPos + inLen; inPos < inEnd; inPos++) { 24 | final int c = in[inPos]; 25 | switch (c) { 26 | case '{': 27 | case '[': 28 | out[outPos] = c == '{' ? TYPE_OBJECT : TYPE_ARRAY; 29 | out[outPos + 1] = inPos; 30 | out[outPos + 2] = -1; 31 | out[outPos + 3] = parentPos; 32 | if (parentPos >= 0) 33 | out[parentPos]++; 34 | parentPos = outPos; 35 | outPos += 4; 36 | continue; 37 | case '}': 38 | case ']': 39 | final int type = c == '}' ? TYPE_OBJECT : TYPE_ARRAY; 40 | if (outPos <= 0) 41 | return -1; 42 | for (int pos = outPos - 4; ; pos = out[pos + 3]) { 43 | if (out[pos + 2] < 0) { 44 | if ((out[pos] & TYPE_MASK) != type) 45 | return -1 - outPos; 46 | out[pos + 2] = inPos + 1; 47 | parentPos = out[pos + 3]; 48 | break; 49 | } 50 | if (out[pos + 3] < 0) { 51 | if ((out[pos] & TYPE_MASK) != type || parentPos < 0) 52 | return -1 - outPos; 53 | break; 54 | } 55 | } 56 | continue; 57 | case '\'': 58 | case '"': 59 | out[outPos] = TYPE_STRING; 60 | out[outPos + 1] = ++inPos; 61 | for (; inPos < inEnd; inPos++) { 62 | final int d = in[inPos]; 63 | if (d == c) 64 | break; 65 | if (d == '\\' && inPos + 1 < inEnd) 66 | inPos++; 67 | } 68 | out[outPos + 2] = inPos; 69 | out[outPos + 3] = parentPos; 70 | outPos += 4; 71 | if (parentPos >= 0) 72 | out[parentPos]++; 73 | continue; 74 | case '\t': 75 | case '\r': 76 | case '\n': 77 | case ' ': 78 | continue; 79 | case ':': 80 | parentPos = outPos - 4; 81 | continue; 82 | case ',': 83 | if (parentPos >= 0 && out[parentPos] >= 0) // != ARRAY && != OBJECT 84 | parentPos = out[parentPos + 3]; 85 | continue; 86 | } 87 | out[outPos] = TYPE_PRIMITIVE; 88 | out[outPos + 1] = inPos; 89 | end: 90 | for (; inPos < inEnd; inPos++) { 91 | switch (in[inPos]) { 92 | case '\t': 93 | case '\r': 94 | case '\n': 95 | case ' ': 96 | case ':': 97 | case ',': 98 | case ']': 99 | case '}': 100 | break end; 101 | } 102 | } 103 | out[outPos + 2] = inPos--; 104 | out[outPos + 3] = parentPos; 105 | outPos += 4; 106 | if (parentPos >= 0) 107 | out[parentPos]++; 108 | } 109 | // for (int pos = outPos - 4; pos >= 0; pos -= 4) 110 | // if (out[pos + 2] < 0) 111 | // return ERROR_PART; 112 | return outPos; 113 | } 114 | 115 | private JsonToken() { 116 | } 117 | 118 | public static void main(String[] args) { 119 | String json = "{a:12,\"b\":{\"c\":[3,4],\"d\":\"测试\"},'ef':{}}"; 120 | final byte[] jsonBytes = json.getBytes(); 121 | final int[] tokens = new int[1024]; 122 | final int n = parse(jsonBytes, 0, jsonBytes.length, tokens); 123 | System.out.println(n + ": " + jsonBytes.length + "/" + json.length()); 124 | for (int i = 0; i < n; i += 4) { 125 | System.out.printf("%2d: %d[%d]: %2d-%2d %2d: %s%n", 126 | i, tokens[i] >>> TYPE_SHIFT, tokens[i] & SIZE_MASK, tokens[i + 1], tokens[i + 2], tokens[i + 3], 127 | new String(jsonBytes, tokens[i + 1], tokens[i + 2] - tokens[i + 1])); 128 | } 129 | System.out.println("==="); 130 | } 131 | } 132 | -------------------------------------------------------------------------------- /.idea/misc.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 29 | 52 | 53 | 54 | 55 | 56 | -------------------------------------------------------------------------------- /test/jason/TestNumberParser.java: -------------------------------------------------------------------------------- 1 | package jason; 2 | 3 | import java.nio.charset.StandardCharsets; 4 | import java.util.concurrent.ThreadLocalRandom; 5 | 6 | public final class TestNumberParser { 7 | public static void testReader() { 8 | byte[][] tests = {"3.1234567 ".getBytes(), "31234567 ".getBytes(), "0.31234567 ".getBytes(), 9 | "312.34567 ".getBytes(), "3.1234567e7 ".getBytes(), "3.1234567E-7 ".getBytes(), "0 ".getBytes(), 10 | "1.0 ".getBytes()}; 11 | JsonReader jr = new JsonReader(); 12 | double r = 0; 13 | for (int i = 0; i < 10_000_000; i++) { 14 | for (int j = 0; j < 8; j++) 15 | r += jr.buf(tests[j]).parseDouble(); 16 | } 17 | System.out.format("%s.testReader: %15.6f\n", TestNumberParser.class.getSimpleName(), r); // 624694507922444.400000 18 | } 19 | 20 | public static void testWriter() { 21 | double[] tests = {3.1234567, 31234567, 0.31234567, 312.34567, 3.1234567e7, 3.1234567E-7, 0, 1.0}; 22 | JsonWriter jw = new JsonWriter(); 23 | int n = 0; 24 | for (int i = 0; i < 10_000_000; i++) { 25 | for (int j = 0; j < 8; j++) { 26 | // n += Double.toString(tests[j]).length(); 27 | jw.clear().write(tests[j]); 28 | n += jw.size(); 29 | // System.out.println(new String(jw.buf, 0, jw.pos)); 30 | } 31 | } 32 | System.out.format("%s.testWriter: %d\n", TestNumberParser.class.getSimpleName(), n); // 660000000 33 | } 34 | 35 | public static void testRandomDoubleParser() { 36 | int e1 = 0, e2 = 0; 37 | final JsonReader jr = JsonReader.local(); 38 | final ThreadLocalRandom r = ThreadLocalRandom.current(); 39 | final long t = System.nanoTime(); 40 | for (int i = 0; i < 10_000_000; i++) { 41 | long v; 42 | if (i < 400) { 43 | if (i < 100) 44 | v = i; 45 | else if (i < 200) 46 | v = 0x10_0000_0000_0000L - (i - 99); 47 | else if (i < 300) 48 | v = 0x7fe0_0000_0000_0000L + (i - 200); 49 | else 50 | v = 0x7ff0_0000_0000_0000L - (i - 299); 51 | } else { 52 | do 53 | v = r.nextLong(); 54 | while ((v & 0x7ff0_0000_0000_0000L) == 0x7ff0_0000_0000_0000L); 55 | } 56 | final double f = Double.longBitsToDouble(v); 57 | final double f2 = jr.buf((f + " ").getBytes(StandardCharsets.ISO_8859_1)).parseDouble(); 58 | if (f != f2) { 59 | double f3, f4, f5, f6; 60 | if (f == (f3 = Math.nextDown(f2)) || f == (f5 = Math.nextUp(f2))) 61 | e1++; 62 | else if (f == (f4 = Math.nextDown(f3)) || f == (f6 = Math.nextUp(f5))) 63 | e2++; 64 | else { 65 | throw new AssertionError("testRandomDoubleParser[" + i + "]:" 66 | + "\n " + f 67 | + "\n != " + f2 68 | + "\n-2: " + f4 69 | + "\n-1: " + f3 70 | + "\n+1: " + f5 71 | + "\n+2: " + f6); 72 | } 73 | } 74 | } 75 | System.out.println("testRandomDoubleParser OK! " + (System.nanoTime() - t) / 1_000_000 76 | + " ms, errors=" + e1 + "+" + e2); 77 | } 78 | 79 | public static void testRandomFloatParser() { 80 | final JsonReader jr = JsonReader.local(); 81 | final ThreadLocalRandom r = ThreadLocalRandom.current(); 82 | final long t = System.nanoTime(); 83 | for (int i = 0; i < 10_000_000; i++) { 84 | int v; 85 | if (i < 400) { 86 | if (i < 100) 87 | v = i; 88 | else if (i < 200) 89 | v = 0x80_0000 - (i - 99); 90 | else if (i < 300) 91 | v = 0x7f00_0000 + (i - 200); 92 | else 93 | v = 0x7f80_0000 - (i - 299); 94 | } else { 95 | do 96 | v = r.nextInt(); 97 | while ((v & 0x7f80_0000) == 0x7f80_0000); 98 | } 99 | final float f = Float.intBitsToFloat(v); 100 | final float f2 = (float)jr.buf((f + " ").getBytes(StandardCharsets.ISO_8859_1)).parseDouble(); 101 | if (f != f2) 102 | throw new AssertionError("testRandomFloatParser[" + i + "]: " + f + " != " + f2); 103 | } 104 | System.out.println("testRandomFloatParser OK! " + (System.nanoTime() - t) / 1_000_000 + " ms"); 105 | } 106 | 107 | public static void main(String[] args) { 108 | for (int i = 0; i < 5; i++) 109 | testRandomDoubleParser(); 110 | for (int i = 0; i < 5; i++) 111 | testRandomFloatParser(); 112 | 113 | long t = System.nanoTime(); 114 | testReader(); 115 | System.out.println(TestNumberParser.class.getSimpleName() + ".testReader: " + 116 | (System.nanoTime() - t) / 1_000_000 + " ms"); 117 | t = System.nanoTime(); 118 | testWriter(); 119 | System.out.println(TestNumberParser.class.getSimpleName() + ".testWriter: " + 120 | (System.nanoTime() - t) / 1_000_000 + " ms"); 121 | } 122 | } 123 | -------------------------------------------------------------------------------- /.settings/org.eclipse.jdt.ui.prefs: -------------------------------------------------------------------------------- 1 | cleanup.add_default_serial_version_id=true 2 | cleanup.add_generated_serial_version_id=false 3 | cleanup.add_missing_annotations=true 4 | cleanup.add_missing_deprecated_annotations=true 5 | cleanup.add_missing_methods=true 6 | cleanup.add_missing_nls_tags=false 7 | cleanup.add_missing_override_annotations=true 8 | cleanup.add_missing_override_annotations_interface_methods=true 9 | cleanup.add_serial_version_id=false 10 | cleanup.always_use_blocks=false 11 | cleanup.always_use_parentheses_in_expressions=false 12 | cleanup.always_use_this_for_non_static_field_access=false 13 | cleanup.always_use_this_for_non_static_method_access=false 14 | cleanup.convert_functional_interfaces=true 15 | cleanup.convert_to_enhanced_for_loop=true 16 | cleanup.correct_indentation=false 17 | cleanup.format_source_code=true 18 | cleanup.format_source_code_changes_only=false 19 | cleanup.insert_inferred_type_arguments=false 20 | cleanup.make_local_variable_final=false 21 | cleanup.make_parameters_final=false 22 | cleanup.make_private_fields_final=true 23 | cleanup.make_type_abstract_if_missing_method=false 24 | cleanup.make_variable_declarations_final=true 25 | cleanup.never_use_blocks=true 26 | cleanup.never_use_parentheses_in_expressions=true 27 | cleanup.number_suffix=true 28 | cleanup.organize_imports=true 29 | cleanup.push_down_negation=true 30 | cleanup.qualify_static_field_accesses_with_declaring_class=false 31 | cleanup.qualify_static_member_accesses_through_instances_with_declaring_class=true 32 | cleanup.qualify_static_member_accesses_through_subtypes_with_declaring_class=true 33 | cleanup.qualify_static_member_accesses_with_declaring_class=true 34 | cleanup.qualify_static_method_accesses_with_declaring_class=false 35 | cleanup.remove_private_constructors=true 36 | cleanup.remove_redundant_modifiers=true 37 | cleanup.remove_redundant_semicolons=true 38 | cleanup.remove_redundant_type_arguments=true 39 | cleanup.remove_trailing_whitespaces=true 40 | cleanup.remove_trailing_whitespaces_all=true 41 | cleanup.remove_trailing_whitespaces_ignore_empty=false 42 | cleanup.remove_unnecessary_array_creation=true 43 | cleanup.remove_unnecessary_casts=true 44 | cleanup.remove_unnecessary_nls_tags=true 45 | cleanup.remove_unused_imports=true 46 | cleanup.remove_unused_local_variables=true 47 | cleanup.remove_unused_private_fields=true 48 | cleanup.remove_unused_private_members=false 49 | cleanup.remove_unused_private_methods=true 50 | cleanup.remove_unused_private_types=true 51 | cleanup.simplify_lambda_expression_and_method_ref=true 52 | cleanup.sort_members=false 53 | cleanup.sort_members_all=false 54 | cleanup.use_anonymous_class_creation=false 55 | cleanup.use_autoboxing=true 56 | cleanup.use_blocks=false 57 | cleanup.use_blocks_only_for_return_and_throw=false 58 | cleanup.use_directly_map_method=true 59 | cleanup.use_lambda=true 60 | cleanup.use_parentheses_in_expressions=false 61 | cleanup.use_this_for_non_static_field_access=true 62 | cleanup.use_this_for_non_static_field_access_only_if_necessary=true 63 | cleanup.use_this_for_non_static_method_access=true 64 | cleanup.use_this_for_non_static_method_access_only_if_necessary=true 65 | cleanup.use_type_arguments=false 66 | cleanup.use_unboxing=true 67 | cleanup_profile=_my 68 | cleanup_settings_version=2 69 | eclipse.preferences.version=1 70 | editor_save_participant_org.eclipse.jdt.ui.postsavelistener.cleanup=true 71 | formatter_profile=_Eclipse fixed 72 | formatter_settings_version=19 73 | org.eclipse.jdt.ui.exception.name=e 74 | org.eclipse.jdt.ui.gettersetter.use.is=true 75 | org.eclipse.jdt.ui.keywordthis=false 76 | org.eclipse.jdt.ui.overrideannotation=true 77 | org.eclipse.jdt.ui.text.custom_code_templates= 78 | sp_cleanup.add_default_serial_version_id=true 79 | sp_cleanup.add_generated_serial_version_id=false 80 | sp_cleanup.add_missing_annotations=false 81 | sp_cleanup.add_missing_deprecated_annotations=true 82 | sp_cleanup.add_missing_methods=false 83 | sp_cleanup.add_missing_nls_tags=false 84 | sp_cleanup.add_missing_override_annotations=true 85 | sp_cleanup.add_missing_override_annotations_interface_methods=true 86 | sp_cleanup.add_serial_version_id=false 87 | sp_cleanup.always_use_blocks=true 88 | sp_cleanup.always_use_parentheses_in_expressions=false 89 | sp_cleanup.always_use_this_for_non_static_field_access=false 90 | sp_cleanup.always_use_this_for_non_static_method_access=false 91 | sp_cleanup.convert_functional_interfaces=false 92 | sp_cleanup.convert_to_enhanced_for_loop=false 93 | sp_cleanup.correct_indentation=false 94 | sp_cleanup.format_source_code=false 95 | sp_cleanup.format_source_code_changes_only=false 96 | sp_cleanup.insert_inferred_type_arguments=false 97 | sp_cleanup.make_local_variable_final=false 98 | sp_cleanup.make_parameters_final=false 99 | sp_cleanup.make_private_fields_final=true 100 | sp_cleanup.make_type_abstract_if_missing_method=false 101 | sp_cleanup.make_variable_declarations_final=false 102 | sp_cleanup.never_use_blocks=false 103 | sp_cleanup.never_use_parentheses_in_expressions=true 104 | sp_cleanup.on_save_use_additional_actions=true 105 | sp_cleanup.organize_imports=false 106 | sp_cleanup.push_down_negation=false 107 | sp_cleanup.qualify_static_field_accesses_with_declaring_class=false 108 | sp_cleanup.qualify_static_member_accesses_through_instances_with_declaring_class=true 109 | sp_cleanup.qualify_static_member_accesses_through_subtypes_with_declaring_class=true 110 | sp_cleanup.qualify_static_member_accesses_with_declaring_class=false 111 | sp_cleanup.qualify_static_method_accesses_with_declaring_class=false 112 | sp_cleanup.remove_private_constructors=true 113 | sp_cleanup.remove_redundant_modifiers=false 114 | sp_cleanup.remove_redundant_semicolons=false 115 | sp_cleanup.remove_redundant_type_arguments=false 116 | sp_cleanup.remove_trailing_whitespaces=true 117 | sp_cleanup.remove_trailing_whitespaces_all=true 118 | sp_cleanup.remove_trailing_whitespaces_ignore_empty=false 119 | sp_cleanup.remove_unnecessary_array_creation=false 120 | sp_cleanup.remove_unnecessary_casts=false 121 | sp_cleanup.remove_unnecessary_nls_tags=false 122 | sp_cleanup.remove_unused_imports=true 123 | sp_cleanup.remove_unused_local_variables=false 124 | sp_cleanup.remove_unused_private_fields=true 125 | sp_cleanup.remove_unused_private_members=false 126 | sp_cleanup.remove_unused_private_methods=true 127 | sp_cleanup.remove_unused_private_types=true 128 | sp_cleanup.sort_members=false 129 | sp_cleanup.sort_members_all=false 130 | sp_cleanup.use_anonymous_class_creation=false 131 | sp_cleanup.use_autoboxing=false 132 | sp_cleanup.use_blocks=false 133 | sp_cleanup.use_blocks_only_for_return_and_throw=false 134 | sp_cleanup.use_lambda=false 135 | sp_cleanup.use_parentheses_in_expressions=false 136 | sp_cleanup.use_this_for_non_static_field_access=false 137 | sp_cleanup.use_this_for_non_static_field_access_only_if_necessary=true 138 | sp_cleanup.use_this_for_non_static_method_access=false 139 | sp_cleanup.use_this_for_non_static_method_access_only_if_necessary=true 140 | sp_cleanup.use_type_arguments=false 141 | sp_cleanup.use_unboxing=false 142 | -------------------------------------------------------------------------------- /test/jason/TestWriter.java: -------------------------------------------------------------------------------- 1 | package jason; 2 | 3 | import java.util.concurrent.ThreadLocalRandom; 4 | 5 | public class TestWriter { 6 | static final JsonWriter jw = new JsonWriter(); 7 | static final JsonReader jr = new JsonReader(); 8 | static int count; 9 | 10 | static void testInt(int d) { 11 | jw.free().ensure(11); 12 | jw.write(d); 13 | String ss = jw.toString(); 14 | jr.buf(jw.toBytes()); 15 | long d2 = jr.parseInt(); 16 | if (d != d2) 17 | throw new IllegalStateException("check err: " + d + " => '" + ss + "' => " + d2); 18 | if (jw.size() > 11) 19 | throw new IllegalStateException("too long size: " + d + " => '" + ss + "' => " + d2); 20 | count++; 21 | } 22 | 23 | static void testInt(int d, String s) { 24 | jw.free().ensure(11); 25 | jw.write(d); 26 | String ss = jw.toString(); 27 | jr.buf(jw.toBytes()); 28 | long d2 = jr.parseInt(); 29 | if (d != d2) 30 | throw new IllegalStateException("check err: " + d + " => '" + ss + "' => " + d2); 31 | if (jw.size() > 11) 32 | throw new IllegalStateException("too long size: " + d + " => '" + ss + "' => " + d2); 33 | if (!ss.equals(s)) 34 | throw new IllegalStateException("check err: " + d + " => '" + ss + "' != '" + s + "'"); 35 | count++; 36 | } 37 | 38 | static void testLong(long d) { 39 | if (d >= Integer.MIN_VALUE && d <= Integer.MAX_VALUE) 40 | testInt((int)d); 41 | jw.free().ensure(20); 42 | jw.write(d); 43 | String ss = jw.toString(); 44 | jr.buf(jw.toBytes()); 45 | long d2 = jr.parseLong(); 46 | if (d != d2) 47 | throw new IllegalStateException("check err: " + d + " => '" + ss + "' => " + d2); 48 | if (jw.size() > 20) 49 | throw new IllegalStateException("too long size: " + d + " => '" + ss + "' => " + d2); 50 | count++; 51 | } 52 | 53 | static void testLong(long d, String s) { 54 | if (d >= Integer.MIN_VALUE && d <= Integer.MAX_VALUE) 55 | testInt((int)d); 56 | jw.free().ensure(20); 57 | jw.write(d); 58 | String ss = jw.toString(); 59 | jr.buf(jw.toBytes()); 60 | long d2 = jr.parseLong(); 61 | if (d != d2) 62 | throw new IllegalStateException("check err: " + d + " => '" + ss + "' => " + d2); 63 | if (jw.size() > 20) 64 | throw new IllegalStateException("too long size: " + d + " => '" + ss + "' => " + d2); 65 | if (!ss.equals(s)) 66 | throw new IllegalStateException("check err: " + d + " => '" + ss + "' != '" + s + "'"); 67 | count++; 68 | } 69 | 70 | static void testDouble(double d) { 71 | jw.free().ensure(25); 72 | jw.write(d); 73 | String ss = jw.toString(); 74 | jr.buf(jw.toBytes()); 75 | double d2 = jr.parseDouble(); 76 | if (d != d2) 77 | throw new IllegalStateException("check err: " + d + " => '" + ss + "' => " + d2); 78 | if (jw.size() > 25) 79 | throw new IllegalStateException("too long size: " + d + " => '" + ss + "' => " + d2); 80 | count++; 81 | } 82 | 83 | static void testDouble(double d, String s) { 84 | jw.free().ensure(25); 85 | jw.write(d); 86 | String ss = jw.toString(); 87 | jr.buf(jw.toBytes()); 88 | double d2 = jr.parseDouble(); 89 | if (d != d2) 90 | throw new IllegalStateException("check err: " + d + " => '" + ss + "' => " + d2); 91 | if (jw.size() > 25) 92 | throw new IllegalStateException("too long size: " + d + " => '" + ss + "' => " + d2); 93 | if (!ss.equals(s)) 94 | throw new IllegalStateException("check err: " + d + " => '" + ss + "' != '" + s + "'"); 95 | count++; 96 | } 97 | 98 | static void testDouble(int maxDecimalPlaces, double d, String s) { 99 | testDouble(d); 100 | jw.free().ensure(25); 101 | jw.write(d, maxDecimalPlaces); 102 | String ss = jw.toString(); 103 | if (!ss.equals(s)) 104 | throw new IllegalStateException("check err: " + d + " => '" + ss + "' != '" + s + "'"); 105 | count++; 106 | } 107 | 108 | public static void testDoubleRange() { 109 | final JsonWriter jw = JsonWriter.local(); 110 | double d = 0.01; 111 | for (int j = 0; j < 5; j++, d *= 10) { 112 | long dd = Double.doubleToRawLongBits(d); 113 | for (int i = 0; i < 1_000_000; i++) { 114 | final double f = Double.longBitsToDouble(dd + i); 115 | jw.clear().write(f); 116 | final String s = jw.toString(); 117 | final double f2 = Double.parseDouble(s); 118 | if (f != f2) 119 | throw new AssertionError("testDoubleRange[" + j + "," + i + "]: " + f + " != " + f2 + ", " + s); 120 | } 121 | } 122 | for (long e = 0; e < 2048; e++) { 123 | final double f = Double.doubleToRawLongBits(e << 52); 124 | jw.clear().write(f); 125 | final String s = jw.toString(); 126 | final double f2 = Double.parseDouble(s); 127 | if (f != f2) 128 | throw new AssertionError("testDoubleRange[e" + e + "]: " + f + " != " + f2 + ", " + s); 129 | } 130 | for (long e = 0; e < 2048; e++) { 131 | final double f = Double.doubleToRawLongBits((e << 52) + 1); 132 | jw.clear().write(f); 133 | final String s = jw.toString(); 134 | final double f2 = Double.parseDouble(s); 135 | //noinspection ConstantValue 136 | if (f != f2 && !(Double.isNaN(f) && Double.isNaN(f2))) 137 | throw new AssertionError("testDoubleRange[e" + e + ":1]: " + f + " != " + f2 + ", " + s); 138 | } 139 | for (int i = 0; i < 1_000_000; i++) { 140 | final double f = Double.doubleToRawLongBits(i); 141 | jw.clear().write(f); 142 | final String s = jw.toString(); 143 | final double f2 = Double.parseDouble(s); 144 | if (f != f2) 145 | throw new AssertionError("testDoubleRange[" + i + "]: " + f + " != " + f2 + ", " + s); 146 | } 147 | System.out.println("testDoubleRange OK!"); 148 | } 149 | 150 | public static void testDoubleRandom() { 151 | final JsonWriter jw = JsonWriter.local(); 152 | final ThreadLocalRandom r = ThreadLocalRandom.current(); 153 | for (int i = 0; i < 10_000_000; i++) { 154 | long v = r.nextLong(); 155 | if ((v & 0x7ff0_0000_0000_0000L) == 0x7ff0_0000_0000_0000L) { 156 | v &= 0xfff8_0000_0000_0000L; // Infinity/-Infinity/NaN 157 | if (v == 0xfff8_0000_0000_0000L) 158 | v = 0x7ff8_0000_0000_0000L; 159 | } 160 | final double f = Double.longBitsToDouble(v); 161 | jw.clear().write(f); 162 | final String s = jw.toString(); 163 | final double f2 = Double.parseDouble(s); 164 | if (f != f2 && !(Double.isNaN(f) && Double.isNaN(f2))) 165 | throw new AssertionError("testDoubleRandom[" + i + "]: " + f + " != " + f2 + ", " + s); 166 | } 167 | System.out.println("testDoubleRandom OK!"); 168 | } 169 | 170 | public static void main(String[] args) { 171 | testLong(0); 172 | testLong(1); 173 | testLong(-1); 174 | testLong(9); 175 | testLong(-9); 176 | testLong(10); 177 | testLong(-10); 178 | testLong(11); 179 | testLong(-11); 180 | testLong(Integer.MAX_VALUE); 181 | testLong(-Integer.MAX_VALUE); 182 | testLong(Integer.MIN_VALUE); 183 | testLong(0x8000_0000L); 184 | testLong(Long.MAX_VALUE); 185 | testLong(-Long.MAX_VALUE); 186 | testLong(Long.MIN_VALUE); 187 | for (int i = 0; i < 32; i++) { 188 | testLong(0x5a5a_5a5a_5a5a_5a5aL >> i); 189 | testLong(0xa5a5_a5a5_a5a5_a5a5L >> i); 190 | } 191 | 192 | testDouble(0.0, "0.0"); 193 | testDouble(-0.0, "-0.0"); 194 | testDouble(1.0, "1.0"); 195 | testDouble(-1.0, "-1.0"); 196 | testDouble(1.2345, "1.2345"); 197 | testDouble(1.2345678, "1.2345678"); 198 | testDouble(0.123456789012, "0.123456789012"); 199 | testDouble(1234567.8, "1234567.8"); 200 | testDouble(-79.39773355813419, "-79.39773355813419"); 201 | testDouble(-36.973846435546875, "-36.973846435546875"); 202 | testDouble(0.000001, "0.000001"); 203 | testDouble(0.0000001, "1e-7"); 204 | testDouble(1e30, "1e30"); 205 | testDouble(1.234567890123456e30, "1.234567890123456e30"); 206 | testDouble(5e-324, "5e-324"); // Min subnormal positive double 207 | testDouble(2.225073858507201e-308, "2.225073858507201e-308"); // Max subnormal positive double 208 | testDouble(2.2250738585072014e-308, "2.2250738585072014e-308"); // Min normal positive double 209 | testDouble(1.7976931348623157e308, "1.7976931348623157e308"); // Max double 210 | 211 | testDouble(3, 0.0, "0.0"); 212 | testDouble(1, 0.0, "0.0"); 213 | testDouble(3, -0.0, "-0.0"); 214 | testDouble(3, 1.0, "1.0"); 215 | testDouble(3, -1.0, "-1.0"); 216 | testDouble(3, 1.2345, "1.234"); 217 | testDouble(2, 1.2345, "1.23"); 218 | testDouble(1, 1.2345, "1.2"); 219 | testDouble(3, 1.2345678, "1.234"); 220 | testDouble(3, 1.0001, "1.0"); 221 | testDouble(2, 1.0001, "1.0"); 222 | testDouble(1, 1.0001, "1.0"); 223 | testDouble(3, 0.123456789012, "0.123"); 224 | testDouble(2, 0.123456789012, "0.12"); 225 | testDouble(1, 0.123456789012, "0.1"); 226 | testDouble(4, 0.0001, "0.0001"); 227 | testDouble(3, 0.0001, "0.0"); 228 | testDouble(2, 0.0001, "0.0"); 229 | testDouble(1, 0.0001, "0.0"); 230 | testDouble(3, 1234567.8, "1234567.8"); 231 | testDouble(3, 1e30, "1e30"); 232 | testDouble(3, 5e-324, "0.0"); // Min subnormal positive double 233 | testDouble(3, 2.225073858507201e-308, "0.0"); // Max subnormal positive double 234 | testDouble(3, 2.2250738585072014e-308, "0.0"); // Min normal positive double 235 | testDouble(3, 1.7976931348623157e308, "1.7976931348623157e308"); // Max double 236 | testDouble(5, -0.14000000000000001, "-0.14"); 237 | testDouble(4, -0.14000000000000001, "-0.14"); 238 | testDouble(3, -0.14000000000000001, "-0.14"); 239 | testDouble(3, -0.10000000000000001, "-0.1"); 240 | testDouble(2, -0.10000000000000001, "-0.1"); 241 | testDouble(1, -0.10000000000000001, "-0.1"); 242 | System.out.println(TestWriter.class.getSimpleName() + ": " + count + " tests OK!"); 243 | 244 | testDoubleRange(); 245 | testDoubleRandom(); 246 | } 247 | } 248 | -------------------------------------------------------------------------------- /test/jason/Test.java: -------------------------------------------------------------------------------- 1 | package jason; 2 | 3 | import java.net.Inet4Address; 4 | import java.nio.charset.StandardCharsets; 5 | import java.util.*; 6 | 7 | public final class Test { 8 | static class A { 9 | int a; 10 | } 11 | 12 | static class B extends A { 13 | int b; 14 | } 15 | 16 | static class C { 17 | A a = new B(); 18 | C c; 19 | Map m = new HashMap<>(); 20 | } 21 | 22 | public static void assertNotNull(Object a) { 23 | if (a == null) 24 | throw new AssertionError("null"); 25 | } 26 | 27 | public static void assertEquals(int a, int b) { 28 | if (a != b) 29 | throw new AssertionError(a + " != " + b); 30 | } 31 | 32 | public static void assertEquals(Object a, Object b) { 33 | if (!Objects.equals(a, b)) 34 | throw new AssertionError(a + " != " + b); 35 | } 36 | 37 | public static void test1() throws ReflectiveOperationException { 38 | byte[] buf = "{a:[{x:1,y:2},{x:3,y:4},{x:5,y:6}]}".getBytes(); 39 | Object obj = JsonReader.local().buf(buf).parse(); 40 | assertNotNull(obj); 41 | assertEquals("{a=[{x=1, y=2}, {x=3, y=4}, {x=5, y=6}]}", obj.toString()); 42 | } 43 | 44 | public static void test2() throws ReflectiveOperationException { 45 | C c = JsonReader.local().buf("{a:{a:1,b:2}}").parse(C.class); 46 | assertNotNull(c); 47 | assertEquals(B.class, c.a.getClass()); 48 | assertEquals(1, c.a.a); 49 | assertEquals(2, ((B)c.a).b); 50 | 51 | c.a = new A(); 52 | c = JsonReader.local().buf("{a:{a:3,b:4}}").parse(c); 53 | assertNotNull(c); 54 | assertEquals(A.class, c.a.getClass()); 55 | assertEquals(3, c.a.a); 56 | 57 | c.a = null; 58 | c = JsonReader.local().buf("{a:{a:5,b:6}}").parse(c); 59 | assertNotNull(c); 60 | assertEquals(A.class, c.a.getClass()); 61 | assertEquals(5, c.a.a); 62 | 63 | Json.instance.getClassMeta(A.class).setParser((json, __, ___, ____, _____) -> json.parse(B.class)); 64 | c.a = null; 65 | c = JsonReader.local().buf("{a:{a:7,b:8}}").parse(c); 66 | assertNotNull(c); 67 | assertEquals(B.class, c.a.getClass()); 68 | assertEquals(7, c.a.a); 69 | assertEquals(8, ((B)c.a).b); 70 | 71 | B b = JsonReader.local().buf("{a:5 \n b:6}").parse(B.class); 72 | assertNotNull(b); 73 | assertEquals(B.class, b.getClass()); 74 | assertEquals(5, b.a); 75 | assertEquals(6, b.b); 76 | } 77 | 78 | public static void test3() { 79 | C c = new C(); 80 | c.a.a = 1; 81 | ((B)c.a).b = -1; 82 | String json = JsonWriter.local().clear().setNoQuoteKey(false).write(c).toString(); 83 | assertEquals("{\"a\":{\"a\":1,\"b\":-1},\"m\":{}}", json); 84 | } 85 | 86 | public static void test4() { 87 | C c = new C(); 88 | c.a.a = 1; 89 | ((B)c.a).b = -1; 90 | String json = JsonWriter.local().clear().setFlags(JsonWriter.FLAG_PRETTY_FORMAT).write(c).toString(); 91 | assertEquals("{\n" + 92 | "\t\"a\": {\n" + 93 | "\t\t\"a\": 1,\n" + 94 | "\t\t\"b\": -1\n" + 95 | "\t},\n" + 96 | "\t\"m\": {}\n" + 97 | "}", json); 98 | } 99 | 100 | public static void test5() { 101 | C c = new C(); 102 | c.a.a = 1; 103 | ((B)c.a).b = -1; 104 | String json = JsonWriter.local().clear().setFlags(JsonWriter.FLAG_NO_QUOTE_KEY).write(c).toString(); 105 | assertEquals("{a:{a:1,b:-1},m:{}}", json); 106 | } 107 | 108 | public static void test6() { 109 | C c = new C(); 110 | c.a.a = 1; 111 | ((B)c.a).b = -1; 112 | String json = JsonWriter.local().clear().setFlags(JsonWriter.FLAG_WRITE_NULL).write(c).toString(); 113 | assertEquals("{\"a\":{\"a\":1,\"b\":-1},\"c\":null,\"m\":{}}", json); 114 | } 115 | 116 | public static void test7() { 117 | System.out.println(System.getProperty("java.version")); 118 | System.out.println(Json.instance.getClassMeta(Inet4Address.class)); 119 | } 120 | 121 | static class D { 122 | final HashMap m = new HashMap<>(); 123 | } 124 | 125 | public static void test8() throws ReflectiveOperationException { 126 | D d = new D(); 127 | d.m.put(123, 456); 128 | String s = JsonWriter.local().clear().setFlags(0).write(d).toString(); 129 | assertEquals("{\"m\":{\"123\":456}}", s); 130 | d.m.clear(); 131 | JsonReader.local().buf("{\"m\":{123:456}}").parse(d); 132 | assertEquals(1, d.m.size()); 133 | assertEquals(String.valueOf(456), String.valueOf(d.m.get(123))); 134 | assertEquals(Integer.class, d.m.entrySet().iterator().next().getKey().getClass()); 135 | } 136 | 137 | static class E { 138 | int a; 139 | E e; 140 | } 141 | 142 | public static void test9() { 143 | E e = new E(); 144 | e.a = 123; 145 | e.e = e; 146 | String json = JsonWriter.local().clear().setDepthLimit(4).write(e).toString(); 147 | assertEquals("{\"a\":123,\"e\":{\"a\":123,\"e\":{\"a\":123,\"e\":{\"a\":123,\"e\":\"!OVERDEPTH!\"}}}}", json); 148 | } 149 | 150 | abstract static class F1 { 151 | int f; 152 | } 153 | 154 | static class F2 extends ArrayList { 155 | private F2() { 156 | } 157 | } 158 | 159 | static class G { 160 | final Set set1 = new HashSet<>(); 161 | HashSet set2; 162 | Set set3; 163 | Map e1; 164 | F1 f1; 165 | F2 f2; 166 | } 167 | 168 | public static void testA() throws ReflectiveOperationException { 169 | G g = JsonReader.local().buf("{\"set1\":[123,456],\"set2\":[789],\"set3\":[],\"e1\":{\"1\":[]},\"f2\":[222]}") 170 | .parse(G.class); 171 | assertNotNull(g); 172 | assertEquals(HashSet.class, g.set1.getClass()); 173 | assertNotNull(g.set2); 174 | assertEquals(HashSet.class, g.set2.getClass()); 175 | assertNotNull(g.set3); 176 | assertEquals(HashSet.class, g.set3.getClass()); 177 | assertEquals(222, ((Number)g.f2.get(0)).intValue()); 178 | } 179 | 180 | public static void testB() { 181 | int[] a = new int[]{1, 2, 3}; 182 | String[] b = new String[]{"a", "b", "c"}; 183 | List c = new ArrayList<>(); 184 | Collections.addAll(c, 1, 2, 3); 185 | List d = new ArrayList<>(); 186 | Collections.addAll(d, b); 187 | Map e = new TreeMap<>(); 188 | e.put(1, "a"); 189 | e.put(2, "b"); 190 | e.put(3, "c"); 191 | 192 | String json; 193 | json = JsonWriter.local().clear().write(a).toString(); 194 | assertEquals("[1,2,3]", json); 195 | json = JsonWriter.local().clear().write(b).toString(); 196 | assertEquals("[\"a\",\"b\",\"c\"]", json); 197 | json = JsonWriter.local().clear().write(c).toString(); 198 | assertEquals("[1,2,3]", json); 199 | json = JsonWriter.local().clear().write(d).toString(); 200 | assertEquals("[\"a\",\"b\",\"c\"]", json); 201 | json = JsonWriter.local().clear().write(e).toString(); 202 | assertEquals("{\"1\":\"a\",\"2\":\"b\",\"3\":\"c\"}", json); 203 | 204 | JsonWriter.local().setPrettyFormat(true).setWrapElement(true); 205 | 206 | json = JsonWriter.local().clear().write(a).toString(); 207 | assertEquals("[\n" + 208 | "\t1,\n" + 209 | "\t2,\n" + 210 | "\t3\n" + 211 | "]", json); 212 | json = JsonWriter.local().clear().write(b).toString(); 213 | assertEquals("[\n" + 214 | "\t\"a\",\n" + 215 | "\t\"b\",\n" + 216 | "\t\"c\"\n" + 217 | "]", json); 218 | json = JsonWriter.local().clear().write(c).toString(); 219 | assertEquals("[\n" + 220 | "\t1,\n" + 221 | "\t2,\n" + 222 | "\t3\n" + 223 | "]", json); 224 | json = JsonWriter.local().clear().write(d).toString(); 225 | assertEquals("[\n" + 226 | "\t\"a\",\n" + 227 | "\t\"b\",\n" + 228 | "\t\"c\"\n" + 229 | "]", json); 230 | json = JsonWriter.local().clear().write(e).toString(); 231 | assertEquals("{\n" + 232 | "\t\"1\": \"a\",\n" + 233 | "\t\"2\": \"b\",\n" + 234 | "\t\"3\": \"c\"\n" + 235 | "}", json); 236 | } 237 | 238 | public static void testC() { 239 | String s = String.format("%X", JsonWriter.umulHigh(0x8000_0000_0000_0001L, 0x8000_0000_0000_0000L)); 240 | assertEquals("4000000000000000", s); 241 | if (Integer.parseInt(System.getProperty("java.version").replaceFirst("^1\\.", "").replaceFirst("\\D.*", "")) > 8) { 242 | s = String.format("%X", JsonWriter.umulHigh9(0x8000_0000_0000_0001L, 0x8000_0000_0000_0000L)); 243 | assertEquals("4000000000000000", s); 244 | } 245 | } 246 | 247 | public static void testD() throws ReflectiveOperationException { 248 | C c = new C(); 249 | A a = new A(); 250 | a.a = 123; 251 | c.m.put(a, 456); 252 | String j = JsonWriter.local().clear().write(c).toString(); 253 | assertEquals("{\n" + 254 | "\t\"a\": {\n" + 255 | "\t\t\"a\": 0,\n" + 256 | "\t\t\"b\": 0\n" + 257 | "\t},\n" + 258 | "\t\"m\": {\n" + 259 | "\t\t\"{a:123}\": 456\n" + 260 | "\t}\n" + 261 | "}", j); 262 | c.m.clear(); 263 | JsonReader.local().buf(j).parse(c); 264 | Map.Entry e = c.m.entrySet().iterator().next(); 265 | assertEquals(123, e.getKey().a); 266 | assertEquals(456, e.getValue().intValue()); 267 | } 268 | 269 | public static void testE() { 270 | byte[] b = JsonReader.local().buf("'\\u001F\\u03A0\\u9abf\\uD955\\udeaa'").parseByteString(); 271 | assertNotNull(b); 272 | String s = new String(b, StandardCharsets.UTF_8); 273 | assertEquals(10, b.length); 274 | assertEquals(5, s.length()); 275 | assertEquals(0x1f, s.charAt(0)); 276 | assertEquals(0x3a0, s.charAt(1)); 277 | assertEquals(0x9abf, s.charAt(2)); 278 | assertEquals(0xd955, s.charAt(3)); 279 | assertEquals(0xdeaa, s.charAt(4)); 280 | 281 | s = JsonReader.local().buf("'\\u001F\\u03A0\\u9abf\\uD955\\udeaa'").parseString(); 282 | assertNotNull(s); 283 | assertEquals(5, s.length()); 284 | assertEquals(0x1f, s.charAt(0)); 285 | assertEquals(0x3a0, s.charAt(1)); 286 | assertEquals(0x9abf, s.charAt(2)); 287 | assertEquals(0xd955, s.charAt(3)); 288 | assertEquals(0xdeaa, s.charAt(4)); 289 | 290 | s = JsonReader.local().buf("\\u001F\\u03A0\\u9abf\\uD955\\udeaa ").parseStringNoQuot(); 291 | assertNotNull(s); 292 | assertEquals(5, s.length()); 293 | assertEquals(0x1f, s.charAt(0)); 294 | assertEquals(0x3a0, s.charAt(1)); 295 | assertEquals(0x9abf, s.charAt(2)); 296 | assertEquals(0xd955, s.charAt(3)); 297 | assertEquals(0xdeaa, s.charAt(4)); 298 | 299 | JsonWriter.local().clear().write(s, true); 300 | char[] c = JsonWriter.local().toChars(); 301 | assertEquals(15, JsonWriter.local().size()); // 6+2+3+4 302 | assertEquals(10, c.length); // 6+1+1+2 303 | assertEquals("\\u001F", new String(c, 0, 6)); 304 | assertEquals(0x3a0, c[6]); 305 | assertEquals(0x9abf, c[7]); 306 | assertEquals(0xd955, c[8]); 307 | assertEquals(0xdeaa, c[9]); 308 | } 309 | 310 | public static void testF() throws ReflectiveOperationException { 311 | Object o = JsonReader.local().buf("[Infinity,-Infinity,NaN,0x1234567890abcdef,-0x1]").parse(); 312 | assertNotNull(o); 313 | assertEquals(ArrayList.class, o.getClass()); 314 | ArrayList a = (ArrayList)o; 315 | assertEquals(5, a.size()); 316 | assertEquals(Double.POSITIVE_INFINITY, a.get(0)); 317 | assertEquals(Double.NEGATIVE_INFINITY, a.get(1)); 318 | assertEquals(Double.NaN, a.get(2)); 319 | assertEquals(0x1234567890abcdefL, a.get(3)); 320 | assertEquals(-1, a.get(4)); 321 | } 322 | 323 | static class H { 324 | String s; 325 | int v; 326 | } 327 | 328 | public static void testG() throws ReflectiveOperationException { 329 | H a = JsonReader.local().buf("{s:true,v:123}").parse(H.class); 330 | assertNotNull(a); 331 | assertEquals("true", a.s); 332 | assertEquals(123, a.v); 333 | a = JsonReader.local().buf("{s:null\nv:456}").parse(H.class); 334 | assertNotNull(a); 335 | assertEquals("null", a.s); 336 | assertEquals(456, a.v); 337 | } 338 | 339 | public static void main(String[] args) throws ReflectiveOperationException { 340 | test1(); 341 | test2(); 342 | test3(); 343 | test4(); 344 | test5(); 345 | test6(); 346 | test7(); 347 | test8(); 348 | test9(); 349 | testA(); 350 | testB(); 351 | testC(); 352 | testD(); 353 | testE(); 354 | testF(); 355 | testG(); 356 | System.out.println(Test.class.getSimpleName() + ": 16 tests OK!"); 357 | } 358 | } 359 | -------------------------------------------------------------------------------- /src/jason/Json.java: -------------------------------------------------------------------------------- 1 | package jason; 2 | 3 | import java.lang.invoke.MethodHandle; 4 | import java.lang.invoke.MethodHandles; 5 | import java.lang.reflect.*; 6 | import java.nio.charset.StandardCharsets; 7 | import java.util.*; 8 | import java.util.concurrent.ConcurrentHashMap; 9 | import java.util.function.BiFunction; 10 | import org.eclipse.jdt.annotation.NonNull; 11 | import org.eclipse.jdt.annotation.Nullable; 12 | import sun.misc.Unsafe; 13 | 14 | // Compile with JDK11+; Run with JDK8+ (JDK9+ is recommended); Android is NOT supported 15 | public final class Json implements Cloneable { 16 | static final int TYPE_BOOLEAN = 1; // boolean, Boolean 17 | static final int TYPE_BYTE = 2; // byte, Byte 18 | static final int TYPE_SHORT = 3; // short, Short 19 | static final int TYPE_CHAR = 4; // char, Character 20 | static final int TYPE_INT = 5; // int, Integer 21 | static final int TYPE_LONG = 6; // long, Long 22 | static final int TYPE_FLOAT = 7; // float, Float 23 | static final int TYPE_DOUBLE = 8; // double, Double 24 | static final int TYPE_STRING = 9; // String 25 | static final int TYPE_OBJECT = 10; // Object(null,Boolean,Integer,Long,Double,String,ArrayList,HashMap) 26 | static final int TYPE_POS = 11; // Pos(pos) 27 | static final int TYPE_CUSTOM = 12; // user custom type 28 | static final int TYPE_WRAP_FLAG = 0x10; // wrap<1~8> 29 | static final int TYPE_LIST_FLAG = 0x20; // Collection<1~12> (parser only needs clear() & add(v)) 30 | static final int TYPE_MAP_FLAG = 0x30; // Map (parser only needs clear() & put(k,v)) 31 | 32 | public interface KeyReader { 33 | @NonNull 34 | Object parse(@NonNull JsonReader jr, int b) throws ReflectiveOperationException; 35 | } 36 | 37 | public interface Creator { 38 | T create() throws ReflectiveOperationException; 39 | } 40 | 41 | public static final class FieldMeta { 42 | public final int hash; // for FieldMetaMap 43 | public final int type; // defined above 44 | public final int offset; // for unsafe access 45 | public final @NonNull Class klass; // TYPE_CUSTOM:fieldClass; TYPE_LIST_FLAG/TYPE_MAP_FLAG:subValueClass 46 | transient @Nullable ClassMeta classMeta; // from klass, lazy assigned 47 | transient @Nullable FieldMeta next; // for FieldMetaMap 48 | public final byte[] name; // field name 49 | public final @Nullable Creator ctor; // for TYPE_LIST_FLAG/TYPE_MAP_FLAG 50 | public final @Nullable KeyReader keyParser; // for TYPE_MAP_FLAG 51 | public final @NonNull Field field; 52 | public final @Nullable Type[] paramTypes; 53 | 54 | public FieldMeta(int type, int offset, @NonNull String name, @NonNull Class klass, @Nullable Creator ctor, 55 | @Nullable KeyReader keyReader, @NonNull Field field) { 56 | this.name = name.getBytes(StandardCharsets.UTF_8); 57 | this.hash = getKeyHash(this.name, 0, this.name.length); 58 | this.type = type; 59 | this.offset = offset; 60 | this.klass = klass; 61 | this.ctor = ctor; 62 | this.keyParser = keyReader; 63 | this.field = field; 64 | Type geneType = field.getGenericType(); 65 | paramTypes = geneType instanceof ParameterizedType 66 | ? ((ParameterizedType)geneType).getActualTypeArguments() : null; 67 | } 68 | 69 | @NonNull 70 | public String getName() { 71 | return new String(name, StandardCharsets.UTF_8); 72 | } 73 | } 74 | 75 | public interface Parser { 76 | @Nullable 77 | T parse(@NonNull JsonReader reader, @NonNull ClassMeta classMeta, @Nullable FieldMeta fieldMeta, 78 | @Nullable T obj, @Nullable Object parent) throws ReflectiveOperationException; 79 | 80 | @SuppressWarnings("unchecked") 81 | default @Nullable T parse0(@NonNull JsonReader reader, @NonNull ClassMeta classMeta, 82 | @Nullable FieldMeta fieldMeta, @Nullable Object obj, 83 | @Nullable Object parent) throws ReflectiveOperationException { 84 | return parse(reader, (ClassMeta)classMeta, fieldMeta, (T)obj, parent); 85 | } 86 | } 87 | 88 | public interface Writer { 89 | void write(@NonNull JsonWriter writer, @NonNull ClassMeta classMeta, @Nullable T obj); 90 | 91 | // ensure +1 92 | @SuppressWarnings("unchecked") 93 | default void write0(@NonNull JsonWriter writer, @NonNull ClassMeta classMeta, @Nullable Object obj) { 94 | write(writer, (ClassMeta)classMeta, (T)obj); 95 | } 96 | } 97 | 98 | public static final class Pos { 99 | public int pos; 100 | 101 | public Pos() { 102 | } 103 | 104 | public Pos(int p) { 105 | pos = p; 106 | } 107 | } 108 | 109 | public static final class ClassMeta { 110 | private static final @NonNull HashMap, Integer> typeMap = new HashMap<>(32); 111 | private static final @NonNull HashMap keyReaderMap = new HashMap<>(16); 112 | 113 | final @NonNull Json json; 114 | final @NonNull Class klass; 115 | final @NonNull Creator ctor; 116 | private final FieldMeta[] valueTable; 117 | final FieldMeta[] fieldMetas; 118 | transient @Nullable Parser parser; // user custom parser 119 | transient @Nullable Writer writer; // user custom writer 120 | 121 | static { 122 | typeMap.put(boolean.class, TYPE_BOOLEAN); 123 | typeMap.put(byte.class, TYPE_BYTE); 124 | typeMap.put(short.class, TYPE_SHORT); 125 | typeMap.put(char.class, TYPE_CHAR); 126 | typeMap.put(int.class, TYPE_INT); 127 | typeMap.put(long.class, TYPE_LONG); 128 | typeMap.put(float.class, TYPE_FLOAT); 129 | typeMap.put(double.class, TYPE_DOUBLE); 130 | typeMap.put(String.class, TYPE_STRING); 131 | typeMap.put(Object.class, TYPE_OBJECT); 132 | typeMap.put(Pos.class, TYPE_POS); 133 | typeMap.put(Boolean.class, TYPE_WRAP_FLAG + TYPE_BOOLEAN); 134 | typeMap.put(Byte.class, TYPE_WRAP_FLAG + TYPE_BYTE); 135 | typeMap.put(Short.class, TYPE_WRAP_FLAG + TYPE_SHORT); 136 | typeMap.put(Character.class, TYPE_WRAP_FLAG + TYPE_CHAR); 137 | typeMap.put(Integer.class, TYPE_WRAP_FLAG + TYPE_INT); 138 | typeMap.put(Long.class, TYPE_WRAP_FLAG + TYPE_LONG); 139 | typeMap.put(Float.class, TYPE_WRAP_FLAG + TYPE_FLOAT); 140 | typeMap.put(Double.class, TYPE_WRAP_FLAG + TYPE_DOUBLE); 141 | keyReaderMap.put(Boolean.class, JsonReader::parseBooleanKey); 142 | keyReaderMap.put(Byte.class, JsonReader::parseByteKey); 143 | keyReaderMap.put(Short.class, JsonReader::parseShortKey); 144 | keyReaderMap.put(Character.class, JsonReader::parseCharKey); 145 | keyReaderMap.put(Integer.class, JsonReader::parseIntegerKey); 146 | keyReaderMap.put(Long.class, JsonReader::parseLongKey); 147 | keyReaderMap.put(Float.class, JsonReader::parseFloatKey); 148 | keyReaderMap.put(Double.class, JsonReader::parseDoubleKey); 149 | keyReaderMap.put(String.class, JsonReader::parseStringKey); 150 | keyReaderMap.put(Object.class, JsonReader::parseStringKey); 151 | } 152 | 153 | static boolean isInKeyReaderMap(Class klass) { 154 | return keyReaderMap.containsKey(klass); 155 | } 156 | 157 | public static KeyReader getKeyReader(Class klass) { 158 | return keyReaderMap.get(klass); 159 | } 160 | 161 | static boolean isAbstract(@NonNull Class klass) { 162 | return (klass.getModifiers() & (Modifier.INTERFACE | Modifier.ABSTRACT)) != 0; 163 | } 164 | 165 | @SuppressWarnings("unchecked") 166 | public static @NonNull Creator getDefCtor(@NonNull Class klass) { 167 | try { 168 | for (Constructor c : klass.getDeclaredConstructors()) { 169 | if (c.getParameterCount() == 0) { 170 | setAccessible(c); 171 | MethodHandle ctorMH = lookup.unreflectConstructor(c); 172 | return () -> { 173 | try { 174 | return (T)ctorMH.invoke(); 175 | } catch (Throwable e) { // MethodHandle.invoke 176 | throw new RuntimeException(e); 177 | } 178 | }; 179 | } 180 | } 181 | } catch (IllegalAccessException ignored) { 182 | } 183 | return () -> (T)unsafe.allocateInstance(klass); 184 | } 185 | 186 | private static @Nullable Class getCollectionSubClass(Type geneType) { // X, X extends Y, X implements Y 187 | if (geneType instanceof ParameterizedType) { 188 | //noinspection PatternVariableCanBeUsed 189 | ParameterizedType paraType = (ParameterizedType)geneType; 190 | Class rawClass = (Class)paraType.getRawType(); 191 | if (Collection.class.isAssignableFrom(rawClass)) { 192 | Type type = paraType.getActualTypeArguments()[0]; 193 | if (type instanceof Class) 194 | return (Class)type; 195 | } 196 | } 197 | if (geneType instanceof Class) { 198 | //noinspection PatternVariableCanBeUsed 199 | Class klass = (Class)geneType; 200 | for (Type subType : klass.getGenericInterfaces()) { 201 | Class subClass = getCollectionSubClass(subType); 202 | if (subClass != null) 203 | return subClass; 204 | } 205 | return getCollectionSubClass(klass.getGenericSuperclass()); 206 | } 207 | return null; 208 | } 209 | 210 | private static Class getRawClass(Type type) { 211 | if (type instanceof Class) 212 | return (Class)type; 213 | if (type instanceof ParameterizedType) 214 | return (Class)((ParameterizedType)type).getRawType(); 215 | if (type instanceof TypeVariable) { 216 | Type[] bounds = ((TypeVariable)type).getBounds(); 217 | if (bounds.length > 0) 218 | return getRawClass(bounds[0]); 219 | } 220 | return Object.class; 221 | } 222 | 223 | private static Type[] getMapSubClasses(Type geneType) { // X, X extends Y, X implements Y 224 | if (geneType instanceof ParameterizedType) { 225 | //noinspection PatternVariableCanBeUsed 226 | ParameterizedType paraType = (ParameterizedType)geneType; 227 | if (Map.class.isAssignableFrom((Class)paraType.getRawType())) { 228 | Type[] subTypes = paraType.getActualTypeArguments(); 229 | if (subTypes.length == 2) { 230 | subTypes[0] = getRawClass(subTypes[0]); 231 | subTypes[1] = getRawClass(subTypes[1]); 232 | return subTypes; 233 | } 234 | } 235 | } 236 | if (geneType instanceof Class) { 237 | //noinspection PatternVariableCanBeUsed 238 | Class klass = (Class)geneType; 239 | for (Type subType : klass.getGenericInterfaces()) { 240 | Type[] subTypes = getMapSubClasses(subType); 241 | if (subTypes != null) 242 | return subTypes; 243 | } 244 | return getMapSubClasses(klass.getGenericSuperclass()); 245 | } 246 | return null; 247 | } 248 | 249 | ClassMeta(final @NonNull Json json, final @NonNull Class klass) { 250 | this.json = json; 251 | this.klass = klass; 252 | ctor = getDefCtor(klass); 253 | int size = 0; 254 | for (Class c = klass; c != null; c = c.getSuperclass()) 255 | for (Field field : getDeclaredFields(c)) 256 | if ((field.getModifiers() & (Modifier.STATIC | Modifier.TRANSIENT)) == 0 257 | && !field.getName().startsWith("this$")) 258 | size++; 259 | valueTable = new FieldMeta[1 << (32 - Integer.numberOfLeadingZeros(size * 2 - 1))]; 260 | fieldMetas = new FieldMeta[size]; 261 | ArrayList> classes = new ArrayList<>(2); 262 | for (Class c = klass; c != null; c = c.getSuperclass()) 263 | classes.add(c); 264 | for (int i = classes.size() - 1, j = 0; i >= 0; i--) { 265 | Class c = classes.get(i); 266 | for (Field field : getDeclaredFields(c)) { 267 | if ((field.getModifiers() & (Modifier.STATIC | Modifier.TRANSIENT)) != 0) 268 | continue; 269 | final String fieldName = field.getName(); 270 | if (fieldName.startsWith("this$")) // closure field 271 | continue; 272 | Class fieldClass = ensureNonNull(field.getType()); 273 | Creator fieldCtor = null; 274 | KeyReader keyReader = null; 275 | Integer v = typeMap.get(fieldClass); 276 | int type; 277 | if (v != null) 278 | type = v; 279 | else if (Collection.class.isAssignableFrom(fieldClass)) { // Collection 280 | if (!isAbstract(fieldClass)) 281 | fieldCtor = getDefCtor(fieldClass); 282 | else if (fieldClass.isAssignableFrom(ArrayList.class)) // AbstractList,AbstractCollection,List,Collection 283 | fieldCtor = getDefCtor(ArrayList.class); 284 | else if (fieldClass.isAssignableFrom(HashSet.class)) // AbstractSet,Set 285 | fieldCtor = getDefCtor(HashSet.class); 286 | else if (fieldClass.isAssignableFrom(ArrayDeque.class)) // Deque 287 | fieldCtor = getDefCtor(ArrayDeque.class); 288 | else if (fieldClass.isAssignableFrom(TreeSet.class)) // NavigableSet 289 | fieldCtor = getDefCtor(TreeSet.class); 290 | else if (fieldClass.isAssignableFrom(LinkedList.class)) // AbstractSequentialList 291 | fieldCtor = getDefCtor(LinkedList.class); 292 | else if (fieldClass.isAssignableFrom(PriorityQueue.class)) // AbstractQueue 293 | fieldCtor = getDefCtor(PriorityQueue.class); 294 | Class subClass = getCollectionSubClass(field.getGenericType()); 295 | if (subClass != null) { 296 | v = typeMap.get(fieldClass = subClass); 297 | type = TYPE_LIST_FLAG + (v != null ? v & 0xf : TYPE_CUSTOM); 298 | } else 299 | type = TYPE_LIST_FLAG + TYPE_OBJECT; 300 | } else if (Map.class.isAssignableFrom(fieldClass)) { // Map 301 | if (!isAbstract(fieldClass)) 302 | fieldCtor = getDefCtor(fieldClass); 303 | else if (fieldClass.isAssignableFrom(HashMap.class)) // AbstractMap,Map 304 | fieldCtor = getDefCtor(HashMap.class); 305 | else if (fieldClass.isAssignableFrom(TreeMap.class)) // NavigableMap,SortedMap 306 | fieldCtor = getDefCtor(TreeMap.class); 307 | Type[] subTypes = getMapSubClasses(field.getGenericType()); 308 | if (subTypes != null) { 309 | v = typeMap.get(fieldClass = ensureNonNull((Class)subTypes[1])); 310 | type = TYPE_MAP_FLAG + (v != null ? v & 0xf : TYPE_CUSTOM); 311 | keyReader = keyReaderMap.get(subTypes[0]); 312 | if (keyReader == null) { 313 | Class keyClass = (Class)subTypes[0]; 314 | if (isAbstract(keyClass)) { 315 | throw new IllegalStateException("unsupported abstract key class for field: " 316 | + fieldName + " in " + klass.getName()); 317 | } 318 | Creator keyCtor = getDefCtor(keyClass); 319 | keyReader = (jr, b) -> { 320 | String keyStr = JsonReader.parseStringKey(jr, b); 321 | return ensureNonNull(new JsonReader().buf(keyStr).parse(json, keyCtor.create())); 322 | }; 323 | } 324 | } else { 325 | type = TYPE_MAP_FLAG + TYPE_OBJECT; 326 | keyReader = JsonReader::parseStringKey; 327 | } 328 | } else 329 | type = TYPE_CUSTOM; 330 | long offset = objectFieldOffset(field); 331 | if (offset != (int)offset) { 332 | throw new IllegalStateException("unexpected offset(" + offset + ") from field: " 333 | + fieldName + " in " + klass.getName()); 334 | } 335 | final BiFunction, Field, String> fieldNameFilter = json.fieldNameFilter; 336 | final String fn = fieldNameFilter != null ? fieldNameFilter.apply(c, field) : fieldName; 337 | put(j++, new FieldMeta(type, (int)offset, fn != null ? fn : fieldName, fieldClass, fieldCtor, 338 | keyReader, field)); 339 | } 340 | } 341 | } 342 | 343 | public static int getType(Class klass) { 344 | Integer type = typeMap.get(klass); 345 | return type != null ? type : TYPE_CUSTOM; 346 | } 347 | 348 | public @NonNull Creator getCtor() { 349 | return ctor; 350 | } 351 | 352 | public @Nullable Parser getParser() { 353 | return parser; 354 | } 355 | 356 | public void setParser(@Nullable Parser p) { 357 | parser = p; 358 | } 359 | 360 | @SuppressWarnings("unchecked") 361 | @Deprecated // unsafe 362 | public void setParserUnsafe(@Nullable Parser p) { // DANGEROUS! only for special purpose 363 | parser = (Parser)p; 364 | } 365 | 366 | public @Nullable Writer getWriter() { 367 | return writer; 368 | } 369 | 370 | public void setWriter(@Nullable Writer w) { 371 | writer = w; 372 | } 373 | 374 | @Nullable 375 | FieldMeta get(int hash) { 376 | for (FieldMeta fm = valueTable[hash & (valueTable.length - 1)]; fm != null; fm = fm.next) 377 | if (fm.hash == hash) 378 | return fm; 379 | return null; 380 | } 381 | 382 | void put(int idx, @NonNull FieldMeta fieldMeta) { 383 | fieldMeta.next = null; 384 | fieldMetas[idx] = fieldMeta; 385 | int hash = fieldMeta.hash; 386 | int i = hash & (valueTable.length - 1); 387 | FieldMeta fm = valueTable[i]; 388 | if (fm == null) { // fast path 389 | valueTable[i] = fieldMeta; 390 | return; 391 | } 392 | for (; ; ) { 393 | if (fm.hash == hash) { // bad luck! try to call setKeyHashMultiplier with another prime number 394 | throw new IllegalStateException("conflicted field names: " + fieldMeta.getName() + " & " 395 | + fm.getName() + " in " + fieldMeta.klass.getName()); 396 | } 397 | FieldMeta next = fm.next; 398 | if (next == null) { 399 | fm.next = fieldMeta; 400 | return; 401 | } 402 | fm = next; 403 | } 404 | } 405 | } 406 | 407 | private static final MethodHandles.@NonNull Lookup lookup = MethodHandles.lookup(); 408 | public static final int javaVersion; 409 | static final @NonNull Unsafe unsafe; 410 | private static final @NonNull MethodHandle getDeclaredFields0MH; 411 | static final @NonNull MethodHandle objectFieldOffsetMH; 412 | static final @NonNull MethodHandle stringCtorMH; 413 | private static final long OVERRIDE_OFFSET; 414 | static final long STRING_VALUE_OFFSET, STRING_CODE_OFFSET; 415 | static final boolean BYTE_STRING; 416 | static final int keyHashMultiplier = 0x100_0193; // 1677_7619 can be changed to another prime number 417 | public static final Json instance = new Json(); 418 | 419 | private final @NonNull ConcurrentHashMap, ClassMeta> classMetas = new ConcurrentHashMap<>(); 420 | public BiFunction, Field, String> fieldNameFilter; 421 | 422 | @SuppressWarnings("MethodDoesntCallSuperMethod") 423 | @Override 424 | public @NonNull Json clone() { 425 | Json json = new Json(); 426 | json.classMetas.putAll(classMetas); 427 | json.fieldNameFilter = fieldNameFilter; 428 | return json; 429 | } 430 | 431 | static { 432 | try { 433 | javaVersion = (int)Float.parseFloat(System.getProperty("java.specification.version")); 434 | Field theUnsafeField = Unsafe.class.getDeclaredField("theUnsafe"); 435 | theUnsafeField.setAccessible(true); 436 | unsafe = ensureNonNull((Unsafe)theUnsafeField.get(null)); 437 | for (long i = 8; ; i++) { 438 | if (unsafe.getBoolean(theUnsafeField, i)) { 439 | theUnsafeField.setAccessible(false); 440 | if (!unsafe.getBoolean(theUnsafeField, i)) { 441 | OVERRIDE_OFFSET = i; 442 | break; 443 | } 444 | theUnsafeField.setAccessible(true); 445 | } 446 | if (i == 32) // should be enough 447 | throw new UnsupportedOperationException(System.getProperty("java.version")); 448 | } 449 | getDeclaredFields0MH = ensureNonNull(lookup.unreflect(setAccessible( 450 | Class.class.getDeclaredMethod("getDeclaredFields0", boolean.class)))); 451 | if (javaVersion < 9) { 452 | objectFieldOffsetMH = lookup.unreflect( 453 | Unsafe.class.getMethod("objectFieldOffset", Field.class)).bindTo(unsafe); 454 | } else { 455 | Class jdkUnsafeClass = Class.forName("jdk.internal.misc.Unsafe"); 456 | objectFieldOffsetMH = lookup.unreflect(Json.setAccessible(jdkUnsafeClass.getMethod( 457 | "objectFieldOffset", Field.class))).bindTo(setAccessible(Objects.requireNonNull( 458 | getDeclaredField(jdkUnsafeClass, "theUnsafe"))).get(null)); 459 | } 460 | Field valueField = getDeclaredField(String.class, "value"); 461 | STRING_VALUE_OFFSET = objectFieldOffset(Objects.requireNonNull(valueField)); 462 | BYTE_STRING = valueField.getType() == byte[].class; 463 | STRING_CODE_OFFSET = BYTE_STRING ? 464 | objectFieldOffset(Objects.requireNonNull(getDeclaredField(String.class, "coder"))) : 0; 465 | //noinspection JavaReflectionMemberAccess 466 | stringCtorMH = ensureNonNull(lookup.unreflectConstructor(setAccessible(BYTE_STRING 467 | ? String.class.getDeclaredConstructor(byte[].class, byte.class) 468 | : String.class.getDeclaredConstructor(char[].class, boolean.class)))); 469 | } catch (ReflectiveOperationException e) { 470 | throw new ExceptionInInitializerError(e); 471 | } 472 | } 473 | 474 | public static @NonNull Unsafe getUnsafe() { 475 | return unsafe; 476 | } 477 | 478 | public static long objectFieldOffset(@NonNull Field field) { 479 | try { 480 | return (long)objectFieldOffsetMH.invoke(field); 481 | } catch (Throwable e) { 482 | throw new RuntimeException(e); 483 | } 484 | } 485 | 486 | static @NonNull Field @NonNull [] getDeclaredFields(@NonNull Class klass) { 487 | try { 488 | return (Field[])getDeclaredFields0MH.invokeExact(klass, false); 489 | } catch (RuntimeException | Error e) { 490 | throw e; 491 | } catch (Throwable e) { // MethodHandle.invoke 492 | throw new RuntimeException(e); 493 | } 494 | } 495 | 496 | @SuppressWarnings("SameParameterValue") 497 | static @Nullable Field getDeclaredField(@NonNull Class klass, @NonNull String fieldName) { 498 | for (Field field : getDeclaredFields(klass)) 499 | if (field.getName().equals(fieldName)) 500 | return field; 501 | return null; 502 | } 503 | 504 | public static @NonNull T setAccessible(@NonNull T ao) { 505 | unsafe.putBoolean(ao, OVERRIDE_OFFSET, true); 506 | return ao; 507 | } 508 | 509 | public static @NonNull T ensureNonNull(@Nullable T obj) { 510 | assert obj != null; 511 | return obj; 512 | } 513 | 514 | // public static void setKeyHashMultiplier(int multiplier) { // must be set before any other access 515 | // keyHashMultiplier = multiplier; 516 | // } 517 | 518 | public static int getKeyHash(byte @NonNull [] buf, int pos, int end) { 519 | if (pos >= end) 520 | return 0; 521 | //noinspection UnnecessaryLocalVariable 522 | int h = buf[pos], m = keyHashMultiplier; 523 | while (++pos < end) 524 | h = h * m + buf[pos]; 525 | return h; 526 | } 527 | 528 | static @NonNull String newByteString(byte @NonNull [] buf, int pos, int end) { 529 | if (!BYTE_STRING) // for JDK8- 530 | return new String(buf, pos, end - pos, StandardCharsets.ISO_8859_1); 531 | try { 532 | return (String)stringCtorMH.invokeExact(Arrays.copyOfRange(buf, pos, end), (byte)0); // for JDK9+ 533 | } catch (Throwable e) { // MethodHandle.invoke 534 | throw new RuntimeException(e); 535 | } 536 | } 537 | 538 | @SuppressWarnings("unchecked") 539 | public @NonNull ClassMeta getClassMeta(@NonNull Class klass) { 540 | ClassMeta cm = classMetas.get(klass); 541 | if (cm == null) 542 | cm = classMetas.computeIfAbsent(klass, c -> new ClassMeta<>(this, c)); 543 | return (ClassMeta)cm; 544 | } 545 | 546 | public void clearClassMetas() { 547 | classMetas.clear(); 548 | } 549 | 550 | public static @Nullable T parse(@NonNull String jsonStr, @Nullable Class klass) { 551 | JsonReader jr = JsonReader.local(); 552 | try { 553 | return jr.buf(jsonStr).parse(klass); 554 | } catch (ReflectiveOperationException e) { 555 | throw new RuntimeException(e); 556 | } finally { 557 | jr.reset(); 558 | } 559 | } 560 | 561 | public static @Nullable T parse(byte @NonNull [] jsonStr, @Nullable Class klass) { 562 | JsonReader jr = JsonReader.local(); 563 | try { 564 | return jr.buf(jsonStr).parse(klass); 565 | } catch (ReflectiveOperationException e) { 566 | throw new RuntimeException(e); 567 | } finally { 568 | jr.reset(); 569 | } 570 | } 571 | 572 | public static @Nullable T parse(byte @NonNull [] jsonStr, int pos, @Nullable Class klass) { 573 | JsonReader jr = JsonReader.local(); 574 | try { 575 | return jr.buf(jsonStr, pos).parse(klass); 576 | } catch (ReflectiveOperationException e) { 577 | throw new RuntimeException(e); 578 | } finally { 579 | jr.reset(); 580 | } 581 | } 582 | 583 | public static @Nullable T parse(@NonNull String jsonStr, @Nullable T obj) { 584 | JsonReader jr = JsonReader.local(); 585 | try { 586 | return jr.buf(jsonStr).parse(obj); 587 | } catch (ReflectiveOperationException e) { 588 | throw new RuntimeException(e); 589 | } finally { 590 | jr.reset(); 591 | } 592 | } 593 | 594 | public static @Nullable T parse(byte @NonNull [] jsonStr, @Nullable T obj) { 595 | JsonReader jr = JsonReader.local(); 596 | try { 597 | return jr.buf(jsonStr).parse(obj); 598 | } catch (ReflectiveOperationException e) { 599 | throw new RuntimeException(e); 600 | } finally { 601 | jr.reset(); 602 | } 603 | } 604 | 605 | public static @Nullable T parse(byte @NonNull [] jsonStr, int pos, @Nullable T obj) { 606 | JsonReader jr = JsonReader.local(); 607 | try { 608 | return jr.buf(jsonStr, pos).parse(obj); 609 | } catch (ReflectiveOperationException e) { 610 | throw new RuntimeException(e); 611 | } finally { 612 | jr.reset(); 613 | } 614 | } 615 | 616 | public static @NonNull String toCompactString(@Nullable Object obj) { 617 | JsonWriter jw = JsonWriter.local(); 618 | try { 619 | return jw.clear().setFlagsAndDepthLimit(0, 16).write(obj).toString(); 620 | } finally { 621 | jw.clear(); 622 | } 623 | } 624 | 625 | public static byte @NonNull [] toCompactBytes(@Nullable Object obj) { 626 | JsonWriter jw = JsonWriter.local(); 627 | try { 628 | return jw.clear().setFlagsAndDepthLimit(0, 16).write(obj).toBytes(); 629 | } finally { 630 | jw.clear(); 631 | } 632 | } 633 | } 634 | -------------------------------------------------------------------------------- /.settings/org.eclipse.jdt.core.prefs: -------------------------------------------------------------------------------- 1 | eclipse.preferences.version=1 2 | org.eclipse.jdt.core.codeComplete.argumentPrefixes= 3 | org.eclipse.jdt.core.codeComplete.argumentSuffixes= 4 | org.eclipse.jdt.core.codeComplete.fieldPrefixes= 5 | org.eclipse.jdt.core.codeComplete.fieldSuffixes= 6 | org.eclipse.jdt.core.codeComplete.localPrefixes= 7 | org.eclipse.jdt.core.codeComplete.localSuffixes= 8 | org.eclipse.jdt.core.codeComplete.staticFieldPrefixes= 9 | org.eclipse.jdt.core.codeComplete.staticFieldSuffixes= 10 | org.eclipse.jdt.core.codeComplete.staticFinalFieldPrefixes= 11 | org.eclipse.jdt.core.codeComplete.staticFinalFieldSuffixes= 12 | org.eclipse.jdt.core.compiler.annotation.inheritNullAnnotations=enabled 13 | org.eclipse.jdt.core.compiler.annotation.missingNonNullByDefaultAnnotation=ignore 14 | org.eclipse.jdt.core.compiler.annotation.nonnull=org.eclipse.jdt.annotation.NonNull 15 | org.eclipse.jdt.core.compiler.annotation.nonnull.secondary= 16 | org.eclipse.jdt.core.compiler.annotation.nonnullbydefault=org.eclipse.jdt.annotation.NonNullByDefault 17 | org.eclipse.jdt.core.compiler.annotation.nonnullbydefault.secondary= 18 | org.eclipse.jdt.core.compiler.annotation.nullable=org.eclipse.jdt.annotation.Nullable 19 | org.eclipse.jdt.core.compiler.annotation.nullable.secondary= 20 | org.eclipse.jdt.core.compiler.annotation.nullanalysis=enabled 21 | org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled 22 | org.eclipse.jdt.core.compiler.codegen.methodParameters=do not generate 23 | org.eclipse.jdt.core.compiler.codegen.targetPlatform=11 24 | org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve 25 | org.eclipse.jdt.core.compiler.compliance=11 26 | org.eclipse.jdt.core.compiler.debug.lineNumber=generate 27 | org.eclipse.jdt.core.compiler.debug.localVariable=generate 28 | org.eclipse.jdt.core.compiler.debug.sourceFile=generate 29 | org.eclipse.jdt.core.compiler.problem.APILeak=warning 30 | org.eclipse.jdt.core.compiler.problem.annotatedTypeArgumentToUnannotated=warning 31 | org.eclipse.jdt.core.compiler.problem.annotationSuperInterface=warning 32 | org.eclipse.jdt.core.compiler.problem.assertIdentifier=error 33 | org.eclipse.jdt.core.compiler.problem.autoboxing=ignore 34 | org.eclipse.jdt.core.compiler.problem.comparingIdentical=warning 35 | org.eclipse.jdt.core.compiler.problem.deadCode=warning 36 | org.eclipse.jdt.core.compiler.problem.deprecation=warning 37 | org.eclipse.jdt.core.compiler.problem.deprecationInDeprecatedCode=disabled 38 | org.eclipse.jdt.core.compiler.problem.deprecationWhenOverridingDeprecatedMethod=disabled 39 | org.eclipse.jdt.core.compiler.problem.discouragedReference=warning 40 | org.eclipse.jdt.core.compiler.problem.emptyStatement=warning 41 | org.eclipse.jdt.core.compiler.problem.enablePreviewFeatures=disabled 42 | org.eclipse.jdt.core.compiler.problem.enumIdentifier=error 43 | org.eclipse.jdt.core.compiler.problem.explicitlyClosedAutoCloseable=warning 44 | org.eclipse.jdt.core.compiler.problem.fallthroughCase=warning 45 | org.eclipse.jdt.core.compiler.problem.fatalOptionalError=disabled 46 | org.eclipse.jdt.core.compiler.problem.fieldHiding=warning 47 | org.eclipse.jdt.core.compiler.problem.finalParameterBound=warning 48 | org.eclipse.jdt.core.compiler.problem.finallyBlockNotCompletingNormally=warning 49 | org.eclipse.jdt.core.compiler.problem.forbiddenReference=ignore 50 | org.eclipse.jdt.core.compiler.problem.hiddenCatchBlock=warning 51 | org.eclipse.jdt.core.compiler.problem.includeNullInfoFromAsserts=disabled 52 | org.eclipse.jdt.core.compiler.problem.incompatibleNonInheritedInterfaceMethod=warning 53 | org.eclipse.jdt.core.compiler.problem.incompleteEnumSwitch=warning 54 | org.eclipse.jdt.core.compiler.problem.indirectStaticAccess=warning 55 | org.eclipse.jdt.core.compiler.problem.localVariableHiding=warning 56 | org.eclipse.jdt.core.compiler.problem.methodWithConstructorName=warning 57 | org.eclipse.jdt.core.compiler.problem.missingDefaultCase=ignore 58 | org.eclipse.jdt.core.compiler.problem.missingDeprecatedAnnotation=warning 59 | org.eclipse.jdt.core.compiler.problem.missingEnumCaseDespiteDefault=disabled 60 | org.eclipse.jdt.core.compiler.problem.missingHashCodeMethod=warning 61 | org.eclipse.jdt.core.compiler.problem.missingOverrideAnnotation=warning 62 | org.eclipse.jdt.core.compiler.problem.missingOverrideAnnotationForInterfaceMethodImplementation=enabled 63 | org.eclipse.jdt.core.compiler.problem.missingSerialVersion=warning 64 | org.eclipse.jdt.core.compiler.problem.missingSynchronizedOnInheritedMethod=warning 65 | org.eclipse.jdt.core.compiler.problem.noEffectAssignment=warning 66 | org.eclipse.jdt.core.compiler.problem.noImplicitStringConversion=warning 67 | org.eclipse.jdt.core.compiler.problem.nonExternalizedStringLiteral=ignore 68 | org.eclipse.jdt.core.compiler.problem.nonnullParameterAnnotationDropped=warning 69 | org.eclipse.jdt.core.compiler.problem.nonnullTypeVariableFromLegacyInvocation=ignore 70 | org.eclipse.jdt.core.compiler.problem.nullAnnotationInferenceConflict=warning 71 | org.eclipse.jdt.core.compiler.problem.nullReference=error 72 | org.eclipse.jdt.core.compiler.problem.nullSpecViolation=warning 73 | org.eclipse.jdt.core.compiler.problem.nullUncheckedConversion=warning 74 | org.eclipse.jdt.core.compiler.problem.overridingPackageDefaultMethod=warning 75 | org.eclipse.jdt.core.compiler.problem.parameterAssignment=ignore 76 | org.eclipse.jdt.core.compiler.problem.pessimisticNullAnalysisForFreeTypeVariables=warning 77 | org.eclipse.jdt.core.compiler.problem.possibleAccidentalBooleanAssignment=warning 78 | org.eclipse.jdt.core.compiler.problem.potentialNullReference=warning 79 | org.eclipse.jdt.core.compiler.problem.potentiallyUnclosedCloseable=warning 80 | org.eclipse.jdt.core.compiler.problem.rawTypeReference=warning 81 | org.eclipse.jdt.core.compiler.problem.redundantNullAnnotation=warning 82 | org.eclipse.jdt.core.compiler.problem.redundantNullCheck=warning 83 | org.eclipse.jdt.core.compiler.problem.redundantSpecificationOfTypeArguments=warning 84 | org.eclipse.jdt.core.compiler.problem.redundantSuperinterface=warning 85 | org.eclipse.jdt.core.compiler.problem.reportMethodCanBePotentiallyStatic=warning 86 | org.eclipse.jdt.core.compiler.problem.reportMethodCanBeStatic=warning 87 | org.eclipse.jdt.core.compiler.problem.reportPreviewFeatures=warning 88 | org.eclipse.jdt.core.compiler.problem.specialParameterHidingField=disabled 89 | org.eclipse.jdt.core.compiler.problem.staticAccessReceiver=warning 90 | org.eclipse.jdt.core.compiler.problem.suppressOptionalErrors=disabled 91 | org.eclipse.jdt.core.compiler.problem.suppressWarnings=enabled 92 | org.eclipse.jdt.core.compiler.problem.suppressWarningsNotFullyAnalysed=info 93 | org.eclipse.jdt.core.compiler.problem.syntacticNullAnalysisForFields=enabled 94 | org.eclipse.jdt.core.compiler.problem.syntheticAccessEmulation=ignore 95 | org.eclipse.jdt.core.compiler.problem.terminalDeprecation=warning 96 | org.eclipse.jdt.core.compiler.problem.typeParameterHiding=warning 97 | org.eclipse.jdt.core.compiler.problem.unavoidableGenericTypeProblems=enabled 98 | org.eclipse.jdt.core.compiler.problem.uncheckedTypeOperation=warning 99 | org.eclipse.jdt.core.compiler.problem.unclosedCloseable=warning 100 | org.eclipse.jdt.core.compiler.problem.undocumentedEmptyBlock=ignore 101 | org.eclipse.jdt.core.compiler.problem.unhandledWarningToken=ignore 102 | org.eclipse.jdt.core.compiler.problem.unlikelyCollectionMethodArgumentType=warning 103 | org.eclipse.jdt.core.compiler.problem.unlikelyCollectionMethodArgumentTypeStrict=disabled 104 | org.eclipse.jdt.core.compiler.problem.unlikelyEqualsArgumentType=info 105 | org.eclipse.jdt.core.compiler.problem.unnecessaryElse=warning 106 | org.eclipse.jdt.core.compiler.problem.unnecessaryTypeCheck=warning 107 | org.eclipse.jdt.core.compiler.problem.unqualifiedFieldAccess=ignore 108 | org.eclipse.jdt.core.compiler.problem.unstableAutoModuleName=warning 109 | org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownException=warning 110 | org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownExceptionExemptExceptionAndThrowable=enabled 111 | org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownExceptionIncludeDocCommentReference=enabled 112 | org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownExceptionWhenOverriding=disabled 113 | org.eclipse.jdt.core.compiler.problem.unusedExceptionParameter=ignore 114 | org.eclipse.jdt.core.compiler.problem.unusedImport=warning 115 | org.eclipse.jdt.core.compiler.problem.unusedLabel=warning 116 | org.eclipse.jdt.core.compiler.problem.unusedLocal=warning 117 | org.eclipse.jdt.core.compiler.problem.unusedObjectAllocation=warning 118 | org.eclipse.jdt.core.compiler.problem.unusedParameter=warning 119 | org.eclipse.jdt.core.compiler.problem.unusedParameterIncludeDocCommentReference=enabled 120 | org.eclipse.jdt.core.compiler.problem.unusedParameterWhenImplementingAbstract=disabled 121 | org.eclipse.jdt.core.compiler.problem.unusedParameterWhenOverridingConcrete=disabled 122 | org.eclipse.jdt.core.compiler.problem.unusedPrivateMember=warning 123 | org.eclipse.jdt.core.compiler.problem.unusedTypeParameter=warning 124 | org.eclipse.jdt.core.compiler.problem.unusedWarningToken=warning 125 | org.eclipse.jdt.core.compiler.problem.varargsArgumentNeedCast=warning 126 | org.eclipse.jdt.core.compiler.release=enabled 127 | org.eclipse.jdt.core.compiler.source=11 128 | org.eclipse.jdt.core.formatter.align_assignment_statements_on_columns=false 129 | org.eclipse.jdt.core.formatter.align_fields_grouping_blank_lines=2147483647 130 | org.eclipse.jdt.core.formatter.align_type_members_on_columns=false 131 | org.eclipse.jdt.core.formatter.align_variable_declarations_on_columns=false 132 | org.eclipse.jdt.core.formatter.align_with_spaces=false 133 | org.eclipse.jdt.core.formatter.alignment_for_additive_operator=16 134 | org.eclipse.jdt.core.formatter.alignment_for_arguments_in_allocation_expression=16 135 | org.eclipse.jdt.core.formatter.alignment_for_arguments_in_annotation=0 136 | org.eclipse.jdt.core.formatter.alignment_for_arguments_in_enum_constant=16 137 | org.eclipse.jdt.core.formatter.alignment_for_arguments_in_explicit_constructor_call=16 138 | org.eclipse.jdt.core.formatter.alignment_for_arguments_in_method_invocation=16 139 | org.eclipse.jdt.core.formatter.alignment_for_arguments_in_qualified_allocation_expression=16 140 | org.eclipse.jdt.core.formatter.alignment_for_assignment=0 141 | org.eclipse.jdt.core.formatter.alignment_for_bitwise_operator=16 142 | org.eclipse.jdt.core.formatter.alignment_for_compact_if=16 143 | org.eclipse.jdt.core.formatter.alignment_for_compact_loops=16 144 | org.eclipse.jdt.core.formatter.alignment_for_conditional_expression=80 145 | org.eclipse.jdt.core.formatter.alignment_for_conditional_expression_chain=0 146 | org.eclipse.jdt.core.formatter.alignment_for_enum_constants=16 147 | org.eclipse.jdt.core.formatter.alignment_for_expressions_in_array_initializer=16 148 | org.eclipse.jdt.core.formatter.alignment_for_expressions_in_for_loop_header=0 149 | org.eclipse.jdt.core.formatter.alignment_for_logical_operator=16 150 | org.eclipse.jdt.core.formatter.alignment_for_method_declaration=0 151 | org.eclipse.jdt.core.formatter.alignment_for_module_statements=16 152 | org.eclipse.jdt.core.formatter.alignment_for_multiple_fields=16 153 | org.eclipse.jdt.core.formatter.alignment_for_multiplicative_operator=16 154 | org.eclipse.jdt.core.formatter.alignment_for_parameterized_type_references=0 155 | org.eclipse.jdt.core.formatter.alignment_for_parameters_in_constructor_declaration=16 156 | org.eclipse.jdt.core.formatter.alignment_for_parameters_in_method_declaration=16 157 | org.eclipse.jdt.core.formatter.alignment_for_record_components=16 158 | org.eclipse.jdt.core.formatter.alignment_for_relational_operator=0 159 | org.eclipse.jdt.core.formatter.alignment_for_resources_in_try=80 160 | org.eclipse.jdt.core.formatter.alignment_for_selector_in_method_invocation=16 161 | org.eclipse.jdt.core.formatter.alignment_for_shift_operator=0 162 | org.eclipse.jdt.core.formatter.alignment_for_string_concatenation=16 163 | org.eclipse.jdt.core.formatter.alignment_for_superclass_in_type_declaration=16 164 | org.eclipse.jdt.core.formatter.alignment_for_superinterfaces_in_enum_declaration=16 165 | org.eclipse.jdt.core.formatter.alignment_for_superinterfaces_in_record_declaration=16 166 | org.eclipse.jdt.core.formatter.alignment_for_superinterfaces_in_type_declaration=16 167 | org.eclipse.jdt.core.formatter.alignment_for_throws_clause_in_constructor_declaration=16 168 | org.eclipse.jdt.core.formatter.alignment_for_throws_clause_in_method_declaration=16 169 | org.eclipse.jdt.core.formatter.alignment_for_type_arguments=0 170 | org.eclipse.jdt.core.formatter.alignment_for_type_parameters=0 171 | org.eclipse.jdt.core.formatter.alignment_for_union_type_in_multicatch=16 172 | org.eclipse.jdt.core.formatter.blank_lines_after_imports=1 173 | org.eclipse.jdt.core.formatter.blank_lines_after_last_class_body_declaration=0 174 | org.eclipse.jdt.core.formatter.blank_lines_after_package=1 175 | org.eclipse.jdt.core.formatter.blank_lines_before_abstract_method=1 176 | org.eclipse.jdt.core.formatter.blank_lines_before_field=0 177 | org.eclipse.jdt.core.formatter.blank_lines_before_first_class_body_declaration=0 178 | org.eclipse.jdt.core.formatter.blank_lines_before_imports=1 179 | org.eclipse.jdt.core.formatter.blank_lines_before_member_type=1 180 | org.eclipse.jdt.core.formatter.blank_lines_before_method=1 181 | org.eclipse.jdt.core.formatter.blank_lines_before_new_chunk=1 182 | org.eclipse.jdt.core.formatter.blank_lines_before_package=0 183 | org.eclipse.jdt.core.formatter.blank_lines_between_import_groups=0 184 | org.eclipse.jdt.core.formatter.blank_lines_between_statement_group_in_switch=0 185 | org.eclipse.jdt.core.formatter.blank_lines_between_type_declarations=1 186 | org.eclipse.jdt.core.formatter.brace_position_for_annotation_type_declaration=end_of_line 187 | org.eclipse.jdt.core.formatter.brace_position_for_anonymous_type_declaration=end_of_line 188 | org.eclipse.jdt.core.formatter.brace_position_for_array_initializer=end_of_line 189 | org.eclipse.jdt.core.formatter.brace_position_for_block=end_of_line 190 | org.eclipse.jdt.core.formatter.brace_position_for_block_in_case=end_of_line 191 | org.eclipse.jdt.core.formatter.brace_position_for_constructor_declaration=end_of_line 192 | org.eclipse.jdt.core.formatter.brace_position_for_enum_constant=end_of_line 193 | org.eclipse.jdt.core.formatter.brace_position_for_enum_declaration=end_of_line 194 | org.eclipse.jdt.core.formatter.brace_position_for_lambda_body=end_of_line 195 | org.eclipse.jdt.core.formatter.brace_position_for_method_declaration=end_of_line 196 | org.eclipse.jdt.core.formatter.brace_position_for_record_constructor=end_of_line 197 | org.eclipse.jdt.core.formatter.brace_position_for_record_declaration=end_of_line 198 | org.eclipse.jdt.core.formatter.brace_position_for_switch=end_of_line 199 | org.eclipse.jdt.core.formatter.brace_position_for_type_declaration=end_of_line 200 | org.eclipse.jdt.core.formatter.comment.align_tags_descriptions_grouped=true 201 | org.eclipse.jdt.core.formatter.comment.align_tags_names_descriptions=false 202 | org.eclipse.jdt.core.formatter.comment.clear_blank_lines_in_block_comment=false 203 | org.eclipse.jdt.core.formatter.comment.clear_blank_lines_in_javadoc_comment=false 204 | org.eclipse.jdt.core.formatter.comment.count_line_length_from_starting_position=true 205 | org.eclipse.jdt.core.formatter.comment.format_block_comments=false 206 | org.eclipse.jdt.core.formatter.comment.format_header=false 207 | org.eclipse.jdt.core.formatter.comment.format_html=true 208 | org.eclipse.jdt.core.formatter.comment.format_javadoc_comments=false 209 | org.eclipse.jdt.core.formatter.comment.format_line_comments=false 210 | org.eclipse.jdt.core.formatter.comment.format_source_code=true 211 | org.eclipse.jdt.core.formatter.comment.indent_parameter_description=false 212 | org.eclipse.jdt.core.formatter.comment.indent_root_tags=false 213 | org.eclipse.jdt.core.formatter.comment.indent_tag_description=false 214 | org.eclipse.jdt.core.formatter.comment.insert_new_line_before_root_tags=insert 215 | org.eclipse.jdt.core.formatter.comment.insert_new_line_between_different_tags=do not insert 216 | org.eclipse.jdt.core.formatter.comment.insert_new_line_for_parameter=do not insert 217 | org.eclipse.jdt.core.formatter.comment.line_length=80 218 | org.eclipse.jdt.core.formatter.comment.new_lines_at_block_boundaries=true 219 | org.eclipse.jdt.core.formatter.comment.new_lines_at_javadoc_boundaries=true 220 | org.eclipse.jdt.core.formatter.comment.preserve_white_space_between_code_and_line_comments=false 221 | org.eclipse.jdt.core.formatter.compact_else_if=true 222 | org.eclipse.jdt.core.formatter.continuation_indentation=2 223 | org.eclipse.jdt.core.formatter.continuation_indentation_for_array_initializer=2 224 | org.eclipse.jdt.core.formatter.disabling_tag=@formatter\:off 225 | org.eclipse.jdt.core.formatter.enabling_tag=@formatter\:on 226 | org.eclipse.jdt.core.formatter.format_guardian_clause_on_one_line=false 227 | org.eclipse.jdt.core.formatter.format_line_comment_starting_on_first_column=false 228 | org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_annotation_declaration_header=true 229 | org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_enum_constant_header=true 230 | org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_enum_declaration_header=true 231 | org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_record_header=true 232 | org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_type_header=true 233 | org.eclipse.jdt.core.formatter.indent_breaks_compare_to_cases=true 234 | org.eclipse.jdt.core.formatter.indent_empty_lines=false 235 | org.eclipse.jdt.core.formatter.indent_statements_compare_to_block=true 236 | org.eclipse.jdt.core.formatter.indent_statements_compare_to_body=true 237 | org.eclipse.jdt.core.formatter.indent_switchstatements_compare_to_cases=true 238 | org.eclipse.jdt.core.formatter.indent_switchstatements_compare_to_switch=false 239 | org.eclipse.jdt.core.formatter.indentation.size=4 240 | org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_enum_constant=insert 241 | org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_field=insert 242 | org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_local_variable=insert 243 | org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_method=insert 244 | org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_package=insert 245 | org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_parameter=do not insert 246 | org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_type=insert 247 | org.eclipse.jdt.core.formatter.insert_new_line_after_label=do not insert 248 | org.eclipse.jdt.core.formatter.insert_new_line_after_opening_brace_in_array_initializer=do not insert 249 | org.eclipse.jdt.core.formatter.insert_new_line_after_type_annotation=do not insert 250 | org.eclipse.jdt.core.formatter.insert_new_line_at_end_of_file_if_missing=do not insert 251 | org.eclipse.jdt.core.formatter.insert_new_line_before_catch_in_try_statement=do not insert 252 | org.eclipse.jdt.core.formatter.insert_new_line_before_closing_brace_in_array_initializer=do not insert 253 | org.eclipse.jdt.core.formatter.insert_new_line_before_else_in_if_statement=do not insert 254 | org.eclipse.jdt.core.formatter.insert_new_line_before_finally_in_try_statement=do not insert 255 | org.eclipse.jdt.core.formatter.insert_new_line_before_while_in_do_statement=do not insert 256 | org.eclipse.jdt.core.formatter.insert_new_line_in_empty_annotation_declaration=insert 257 | org.eclipse.jdt.core.formatter.insert_new_line_in_empty_anonymous_type_declaration=insert 258 | org.eclipse.jdt.core.formatter.insert_new_line_in_empty_block=insert 259 | org.eclipse.jdt.core.formatter.insert_new_line_in_empty_enum_constant=insert 260 | org.eclipse.jdt.core.formatter.insert_new_line_in_empty_enum_declaration=insert 261 | org.eclipse.jdt.core.formatter.insert_new_line_in_empty_method_body=insert 262 | org.eclipse.jdt.core.formatter.insert_new_line_in_empty_type_declaration=insert 263 | org.eclipse.jdt.core.formatter.insert_space_after_additive_operator=insert 264 | org.eclipse.jdt.core.formatter.insert_space_after_and_in_type_parameter=insert 265 | org.eclipse.jdt.core.formatter.insert_space_after_arrow_in_switch_case=insert 266 | org.eclipse.jdt.core.formatter.insert_space_after_arrow_in_switch_default=insert 267 | org.eclipse.jdt.core.formatter.insert_space_after_assignment_operator=insert 268 | org.eclipse.jdt.core.formatter.insert_space_after_at_in_annotation=do not insert 269 | org.eclipse.jdt.core.formatter.insert_space_after_at_in_annotation_type_declaration=do not insert 270 | org.eclipse.jdt.core.formatter.insert_space_after_bitwise_operator=insert 271 | org.eclipse.jdt.core.formatter.insert_space_after_closing_angle_bracket_in_type_arguments=do not insert 272 | org.eclipse.jdt.core.formatter.insert_space_after_closing_angle_bracket_in_type_parameters=insert 273 | org.eclipse.jdt.core.formatter.insert_space_after_closing_brace_in_block=insert 274 | org.eclipse.jdt.core.formatter.insert_space_after_closing_paren_in_cast=do not insert 275 | org.eclipse.jdt.core.formatter.insert_space_after_colon_in_assert=insert 276 | org.eclipse.jdt.core.formatter.insert_space_after_colon_in_case=insert 277 | org.eclipse.jdt.core.formatter.insert_space_after_colon_in_conditional=insert 278 | org.eclipse.jdt.core.formatter.insert_space_after_colon_in_for=insert 279 | org.eclipse.jdt.core.formatter.insert_space_after_colon_in_labeled_statement=insert 280 | org.eclipse.jdt.core.formatter.insert_space_after_comma_in_allocation_expression=insert 281 | org.eclipse.jdt.core.formatter.insert_space_after_comma_in_annotation=insert 282 | org.eclipse.jdt.core.formatter.insert_space_after_comma_in_array_initializer=insert 283 | org.eclipse.jdt.core.formatter.insert_space_after_comma_in_constructor_declaration_parameters=insert 284 | org.eclipse.jdt.core.formatter.insert_space_after_comma_in_constructor_declaration_throws=insert 285 | org.eclipse.jdt.core.formatter.insert_space_after_comma_in_enum_constant_arguments=insert 286 | org.eclipse.jdt.core.formatter.insert_space_after_comma_in_enum_declarations=insert 287 | org.eclipse.jdt.core.formatter.insert_space_after_comma_in_explicitconstructorcall_arguments=insert 288 | org.eclipse.jdt.core.formatter.insert_space_after_comma_in_for_increments=insert 289 | org.eclipse.jdt.core.formatter.insert_space_after_comma_in_for_inits=insert 290 | org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_declaration_parameters=insert 291 | org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_declaration_throws=insert 292 | org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_invocation_arguments=insert 293 | org.eclipse.jdt.core.formatter.insert_space_after_comma_in_multiple_field_declarations=insert 294 | org.eclipse.jdt.core.formatter.insert_space_after_comma_in_multiple_local_declarations=insert 295 | org.eclipse.jdt.core.formatter.insert_space_after_comma_in_parameterized_type_reference=insert 296 | org.eclipse.jdt.core.formatter.insert_space_after_comma_in_record_components=insert 297 | org.eclipse.jdt.core.formatter.insert_space_after_comma_in_superinterfaces=insert 298 | org.eclipse.jdt.core.formatter.insert_space_after_comma_in_switch_case_expressions=insert 299 | org.eclipse.jdt.core.formatter.insert_space_after_comma_in_type_arguments=insert 300 | org.eclipse.jdt.core.formatter.insert_space_after_comma_in_type_parameters=insert 301 | org.eclipse.jdt.core.formatter.insert_space_after_ellipsis=insert 302 | org.eclipse.jdt.core.formatter.insert_space_after_lambda_arrow=insert 303 | org.eclipse.jdt.core.formatter.insert_space_after_logical_operator=insert 304 | org.eclipse.jdt.core.formatter.insert_space_after_multiplicative_operator=insert 305 | org.eclipse.jdt.core.formatter.insert_space_after_not_operator=do not insert 306 | org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_parameterized_type_reference=do not insert 307 | org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_type_arguments=do not insert 308 | org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_type_parameters=do not insert 309 | org.eclipse.jdt.core.formatter.insert_space_after_opening_brace_in_array_initializer=insert 310 | org.eclipse.jdt.core.formatter.insert_space_after_opening_bracket_in_array_allocation_expression=do not insert 311 | org.eclipse.jdt.core.formatter.insert_space_after_opening_bracket_in_array_reference=do not insert 312 | org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_annotation=do not insert 313 | org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_cast=do not insert 314 | org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_catch=do not insert 315 | org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_constructor_declaration=do not insert 316 | org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_enum_constant=do not insert 317 | org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_for=do not insert 318 | org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_if=do not insert 319 | org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_method_declaration=do not insert 320 | org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_method_invocation=do not insert 321 | org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_parenthesized_expression=do not insert 322 | org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_record_declaration=do not insert 323 | org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_switch=do not insert 324 | org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_synchronized=do not insert 325 | org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_try=do not insert 326 | org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_while=do not insert 327 | org.eclipse.jdt.core.formatter.insert_space_after_postfix_operator=do not insert 328 | org.eclipse.jdt.core.formatter.insert_space_after_prefix_operator=do not insert 329 | org.eclipse.jdt.core.formatter.insert_space_after_question_in_conditional=insert 330 | org.eclipse.jdt.core.formatter.insert_space_after_question_in_wildcard=do not insert 331 | org.eclipse.jdt.core.formatter.insert_space_after_relational_operator=insert 332 | org.eclipse.jdt.core.formatter.insert_space_after_semicolon_in_for=insert 333 | org.eclipse.jdt.core.formatter.insert_space_after_semicolon_in_try_resources=insert 334 | org.eclipse.jdt.core.formatter.insert_space_after_shift_operator=insert 335 | org.eclipse.jdt.core.formatter.insert_space_after_string_concatenation=insert 336 | org.eclipse.jdt.core.formatter.insert_space_after_unary_operator=do not insert 337 | org.eclipse.jdt.core.formatter.insert_space_before_additive_operator=insert 338 | org.eclipse.jdt.core.formatter.insert_space_before_and_in_type_parameter=insert 339 | org.eclipse.jdt.core.formatter.insert_space_before_arrow_in_switch_case=insert 340 | org.eclipse.jdt.core.formatter.insert_space_before_arrow_in_switch_default=insert 341 | org.eclipse.jdt.core.formatter.insert_space_before_assignment_operator=insert 342 | org.eclipse.jdt.core.formatter.insert_space_before_at_in_annotation_type_declaration=insert 343 | org.eclipse.jdt.core.formatter.insert_space_before_bitwise_operator=insert 344 | org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_parameterized_type_reference=do not insert 345 | org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_type_arguments=do not insert 346 | org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_type_parameters=do not insert 347 | org.eclipse.jdt.core.formatter.insert_space_before_closing_brace_in_array_initializer=insert 348 | org.eclipse.jdt.core.formatter.insert_space_before_closing_bracket_in_array_allocation_expression=do not insert 349 | org.eclipse.jdt.core.formatter.insert_space_before_closing_bracket_in_array_reference=do not insert 350 | org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_annotation=do not insert 351 | org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_cast=do not insert 352 | org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_catch=do not insert 353 | org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_constructor_declaration=do not insert 354 | org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_enum_constant=do not insert 355 | org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_for=do not insert 356 | org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_if=do not insert 357 | org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_method_declaration=do not insert 358 | org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_method_invocation=do not insert 359 | org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_parenthesized_expression=do not insert 360 | org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_record_declaration=do not insert 361 | org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_switch=do not insert 362 | org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_synchronized=do not insert 363 | org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_try=do not insert 364 | org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_while=do not insert 365 | org.eclipse.jdt.core.formatter.insert_space_before_colon_in_assert=insert 366 | org.eclipse.jdt.core.formatter.insert_space_before_colon_in_case=do not insert 367 | org.eclipse.jdt.core.formatter.insert_space_before_colon_in_conditional=insert 368 | org.eclipse.jdt.core.formatter.insert_space_before_colon_in_default=do not insert 369 | org.eclipse.jdt.core.formatter.insert_space_before_colon_in_for=insert 370 | org.eclipse.jdt.core.formatter.insert_space_before_colon_in_labeled_statement=do not insert 371 | org.eclipse.jdt.core.formatter.insert_space_before_comma_in_allocation_expression=do not insert 372 | org.eclipse.jdt.core.formatter.insert_space_before_comma_in_annotation=do not insert 373 | org.eclipse.jdt.core.formatter.insert_space_before_comma_in_array_initializer=do not insert 374 | org.eclipse.jdt.core.formatter.insert_space_before_comma_in_constructor_declaration_parameters=do not insert 375 | org.eclipse.jdt.core.formatter.insert_space_before_comma_in_constructor_declaration_throws=do not insert 376 | org.eclipse.jdt.core.formatter.insert_space_before_comma_in_enum_constant_arguments=do not insert 377 | org.eclipse.jdt.core.formatter.insert_space_before_comma_in_enum_declarations=do not insert 378 | org.eclipse.jdt.core.formatter.insert_space_before_comma_in_explicitconstructorcall_arguments=do not insert 379 | org.eclipse.jdt.core.formatter.insert_space_before_comma_in_for_increments=do not insert 380 | org.eclipse.jdt.core.formatter.insert_space_before_comma_in_for_inits=do not insert 381 | org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_declaration_parameters=do not insert 382 | org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_declaration_throws=do not insert 383 | org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_invocation_arguments=do not insert 384 | org.eclipse.jdt.core.formatter.insert_space_before_comma_in_multiple_field_declarations=do not insert 385 | org.eclipse.jdt.core.formatter.insert_space_before_comma_in_multiple_local_declarations=do not insert 386 | org.eclipse.jdt.core.formatter.insert_space_before_comma_in_parameterized_type_reference=do not insert 387 | org.eclipse.jdt.core.formatter.insert_space_before_comma_in_record_components=do not insert 388 | org.eclipse.jdt.core.formatter.insert_space_before_comma_in_superinterfaces=do not insert 389 | org.eclipse.jdt.core.formatter.insert_space_before_comma_in_switch_case_expressions=do not insert 390 | org.eclipse.jdt.core.formatter.insert_space_before_comma_in_type_arguments=do not insert 391 | org.eclipse.jdt.core.formatter.insert_space_before_comma_in_type_parameters=do not insert 392 | org.eclipse.jdt.core.formatter.insert_space_before_ellipsis=do not insert 393 | org.eclipse.jdt.core.formatter.insert_space_before_lambda_arrow=insert 394 | org.eclipse.jdt.core.formatter.insert_space_before_logical_operator=insert 395 | org.eclipse.jdt.core.formatter.insert_space_before_multiplicative_operator=insert 396 | org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_parameterized_type_reference=do not insert 397 | org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_type_arguments=do not insert 398 | org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_type_parameters=do not insert 399 | org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_annotation_type_declaration=insert 400 | org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_anonymous_type_declaration=insert 401 | org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_array_initializer=insert 402 | org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_block=insert 403 | org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_constructor_declaration=insert 404 | org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_enum_constant=insert 405 | org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_enum_declaration=insert 406 | org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_method_declaration=insert 407 | org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_record_constructor=insert 408 | org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_record_declaration=insert 409 | org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_switch=insert 410 | org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_type_declaration=insert 411 | org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_allocation_expression=do not insert 412 | org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_reference=do not insert 413 | org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_type_reference=do not insert 414 | org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_annotation=do not insert 415 | org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_annotation_type_member_declaration=do not insert 416 | org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_catch=insert 417 | org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_constructor_declaration=do not insert 418 | org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_enum_constant=do not insert 419 | org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_for=insert 420 | org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_if=insert 421 | org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_method_declaration=do not insert 422 | org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_method_invocation=do not insert 423 | org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_parenthesized_expression=do not insert 424 | org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_record_declaration=do not insert 425 | org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_switch=insert 426 | org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_synchronized=insert 427 | org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_try=insert 428 | org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_while=insert 429 | org.eclipse.jdt.core.formatter.insert_space_before_parenthesized_expression_in_return=insert 430 | org.eclipse.jdt.core.formatter.insert_space_before_parenthesized_expression_in_throw=insert 431 | org.eclipse.jdt.core.formatter.insert_space_before_postfix_operator=do not insert 432 | org.eclipse.jdt.core.formatter.insert_space_before_prefix_operator=do not insert 433 | org.eclipse.jdt.core.formatter.insert_space_before_question_in_conditional=insert 434 | org.eclipse.jdt.core.formatter.insert_space_before_question_in_wildcard=do not insert 435 | org.eclipse.jdt.core.formatter.insert_space_before_relational_operator=insert 436 | org.eclipse.jdt.core.formatter.insert_space_before_semicolon=do not insert 437 | org.eclipse.jdt.core.formatter.insert_space_before_semicolon_in_for=do not insert 438 | org.eclipse.jdt.core.formatter.insert_space_before_semicolon_in_try_resources=do not insert 439 | org.eclipse.jdt.core.formatter.insert_space_before_shift_operator=insert 440 | org.eclipse.jdt.core.formatter.insert_space_before_string_concatenation=insert 441 | org.eclipse.jdt.core.formatter.insert_space_before_unary_operator=do not insert 442 | org.eclipse.jdt.core.formatter.insert_space_between_brackets_in_array_type_reference=do not insert 443 | org.eclipse.jdt.core.formatter.insert_space_between_empty_braces_in_array_initializer=do not insert 444 | org.eclipse.jdt.core.formatter.insert_space_between_empty_brackets_in_array_allocation_expression=do not insert 445 | org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_annotation_type_member_declaration=do not insert 446 | org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_constructor_declaration=do not insert 447 | org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_enum_constant=do not insert 448 | org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_method_declaration=do not insert 449 | org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_method_invocation=do not insert 450 | org.eclipse.jdt.core.formatter.join_lines_in_comments=false 451 | org.eclipse.jdt.core.formatter.join_wrapped_lines=false 452 | org.eclipse.jdt.core.formatter.keep_annotation_declaration_on_one_line=one_line_never 453 | org.eclipse.jdt.core.formatter.keep_anonymous_type_declaration_on_one_line=one_line_never 454 | org.eclipse.jdt.core.formatter.keep_code_block_on_one_line=one_line_never 455 | org.eclipse.jdt.core.formatter.keep_else_statement_on_same_line=false 456 | org.eclipse.jdt.core.formatter.keep_empty_array_initializer_on_one_line=false 457 | org.eclipse.jdt.core.formatter.keep_enum_constant_declaration_on_one_line=one_line_never 458 | org.eclipse.jdt.core.formatter.keep_enum_declaration_on_one_line=one_line_never 459 | org.eclipse.jdt.core.formatter.keep_if_then_body_block_on_one_line=one_line_never 460 | org.eclipse.jdt.core.formatter.keep_imple_if_on_one_line=false 461 | org.eclipse.jdt.core.formatter.keep_lambda_body_block_on_one_line=one_line_never 462 | org.eclipse.jdt.core.formatter.keep_loop_body_block_on_one_line=one_line_never 463 | org.eclipse.jdt.core.formatter.keep_method_body_on_one_line=one_line_never 464 | org.eclipse.jdt.core.formatter.keep_record_constructor_on_one_line=one_line_never 465 | org.eclipse.jdt.core.formatter.keep_record_declaration_on_one_line=one_line_never 466 | org.eclipse.jdt.core.formatter.keep_simple_do_while_body_on_same_line=false 467 | org.eclipse.jdt.core.formatter.keep_simple_for_body_on_same_line=false 468 | org.eclipse.jdt.core.formatter.keep_simple_getter_setter_on_one_line=false 469 | org.eclipse.jdt.core.formatter.keep_simple_while_body_on_same_line=false 470 | org.eclipse.jdt.core.formatter.keep_then_statement_on_same_line=false 471 | org.eclipse.jdt.core.formatter.keep_type_declaration_on_one_line=one_line_never 472 | org.eclipse.jdt.core.formatter.lineSplit=120 473 | org.eclipse.jdt.core.formatter.never_indent_block_comments_on_first_column=true 474 | org.eclipse.jdt.core.formatter.never_indent_line_comments_on_first_column=true 475 | org.eclipse.jdt.core.formatter.number_of_blank_lines_after_code_block=0 476 | org.eclipse.jdt.core.formatter.number_of_blank_lines_at_beginning_of_code_block=0 477 | org.eclipse.jdt.core.formatter.number_of_blank_lines_at_beginning_of_method_body=0 478 | org.eclipse.jdt.core.formatter.number_of_blank_lines_at_end_of_code_block=0 479 | org.eclipse.jdt.core.formatter.number_of_blank_lines_at_end_of_method_body=0 480 | org.eclipse.jdt.core.formatter.number_of_blank_lines_before_code_block=0 481 | org.eclipse.jdt.core.formatter.number_of_empty_lines_to_preserve=1 482 | org.eclipse.jdt.core.formatter.parentheses_positions_in_annotation=common_lines 483 | org.eclipse.jdt.core.formatter.parentheses_positions_in_catch_clause=common_lines 484 | org.eclipse.jdt.core.formatter.parentheses_positions_in_enum_constant_declaration=common_lines 485 | org.eclipse.jdt.core.formatter.parentheses_positions_in_for_statment=common_lines 486 | org.eclipse.jdt.core.formatter.parentheses_positions_in_if_while_statement=common_lines 487 | org.eclipse.jdt.core.formatter.parentheses_positions_in_lambda_declaration=common_lines 488 | org.eclipse.jdt.core.formatter.parentheses_positions_in_method_delcaration=common_lines 489 | org.eclipse.jdt.core.formatter.parentheses_positions_in_method_invocation=common_lines 490 | org.eclipse.jdt.core.formatter.parentheses_positions_in_record_declaration=common_lines 491 | org.eclipse.jdt.core.formatter.parentheses_positions_in_switch_statement=common_lines 492 | org.eclipse.jdt.core.formatter.parentheses_positions_in_try_clause=common_lines 493 | org.eclipse.jdt.core.formatter.put_empty_statement_on_new_line=true 494 | org.eclipse.jdt.core.formatter.tabulation.char=tab 495 | org.eclipse.jdt.core.formatter.tabulation.size=4 496 | org.eclipse.jdt.core.formatter.text_block_indentation=0 497 | org.eclipse.jdt.core.formatter.use_on_off_tags=true 498 | org.eclipse.jdt.core.formatter.use_tabs_only_for_leading_indentations=false 499 | org.eclipse.jdt.core.formatter.wrap_before_additive_operator=true 500 | org.eclipse.jdt.core.formatter.wrap_before_assignment_operator=false 501 | org.eclipse.jdt.core.formatter.wrap_before_bitwise_operator=true 502 | org.eclipse.jdt.core.formatter.wrap_before_conditional_operator=true 503 | org.eclipse.jdt.core.formatter.wrap_before_logical_operator=true 504 | org.eclipse.jdt.core.formatter.wrap_before_multiplicative_operator=true 505 | org.eclipse.jdt.core.formatter.wrap_before_or_operator_multicatch=true 506 | org.eclipse.jdt.core.formatter.wrap_before_relational_operator=true 507 | org.eclipse.jdt.core.formatter.wrap_before_shift_operator=true 508 | org.eclipse.jdt.core.formatter.wrap_before_string_concatenation=true 509 | org.eclipse.jdt.core.formatter.wrap_outer_expressions_when_nested=true 510 | org.eclipse.jdt.core.javaFormatter=org.eclipse.jdt.core.defaultJavaFormatter 511 | -------------------------------------------------------------------------------- /test/jason/Wast.java: -------------------------------------------------------------------------------- 1 | package jason; 2 | 3 | import java.math.BigInteger; 4 | import java.nio.charset.StandardCharsets; 5 | import java.util.concurrent.ThreadLocalRandom; 6 | 7 | //ref: https://github.com/wycst/wast/blob/main/src/main/java/io/github/wycst/wast/common/utils/NumberUtils.java 8 | public final class Wast { 9 | private static final class ED5 { 10 | static final ED5[] ED5_A = new ED5[343]; 11 | 12 | static { 13 | final long[][] ed5datas = { 14 | {0x4000000000000000L, 0, -62, 0x8000000000000000L, 31, 0}, 15 | {0x5000000000000000L, 0, -60, 0x6666666666666666L, 33, 1717986918}, 16 | {0x6400000000000000L, 0, -58, 0x51eb851eb851eb85L, 35, 515396075}, 17 | {0x7d00000000000000L, 0, -56, 0x4189374bc6a7ef9dL, 37, -1305670058}, 18 | {0x4e20000000000000L, 0, -53, 0x68db8bac710cb295L, 40, -371085175}, 19 | {0x61a8000000000000L, 0, -51, 0x53e2d6238da3c211L, 42, -2014855058}, 20 | {0x7a12000000000000L, 0, -49, 0x431bde82d7b634daL, 44, -752890588}, 21 | {0x4c4b400000000000L, 0, -46, 0x6b5fca6af2bd215eL, 47, 513361979}, 22 | {0x5f5e100000000000L, 0, -44, 0x55e63b88c230e77eL, 49, 2128676501}, 23 | {0x7735940000000000L, 0, -42, 0x44b82fa09b5a52cbL, 51, -1733032636}, 24 | {0x4a817c8000000000L, 0, -39, 0x6df37f675ef6eadfL, 54, 1522115079}, 25 | {0x5d21dba000000000L, 0, -37, 0x57f5ff85e592557fL, 56, 2076685522}, 26 | {0x746a528800000000L, 0, -35, 0x465e6604b7a84465L, 58, -56638501}, 27 | {0x48c2739500000000L, 0, -32, 0x709709a125da0709L, 61, -1808608519}, 28 | {0x5af3107a40000000L, 0, -30, 0x5a126e1a84ae6c07L, 63, -1446886816}, 29 | {0x71afd498d0000000L, 0, -28, 0x480ebe7b9d58566cL, 65, -2016502912}, 30 | {0x470de4df82000000L, 0, -25, 0x734aca5f6226f0adL, 68, -1508417740}, 31 | {0x58d15e1762800000L, 0, -23, 0x5c3bd5191b525a24L, 70, -2065727652}, 32 | {0x6f05b59d3b200000L, 0, -21, 0x49c97747490eae83L, 72, -1652582121}, 33 | {0x4563918244f40000L, 0, -18, 0x760f253edb4ab0d2L, 75, -1785137935}, 34 | {0x56bc75e2d6310000L, 0, -16, 0x5e72843249088d75L, 77, 1148870030}, 35 | {0x6c6b935b8bbd4000L, 0, -14, 0x4b8ed0283a6d3df7L, 79, 1778089483}, 36 | {0x43c33c1937564800L, 0, -11, 0x78e480405d7b9658L, 82, -1450024123}, 37 | {0x54b40b1f852bda00L, 0, -9, 0x60b6cd004ac94513L, 84, -1160019298}, 38 | {0x69e10de76676d080L, 0, -7, 0x4d5f0a66a23a9da9L, 86, 1648964939}, 39 | {0x422ca8b0a00a4250L, 0, -4, 0x7bcb43d769f762a8L, 89, -1656623394}, 40 | {0x52b7d2dcc80cd2e4L, 0, -2, 0x63090312bb2c4eedL, 91, 1251681663}, 41 | {0x6765c793fa10079dL, 0, 0, 0x4f3a68dbc8f03f24L, 93, 1001345330}, 42 | {0x409f9cbc7c4a04c2L, 0x20000000L, 3, 0x7ec3daf941806506L, 96, -974827849}, 43 | {0x50c783eb9b5c85f2L, -1476395008, 5, 0x65697bfa9acd1d9fL, 98, 79131180}, 44 | {0x64f964e68233a76fL, 0x52000000L, 7, 0x51212ffbaf0a7e18L, 100, -795688516}, 45 | {0x7e37be2022c0914bL, 0x26800000L, 9, 0x40e7599625a1fe7aL, 102, 1081436106}, 46 | {0x4ee2d6d415b85aceL, -133169152, 12, 0x67d88f56a29cca5dL, 105, 871304310}, 47 | {0x629b8c891b267182L, -1240203264, 14, 0x5313a5dee87d6eb0L, 107, -161950011}, 48 | {0x7b426fab61f00de3L, 0x63990000L, 16, 0x42761e4bed31255aL, 109, 1588426909}, 49 | {0x4d0985cb1d3608aeL, 0x1e3fa000L, 19, 0x6a5696dfe1e83bc3L, 112, -894490781}, 50 | {0x604be73de4838ad9L, -1513125888, 21, 0x5512124cb4b9c969L, 114, 1861387752}, 51 | {0x785ee10d5da46d90L, 0xf436a00L, 23, 0x440e750a2a2e3abaL, 116, -1087870176}, 52 | {0x4b3b4ca85a86c47aL, 0x98a2240L, 26, 0x6ce3ee76a9e3912aL, 119, -881598822}, 53 | {0x5e0a1fd271287598L, -1947424048, 28, 0x571cbec554b60dbbL, 121, -705279057}, 54 | {0x758ca7c70d7292feL, -1360538236, 30, 0x45b0989ddd5e7163L, 123, 294770213}, 55 | {0x4977e8dc68679bdfL, 0x2d50e572L, 33, 0x6f80f42fc8971bd1L, 126, -1246354577}, 56 | {0x5bd5e313828182d6L, -123396401, 35, 0x5933f68ca078e30eL, 128, 720903257}, 57 | {0x72cb5bd86321e38cL, -1227987326, 37, 0x475cc53d4d2d8271L, 130, -1141264313}, 58 | {0x47bf19673df52e37L, -230621167, 40, 0x722e086215159d82L, 133, -967029442}, 59 | {0x59aedfc10d7279c5L, -288276458, 42, 0x5b5806b4ddaae468L, 135, -1632617013}, 60 | {0x701a97b150cf1837L, 0x6a85901bL, 44, 0x49133890b1558386L, 137, -447100151}, 61 | {0x46109eced2816f22L, -1567393263, 47, 0x74eb8db44eef38d7L, 140, -715360241}, 62 | {0x5794c6828721caebL, 0x4b385895L, 49, 0x5d893e29d8bf60acL, 142, -1431281652}, 63 | {0x6d79f82328ea3da6L, 0x1e066ebbL, 51, 0x4ad431bb13cc4d56L, 144, -286031863}, 64 | {0x446c3b15f9926687L, -758905548, 54, 0x77b9e92b52e07bbeL, 147, 1260335938}, 65 | {0x558749db77f70029L, -948631934, 56, 0x5fc7edbc424d2fcbL, 149, 1867262210}, 66 | {0x6ae91c5255f4c034L, 0x39524822L, 58, 0x4c9ff163683dbfd5L, 151, -224177151}, 67 | {0x42d1b1b375b8f820L, -1546425067, 61, 0x7a998238a6c932efL, 154, -358683441}, 68 | {0x53861e2053273628L, -859289509, 63, 0x6214682d523a8f26L, 156, 1431040166}, 69 | {0x6867a5a867f103b2L, 0xfffa5a71L, 65, 0x4e76b9bddb620c1eL, 158, -1432148245}, 70 | {0x4140c78940f6a24fL, -537102201, 68, 0x7d8ac2c95f034697L, 161, 2003530104}, 71 | {0x5190f96b91344ae3L, -671377751, 70, 0x646f023ab2690545L, 163, -115162835}, 72 | {0x65f537c675815d9cL, -839222189, 72, 0x5058ce955b87376bL, 165, 766863191}, 73 | {0x7f7285b812e1b504L, 0x1791b68L, 74, 0x40470baaaf9f5f88L, 167, -245502907}, 74 | {0x4fa793930bcd1122L, -2132037343, 77, 0x66d812aab29898dbL, 170, 466188809}, 75 | {0x63917877cec0556bL, 0x21269d69L, 79, 0x524675555bad4715L, 172, -1345035871}, 76 | {0x7c75d695c2706ac5L, -378518333, 81, 0x41d1f7777c8a9f44L, 174, -1935022156}, 77 | {0x4dc9a61d998642bbL, -1310315782, 84, 0x694ff258c7443207L, 177, 1198931846}, 78 | {0x613c0fa4ffe7d36aL, -1637894728, 86, 0x543ff513d29cf4d2L, 179, -1617834901}, 79 | {0x798b138e3fe1c845L, 0x45f7a327L, 88, 0x43665da9754a5d75L, 181, 1282712457}, 80 | {0x4bf6ec38e7ed1d2bL, 0x4bbac5f8L, 91, 0x6bd6fc425543c8bbL, 184, -1383633906}, 81 | {0x5ef4a74721e86476L, 0x1ea97776L, 93, 0x5645969b77696d62L, 186, -247913665}, 82 | {0x76b1d118ea627d93L, -1504455340, 95, 0x4504787c5f878ab5L, 188, -1916317851}, 83 | {0x4a2f22af927d8e7cL, 0x47f46554L, 98, 0x6e6d8d93cc0c1122L, 191, 2087852194}, 84 | {0x5cbaeb5b771cf21bL, 0x59f17ea9L, 100, 0x5857a4763cd6741bL, 193, -1765692082}, 85 | {0x73e9a63254e42ea2L, 0x306dde54L, 102, 0x46ac8391ca4529afL, 195, -1412553665}, 86 | {0x487207df750e9d25L, 0x5e44aaf4L, 105, 0x711405b6106ea919L, 198, 316894513}, 87 | {0x5a8e89d75252446eL, -1244277327, 107, 0x5a766af80d255414L, 200, 253515611}, 88 | {0x71322c4d26e6d58aL, 0x634b4b1eL, 109, 0x485ebbf9a41ddcdcL, 202, -656180971}, 89 | {0x46bf5bb038504576L, 0x7e0f0ef2L, 112, 0x73cac65c39c96161L, 205, 1527090825}, 90 | {0x586f329c466456d4L, 0x1d92d2afL, 114, 0x5ca23849c7d44de7L, 207, 2080666119}, 91 | {0x6e8aff4357fd6c89L, 0x24f7875bL, 116, 0x4a1b603b06437185L, 209, -53454023}, 92 | {0x4516df8a16fe63d5L, -1222986599, 119, 0x76923391a39f1c09L, 212, -1803513356}, 93 | {0x565c976c9cbdfccbL, 0x24e161bfL, 121, 0x5edb5c7482e5b007L, 214, -1442810685}, 94 | {0x6bf3bd47c3ed7bfdL, -300303825, 123, 0x4be2b05d35848cd2L, 216, -295255089}, 95 | {0x4378564cda746d7eL, -1261431715, 126, 0x796ab3c855a0e151L, 219, 2104572236}, 96 | {0x54566be0111188deL, 0x62041975L, 128, 0x6122296d114d810dL, 221, -34329130}, 97 | {0x696c06d81555eb15L, -91938862, 130, 0x4db4edf0daa4673eL, 223, 1690523615}, 98 | {0x41e384470d55b2edL, -1131203613, 133, 0x7c54afe7c43a3ecaL, 226, 986850865}, 99 | {0x525c6558d0ab1fa9L, 0x2bb800dcL, 135, 0x6376f31fd02e98a1L, 228, -928506226}, 100 | {0x66f37eaf04d5e793L, 0x76a60113L, 137, 0x4f925c1973587a1bL, 230, 116188478}, 101 | {0x40582f2d6305b0bcL, 0x2a27c0acL, 140, 0x7f50935bebc0c35eL, 233, 1903888484}, 102 | {0x506e3af8bbc71cebL, 0x34b1b0d7L, 142, 0x65da0f7cbc9a35e5L, 235, 664117328}, 103 | {0x6489c9b6eab8e426L, 0x1de1d0cL, 144, 0x517b3f96fd482b1dL, 237, -1186693056}, 104 | {0x7dac3c24a5671d2fL, -2108316592, 146, 0x412f66126439bc17L, 239, -949354445}, 105 | {0x4e8ba596e760723dL, -1317697870, 149, 0x684bd683d38f9359L, 242, 1058013266}, 106 | {0x622e8efca1388ecdL, 0x1dd2e85eL, 151, 0x536fdecfdc72dc47L, 244, 1705404072}, 107 | {0x7aba32bbc986b280L, 0x6547a276L, 153, 0x42bfe57316c249d2L, 246, -1212657120}, 108 | {0x4cb45fb55df42f90L, 0x3f4cc589L, 156, 0x6acca251be03a951L, 249, 636728985}, 109 | {0x5fe177a2b5713b74L, 0x4f1ff6ecL, 158, 0x557081dafe695440L, 251, -349610271}, 110 | {0x77d9d58b62cd8a51L, 0x62e7f4a7L, 160, 0x445a017bfebaa9cdL, 253, -1997675135}, 111 | {0x4ae825771dc07672L, -573507352, 163, 0x6d5ccf2ccac442e2L, 256, 1957680539}, 112 | {0x5da22ed4e530940fL, -1790626014, 165, 0x577d728a3bd03581L, 258, -151842487}, 113 | {0x750aba8a1e7cb913L, 0x7a9684ebL, 167, 0x45fdf53b630cf79bL, 260, 737519469}, 114 | {0x4926b496530df3acL, 0x2c9e1313L, 170, 0x6ffcbb923814bf5eL, 263, -1396949227}, 115 | {0x5b7061bbe7d17097L, 0x37c597d8L, 172, 0x5996fc74f9aa32b2L, 265, 600427537}, 116 | {0x724c7a2ae1c5ccbdL, 0x5b6fdceL, 174, 0x47abfd2a6154f55bL, 267, 1339335489}, 117 | {0x476fcc5acd1b9ff6L, 0x23925ea0L, 177, 0x72acc843ceee555eL, 270, -434043595}, 118 | {0x594bbf71806287f3L, -1401489848, 179, 0x5bbd6d030bf1dde5L, 272, -2065221795}, 119 | {0x6f9eaf4de07b29f0L, -1751862309, 181, 0x49645735a327e4b7L, 274, -1652177436}, 120 | {0x45c32d90ac4cfa36L, 0x5ebcf069L, 184, 0x756d5855d1d96df2L, 277, -1784490438}, 121 | {0x5733f8f4d76038c3L, -160682877, 186, 0x5df11377db1457f5L, 279, 1149388027}, 122 | {0x6d00f7320d3846f4L, -200853596, 188, 0x4b2742c648dd132aL, 281, -1657469956}, 123 | {0x44209a7f48432c59L, 0x188482c6L, 191, 0x783ed13d4161b844L, 284, 784021907}, 124 | {0x5528c11f1a53f76fL, 0x5ea5a378L, 193, 0x603240fdcde7c69cL, 286, -231775933}, 125 | {0x6a72f166e0e8f54bL, 0x364f0c56L, 195, 0x4cf500cb0b1fd217L, 288, 673572712}, 126 | {0x4287d6e04c91994fL, 0x1f167b5L, 198, 0x7b219ade7832e9beL, 291, -1499264038}, 127 | {0x5329cc985fb5ffa2L, -1032994397, 200, 0x628148b1f9c25498L, 293, -2058404689}, 128 | {0x67f43fbe77a37f8bL, 0x7309320cL, 202, 0x4ecdd3c1949b76e0L, 295, 1789250085}, 129 | {0x40f8a7d70ac62fb7L, 0x27e5bf47L, 205, 0x7e161f9c20f8be33L, 298, -573173700}, 130 | {0x5136d1cccd77bba4L, -237031655, 207, 0x64de7fb01a609829L, 300, 2118441417}, 131 | {0x6584864000d5aa8eL, 0x2e56fadfL, 209, 0x50b1ffc0151a1354L, 302, 1694753134}, 132 | {0x7ee5a7d0010b1531L, -1175668329, 211, 0x408e66334414dc43L, 304, -2080171330}, 133 | {0x4f4f88e200a6ed3fL, 0x1433f3feL, 214, 0x674a3d1ed354939fL, 307, 966693169}, 134 | {0x63236b1a80d0a88eL, -650055426, 216, 0x52a1ca7f0f76dc7fL, 309, 1632347994}, 135 | {0x7bec45e12104d2b2L, -1886311106, 218, 0x421b0865a5f8b065L, 311, -412108523}, 136 | {0x4d73abacb4a303afL, -1715815354, 221, 0x69c4da3c3cc11a3cL, 314, -1518367096}, 137 | {0x60d09697e1cbc49bL, -2144769192, 223, 0x549d7b6363cdae96L, 316, -355700218}, 138 | {0x7904bc3dda3eb5c2L, 0x6033c62eL, 225, 0x43b12f82b63e2545L, 318, -2002547093}, 139 | {0x4ba2f5a6a8673199L, 0x7c205bddL, 228, 0x6c4eb26abd303ba2L, 321, 1949885407}, 140 | {0x5e8bb3105280fdffL, -618106156, 230, 0x56a55b889759c94eL, 323, -1017072052}, 141 | {0x762e9fd467213d7fL, -772632695, 232, 0x45511606df7b0772L, 325, 904329277}, 142 | {0x49dd23e4c074c66fL, -482895434, 235, 0x6ee8233e325e7250L, 328, 1446926843}, 143 | {0x5c546cddf091f80bL, -603619293, 237, 0x58b9b5cb5b7ec1d9L, 330, -560445444}, 144 | {0x736988156cb6760eL, -754524116, 239, 0x46faf7d5e2cbce47L, 332, -448356355}, 145 | {0x4821f50d63f209c9L, 0x43e44c1bL, 242, 0x71918c896adfb073L, 335, 141623291}, 146 | {0x5a2a7250bcee8c3bL, -1797431518, 244, 0x5adad6d4557fc05cL, 337, 113298633}, 147 | {0x70b50ee4ec2a2f4aL, 0x7a14b6ebL, 246, 0x48af1243779966b0L, 339, 90638906}, 148 | {0x4671294f139a5d8eL, -1941114285, 249, 0x744b506bf28f0ab3L, 342, 1004015709}, 149 | {0x580d73a2d880f4f2L, 0x2f602ee7L, 251, 0x5d090d2328726ef5L, 344, -914774351}, 150 | {0x6e10d08b8ea1322eL, -1153942879, 253, 0x4a6da41c205b8bf7L, 346, -731819481}, 151 | {0x44ca82573924bf5dL, 0x350324a5L, 256, 0x7715d36033c5acbfL, 349, -1170911170}, 152 | {0x55fd22ed076def34L, -2109477426, 258, 0x5f44a919c3048a32L, 351, -77735477}, 153 | {0x6b7c6ba849496b01L, -1563104958, 260, 0x4c36edae359d3b5bL, 353, -62188381}, 154 | {0x432dc3492dcde2e1L, 0x5c511c9L, 263, 0x79f17c49ef61f893L, 356, 759492049}, 155 | {0x53f9341b79415b99L, 0x4736563bL, 265, 0x618dfd07f2b4c6dcL, 358, 607593639}, 156 | {0x68f781225791b27fL, -1727796278, 267, 0x4e0b30d328909f16L, 360, -2090905466}, 157 | {0x419ab0b576bb0f8fL, -1079872674, 270, 0x7cdeb4850db431bdL, 363, -1627461827}, 158 | {0x52015ce2d469d373L, -1349840842, 272, 0x63e55d373e29c164L, 365, 2134004375}, 159 | {0x6681b41b89844850L, -1687301053, 274, 0x4feab0f8fe87cde9L, 367, -10783419}, 160 | {0x4011109135f2ad32L, 0x6124a4aaL, 277, 0x7fdde7f4ca72e30fL, 370, -17253469}, 161 | {0x501554b5836f587eL, -110244395, 279, 0x664b1ff7085be8d9L, 372, -1731789694}, 162 | {0x641aa9e2e44b2e9eL, -1211547318, 281, 0x51d5b32c06afed7aL, 374, -526438296}, 163 | {0x7d21545b9d5dfa46L, 0x65bb919cL, 283, 0x4177c2899ef32462L, 376, 1296836281}, 164 | {0x4e34d4b9425abc6bL, -6997246, 286, 0x68bf9da8fe51d3d0L, 379, 2074938051}, 165 | {0x61c209e792f16b86L, -8746558, 288, 0x53cc7e20cb74a973L, 381, -1776023396}, 166 | {0x7a328c6177adc668L, -1084675021, 290, 0x4309fe80a2c3bac2L, 383, -561825258}, 167 | {0x4c5f97bceacc9c01L, 0x7797bb9fL, 293, 0x6b4330cdd1392ad1L, 386, 1678059965}, 168 | {0x5f777dac257fc301L, -713184633, 295, 0x55cf5a3e40fa88a7L, 388, -2093525865}, 169 | {0x77555d172edfb3c2L, 0x4add1529L, 297, 0x44a5e1cb672ed3b9L, 390, 902159686}, 170 | {0x4a955a2e7d4bd059L, 0x6eca2d3aL, 300, 0x6dd636123eb152c1L, 393, -274531421}, 171 | {0x5d3ab0ba1c9ec46fL, -897795960, 302, 0x57de91a832277567L, 395, -219625137}, 172 | {0x74895ce8a3c6758bL, -1122244949, 304, 0x464ba7b9c1b92ab9L, 397, -1893687028}, 173 | {0x48d5da11665c0977L, 0x5631702aL, 307, 0x70790c5c6928445cL, 400, 406074592}, 174 | {0x5b0b5095bff30bd5L, 0x2bbdcc35L, 309, 0x59fa7049edb9d049L, 402, -1393127245}, 175 | {0x71ce24bb2fefcecaL, 0x76ad3f42L, 311, 0x47fb8d07f161736eL, 404, 603485122}, 176 | {0x4720d6f4fdf5e13eL, -1976809591, 314, 0x732c14d98235857dL, 407, 106582737}, 177 | {0x58e90cb23d73598eL, 0x2cb7596cL, 316, 0x5c2343e134f79dfdL, 409, -1632720729}, 178 | {0x6f234fdeccd02ff1L, -1209716793, 318, 0x49b5cfe75d92e4caL, 411, -447183124}, 179 | {0x457611eb40021df7L, 0x12ef3ddcL, 321, 0x75efb30bc8eb07abL, 414, 143500461}, 180 | {0x56d396661002a574L, -676655789, 323, 0x5e595c096d88d2efL, 416, 973793828}, 181 | {0x6c887bff94034ed2L, 0xd95d0a8L, 325, 0x4b7ab0078ad3dbf2L, 418, -1797945315}, 182 | {0x43d54d7fbc821143L, 0x487da269L, 328, 0x78c44cd8de1fc650L, 421, -299732127}, 183 | {0x54caa0dfaba29594L, 0x1a9d0b03L, 330, 0x609d0a4718196b73L, 423, -239785701}, 184 | {0x69fd4917968b3af9L, 0x21444dc4L, 332, 0x4d4a6e9f467abc5cL, 425, -1050822020}, 185 | {0x423e4daebe1704dbL, -1261784934, 335, 0x7baa4a9870c46094L, 428, 1754658604}, 186 | {0x52cde11a6d9cc612L, -1577231167, 337, 0x62eea2138d69e6ddL, 430, 544733424}, 187 | {0x678159610903f797L, 0x4a7cb3f2L, 339, 0x4f254e760abb1f17L, 432, 1294780199}, 188 | {0x40b0d7dca5a27abeL, -1903300489, 342, 0x7ea21723445e9825L, 435, 1212654859}, 189 | {0x50dd0dd3cf0b196eL, 0x32316c95L, 344, 0x654e78e9037ee01dL, 437, -747863032}, 190 | {0x65145148c2cddfc9L, -1094858822, 346, 0x510b93ed9c658017L, 439, -598290425}, 191 | {0x7e59659af38157bcL, 0x2e6d39a9L, 348, 0x40d60ff149eaccdfL, 441, -478632340}, 192 | {0x4ef7df80d830d6d5L, -1660664823, 351, 0x67bce64edcaae166L, 444, 952175174}, 193 | {0x62b5d7610e3d0c8bL, 0x445550cL, 353, 0x52fd850be3bbe784L, 446, -97253320}, 194 | {0x7b634d3951cc4fadL, -984176049, 355, 0x42646a6fe9631f9dL, 448, -1795789574}, 195 | {0x4d1e1043d31fb1ccL, -1688851855, 358, 0x6a3a43e642383295L, 451, -1155276400}, 196 | {0x60659454c7e79e3fL, -1037322995, 360, 0x54fb698501c68edeL, 453, 793765798}, 197 | {0x787ef969f9e185cfL, -1296653743, 362, 0x43fc546a67d20be4L, 455, -223980821}, 198 | {0x4b4f5be23c2cf3a1L, -810408590, 365, 0x6cc6ed770c83463bL, 458, 500624146}, 199 | {0x5e2332dacb38308aL, 0x439eaecfL, 367, 0x57058ac5a39c382fL, 460, 1259492776}, 200 | {0x75abff917e063cacL, -729392509, 369, 0x459e089e1c7cf9bfL, 462, 1866587680}, 201 | {0x498b7fbaeec3e5ecL, 0x4d3f892L, 372, 0x6f6340fcfa618f98L, 465, -1308427008}, 202 | {0x5bee5fa9aa74df67L, 0x608f6b6L, 374, 0x591c33fd951ad946L, 467, -187748147}, 203 | {0x72e9f79415121740L, -947178396, 376, 0x4749c33144157a9fL, 469, 708794941}, 204 | {0x47d23abc8d2b4e88L, 0x7cb700beL, 379, 0x720f9eb539bbf765L, 472, 275078447}, 205 | {0x59c6c96bb076222aL, -1679507218, 381, 0x5b3fb22a94965f84L, 474, 220062758}, 206 | {0x70387bc69c93aab5L, 0x42ddf129L, 383, 0x48ffc1bbaa11e603L, 476, 1035043665}, 207 | {0x46234d5c21dc4ab1L, 0x49cab6baL, 386, 0x74cc692c434fd66bL, 479, -1779903972}, 208 | {0x57ac20b32a535d5dL, -1673698200, 388, 0x5d705423690cab89L, 481, 1153057200}, 209 | {0x6d9728dff4e834b5L, 0x34cbd82L, 390, 0x4ac0434f873d5607L, 483, 1781439219}, 210 | {0x447e798bf91120f1L, 0x220ff671L, 393, 0x779a054c0b955672L, 486, 1132315832}, 211 | {0x559e17eef755692dL, 0x6a93f40eL, 395, 0x5fae6aa33c77785bL, 488, 1764846125}, 212 | {0x6b059deab52ac378L, -986124015, 397, 0x4c8b888296c5f9e2L, 490, -1165103478}, 213 | {0x42e382b2b13aba2bL, 0x7b4396abL, 400, 0x7a78da6a8ad65c9dL, 493, -146178646}, 214 | {0x539c635f5d8968b6L, 0x5a147c56L, 402, 0x61fa48553bdeb07eL, 495, 1601044002}, 215 | {0x68837c3734ebc2e3L, -258368661, 404, 0x4e61d37763188d31L, 497, -437151717}, 216 | {0x41522da2811359ceL, 0x76600123L, 407, 0x7d6952589e8daeb6L, 500, 1018544171}, 217 | {0x51a6b90b21583042L, 0x13f8016bL, 409, 0x645441e07ed7bef8L, 502, 814835337}, 218 | {0x6610674de9ae3c52L, -1728708154, 411, 0x504367e6cbdfcbf9L, 504, -1066118649}, 219 | {0x7f9481216419cb67L, 0x3f338238L, 413, 0x4035ecb8a3196ffbL, 506, 6098540}, 220 | {0x4fbcd0b4de901f20L, -2021641885, 416, 0x66bcadf43828b32bL, 509, 868751123}, 221 | {0x63ac04e2163426e8L, -1453310532, 418, 0x52308b29c686f5bcL, 511, 695000898}, 222 | {0x7c97061a9bc130a2L, -742896341, 420, 0x41c06f549ed25e30L, 513, 556000719}, 223 | {0x4dde63d0a158be65L, -1001181125, 423, 0x6933e554315096b3L, 516, 1748594609}, 224 | {0x6155fcc4c9aeedffL, 0x3567fc49L, 425, 0x542984435aa6def5L, 518, -319111231}, 225 | {0x79ab7bf5fc1aa97fL, 0x2c1fb5cL, 427, 0x435469cf7bb8b25eL, 520, 1462697934}, 226 | {0x4c0b2d79bd90a9efL, 0x61b93d19L, 430, 0x6bba42e592c11d63L, 523, -1095657143}, 227 | {0x5f0df8d82cf4d46bL, 0x3a278c60L, 432, 0x562e9beadbcdb11cL, 525, -1735519174}, 228 | {0x76d1770e38320986L, 0x8b16f78L, 434, 0x44f216557ca48db0L, 527, 2047558498}, 229 | {0x4a42ea68e31f45f3L, -982587989, 437, 0x6e5023bbfaa0e2b3L, 530, -159880240}, 230 | {0x5cd3a5031be71770L, -1228234987, 439, 0x58401c96621a4ef6L, 532, 1590082726}, 231 | {0x74088e43e2e0dd4cL, -461551909, 441, 0x4699b0784e7b725eL, 534, -1304914197}, 232 | {0x488558ea6dcc8a50L, 0xece4c49L, 444, 0x70f5e726e3f8b6fdL, 537, -369875796}, 233 | {0x5aa6af25093face4L, 0x1281df5bL, 446, 0x5a5e5285832d5f31L, 539, -2013887555}, 234 | {0x71505aee4b8f981dL, 0x17225732L, 448, 0x484b75379c244c27L, 541, -1611110044}, 235 | {0x46d238d4ef39bf12L, 0x2e75767fL, 451, 0x73abeebf603a1372L, 544, -1718782611}, 236 | {0x5886c70a2b082ed6L, -1173171169, 453, 0x5c898bcc4cfb42c2L, 546, 342960829}, 237 | {0x6ea878ccb5ca3a8cL, 0x68978927L, 455, 0x4a07a309d72f689bL, 548, 1133362122}, 238 | {0x45294b7ff19e6497L, -1050757704, 458, 0x76729e762518a75eL, 551, -763600981}, 239 | {0x56739e5fee05fdbdL, -1313447130, 460, 0x5ec2185e8413b918L, 553, -1469874244}, 240 | {0x6c1085f7e9877d2dL, 0x1e23fbf0L, 462, 0x4bce79e536762dadL, 555, 1401080982}, 241 | {0x438a53baf1f4ae3cL, 0x32d67d76L, 465, 0x794a5ca1f0bd15e2L, 558, 523742653}, 242 | {0x546ce8a9ae71d9cbL, 0x3f8c1cd3L, 467, 0x61084a1b26fdab1bL, 560, 1277987582}, 243 | {0x698822d41a0e503eL, 0xf6f2408L, 469, 0x4da03b48ebfe227cL, 562, 1022390065}, 244 | {0x41f515c49048f226L, -911903099, 472, 0x7c33920e46636a60L, 565, 1635824105}, 245 | {0x52725b35b45b2eb0L, 0x7c0ed426L, 474, 0x635c74d8384f884dL, 567, 449665824}, 246 | {0x670ef2032171fa5cL, -1693284048, 476, 0x4f7d2a469372d370L, 569, -499260800}, 247 | {0x40695741f4e73c79L, -521431618, 479, 0x7f2eaa0a85848581L, 572, 1778163098}, 248 | {0x5083ad1272210b98L, 0x59267b2dL, 481, 0x65beee6ed136d134L, 574, 1422530478}, 249 | {0x64a498570ea94e7eL, 0x6f7019f9L, 483, 0x51658b8bda9240f6L, 576, -1438955995}, 250 | {0x7dcdbe6cd253a21eL, 0xb4c2077L, 485, 0x411e093caedb672bL, 578, -1151164796}, 251 | {0x4ea0970403744552L, -955280310, 488, 0x68300ec77e2bd845L, 581, -123876755}, 252 | {0x6248bcc5045156a7L, 0x78d3795dL, 490, 0x5359a56c64efe037L, 583, -99101404}, 253 | {0x7adaebf64565ac51L, 0x570857b4L, 492, 0x42ae1df050bfe693L, 585, 779712336}, 254 | {0x4cc8d379eb5f8bb2L, -698009904, 495, 0x6ab02fe6e79970ebL, 588, 2106533197}, 255 | {0x5ffb085866376e9fL, -1946254203, 497, 0x5559bfebec7ac0bcL, 590, 1685226557}, 256 | {0x77f9ca6e7fc54a47L, 0x6efe25a6L, 499, 0x4447ccbcbd2f0096L, 592, -1228799132}, 257 | {0x4afc1e850fdb4e6cL, -1520511096, 502, 0x6d3fadfac84b3424L, 595, 1469895226}, 258 | {0x5dbb262653d22207L, -826897046, 504, 0x576624c8a03c29b6L, 597, -1401064197}, 259 | {0x7529efafe8c6aa89L, -1033621308, 506, 0x45eb50a08030215eL, 599, -261857898}, 260 | {0x493a35cdf17c2a96L, 0x197e9e7aL, 509, 0x6fdee76733803564L, 602, -1277966096}, 261 | {0x5b88c3416ddb353bL, -1612823015, 511, 0x597f1f85c2ccf783L, 604, -1022372877}, 262 | {0x726af411c952028aL, 0x87d5d79fL, 513, 0x4798e6049bd72c69L, 606, 1759082076}, 263 | {0x4782d88b1dd34196L, -1796888893, 516, 0x728e3cd42c8b7a42L, 609, 1096544403}, 264 | {0x59638eade54811fcL, 0x3a1f1074L, 518, 0x5ba4fd768a092e9bL, 611, 1736228982}, 265 | {0x6fbc72595e9a167bL, 0x48a6d492L, 520, 0x4950cac53b3a8bafL, 613, -2046990652}, 266 | {0x45d5c777db204e0dL, 0xd6844dbL, 523, 0x754e113b91f745e5L, 616, -1557198124}, 267 | {0x574b3955d1e86190L, 0x50c25612L, 525, 0x5dd80dc941929e51L, 618, 1331221878}, 268 | {0x6d1e07ab466279f4L, 0x64f2eb96L, 527, 0x4b133e3a9adbb1daL, 620, -1512002875}, 269 | {0x4432c4cb0bfd8c38L, -1088957634, 530, 0x781ec9f75e2c4fc4L, 623, 1016769237}, 270 | {0x553f75fdcefcef46L, -287455219, 532, 0x6018a192b1bd0c9cL, 625, -45578070}, 271 | {0x6a8f537d42bc2b18L, -1433060847, 534, 0x4ce0814227ca707dL, 627, -1754449374}, 272 | {0x4299942e49b59aefL, 0x6a9d444aL, 537, 0x7b00ced03faa4d95L, 630, -1089132080}, 273 | {0x533ff939dc2301abL, 0x4544955dL, 539, 0x62670bd9cc883e11L, 632, 1705674714}, 274 | {0x680ff788532bc216L, 0x1695bab4L, 541, 0x4eb8d647d6d364daL, 634, -1212440607}, 275 | {0x4109fab533fb594dL, -836922191, 544, 0x7df48a0c8aebd491L, 637, 637075407}, 276 | {0x514c796280fa2fa1L, 0x41a4f9ddL, 546, 0x64c3a1a3a25643a7L, 639, 1368653785}, 277 | {0x659f97bb2138bb89L, -1844561836, 548, 0x509c814fb511cfb9L, 641, 235929568}, 278 | {0x7f077da9e986ea6bL, -158218647, 550, 0x407d343fc40e3fc7L, 643, 1047737114}, 279 | {0x4f64ae8a31f45283L, 0x7a1b1c02L, 553, 0x672eb9ffa016cc71L, 646, -41607536}, 280 | {0x633dda2cbe716724L, 0x58a1e302L, 555, 0x528bc7ffb345705bL, 648, 825707430}, 281 | {0x7c0d50b7ee0dc0edL, 0x6eca5bc3L, 557, 0x42096ccc8f6ac048L, 650, -198427515}, 282 | {0x4d885272f4c89894L, 0x653e795aL, 560, 0x69a8ae1418aacd41L, 653, -2035470942}, 283 | {0x60ea670fb1fabeb9L, 0x7e8e17b0L, 562, 0x5486f1a9ad557101L, 655, 948603624}, 284 | {0x792500d39e796e67L, -567173732, 564, 0x439f27baf1112734L, 657, 758882899}, 285 | {0x4bb72084430be500L, -354483583, 567, 0x6c31d92b1b4ea520L, 660, 1214212639}, 286 | {0x5ea4e8a553cede41L, 0x2596c322L, 569, 0x568e4755af721db3L, 662, 1830363570}, 287 | {0x764e22cea8c295d1L, 0x6efc73ebL, 571, 0x453e9f77bf8e7e29L, 664, 605297397}, 288 | {0x49f0d5c129799da2L, -446838670, 574, 0x6eca98bf98e3fd0eL, 667, -1608504543}, 289 | {0x5c6d0b3173d8050bL, -1632290161, 576, 0x58a213cc7a4ffda5L, 669, 1290176743}, 290 | {0x73884dfdd0ce064eL, -2040362701, 578, 0x46e80fd6c83ffe1dL, 671, -685845524}, 291 | {0x483530bea280c3f1L, 0x13fd95c0L, 581, 0x71734c8ad9fffcfcL, 674, -1956346297}, 292 | {0x5a427cee4b20f4edL, 0x58fcfb30L, 583, 0x5ac2a3a247fffd96L, 676, -706083578}, 293 | {0x70d31c29dde93228L, -1355007492, 585, 0x489bb61b6ccccadfL, 678, 294126596}, 294 | {0x4683f19a2ab1bf59L, 0x6d85a43dL, 588, 0x742c569247ae1164L, 681, -388390905}, 295 | {0x5824ee00b55e2f2fL, -924381875, 590, 0x5cf04541d2f1a783L, 683, -310712724}, 296 | {0x6e2e2980e2b5bafbL, -1155477344, 592, 0x4a59d101758e1f9cL, 685, -1107563638}, 297 | {0x44dcd9f08db194ddL, 0x54f48264L, 595, 0x76f61b3588e365c7L, 688, -1772101821}, 298 | {0x5614106cb11dfa14L, -1439587587, 597, 0x5f2b48f7a0b5eb06L, 690, 300305461}, 299 | {0x6b991487dd657899L, -725742660, 599, 0x4c22a0c61a2b226bL, 692, 1099237828}, 300 | {0x433facd4ea5f6b60L, 0x24f6c755L, 602, 0x79d1013cf6ab6a45L, 695, 899787066}, 301 | {0x540f980a24f74638L, 0x2e34792bL, 604, 0x617400fd9222bb6aL, 697, -1857150725}, 302 | {0x69137e0cae3517c6L, 0x39c19776L, 606, 0x4df6673141b562bbL, 699, -1485720580}, 303 | {0x41ac2ec7ece12edbL, 0xe418fea9L, 609, 0x7cbd71e869223792L, 702, -1518159468}, 304 | {0x52173a79e8197a92L, -585154988, 611, 0x63cac186ba81c60eL, 704, -355534116}, 305 | {0x669d0918621fd937L, -1805185559, 613, 0x4fd5679efb9b04d8L, 706, -1143420752}, 306 | {0x402225af3d53e7c2L, -1128240975, 616, 0x7fbbd8fe5f5e6e27L, 709, -1829473202}, 307 | {0x502aaf1b0ca8e1b3L, 0x6bf082deL, 618, 0x662fe0cb7f7ebe86L, 711, 254408356}, 308 | {0x64355ae1cfd31a20L, 0x46eca395L, 620, 0x51bfe70932cbcb9eL, 713, 1921513603}, 309 | {0x7d42b19a43c7e0a8L, 0x58a7cc7bL, 622, 0x4166526dc23ca2e5L, 715, 678217423}, 310 | {0x4e49af006a5cec69L, 0x3768dfcdL, 625, 0x68a3b716039437d5L, 718, 226154419}, 311 | {0x61dc1ac084f42783L, -2059200576, 627, 0x53b62c119c769310L, 720, -678069924}, 312 | {0x7a532170a6313164L, 0x6693ddb0L, 629, 0x42f8234149f875a7L, 722, 316537520}, 313 | {0x4c73f4e667debedeL, -1071879538, 632, 0x6b269ecedcc0bc3eL, 725, -2070520346}, 314 | {0x5f90f22001d66e96L, 0x70238531L, 634, 0x55b87f0be3cd6365L, 727, 920564101}, 315 | {0x77752ea8024c0a3cL, 0xc2c667eL, 636, 0x449398d64fd782b7L, 729, 1595444740}, 316 | {0x4aa93d29016f8665L, -2019835889, 639, 0x6db8f48a1958d125L, 732, 1693718124}, 317 | {0x5d538c7341cb67feL, 0xe982b012L, 641, 0x57c72a0814470db7L, 734, -2080999337}, 318 | {0x74a86f90123e41feL, -1545380841, 643, 0x4638ee6cdd05a492L, 736, -805806011}, 319 | {0x48e945ba0b66e93fL, 0x266e198eL, 646, 0x705b171494d5d41eL, 739, 428697301}, 320 | {0x5b2397288e40a38eL, -267804686, 648, 0x59e278dd43de434bL, 741, 1201951300}, 321 | {0x71ec7cf2b1d0cc72L, -1408497682, 650, 0x47e860b1031835d5L, 743, -756425878}, 322 | {0x4733ce17af227fc7L, -1417181963, 653, 0x730d67819e8d22efL, 746, -1210281405}, 323 | {0x5900c19d9aeb1fb9L, -1771477454, 655, 0x5c0ab9347ed74f26L, 748, 749761794}, 324 | {0x6f40f20501a5e7a7L, -66863169, 657, 0x49a22dc398ac3f51L, 750, -1118177483}, 325 | {0x458897432107b0c8L, -41789481, 660, 0x75d04938f446cbb5L, 753, -71097054}, 326 | {0x56eabd13e9499cfbL, 0x3ce2edcdL, 662, 0x5e403a93f69f095eL, 755, 1661109275}, 327 | {0x6ca56c58e39c043aL, 0xc1ba940L, 664, 0x4b6695432bb26de5L, 757, 469893961}, 328 | {0x43e763b78e4182a4L, 0x479149c8L, 667, 0x78a4220512b7163bL, 760, 1610823797}, 329 | {0x54e13ca571d1e34dL, 0x59759c3aL, 669, 0x60834e6a755f44fcL, 762, 1288659037}, 330 | {0x6a198bcece465c20L, -1345125559, 671, 0x4d35d8552ab29d96L, 764, -1546053148}, 331 | {0x424ff76140ebf994L, 0x6de3e20dL, 674, 0x7b895a21ddea95bdL, 767, -755698118}, 332 | {0x52e3f5399126f7f9L, -1990403439, 676, 0x62d4481b17eede31L, 769, 1972421883}, 333 | {0x679cf287f570b5f7L, -340520651, 678, 0x4f1039af4658b1c1L, 771, 718944047}, 334 | {0x40c21794f96671baL, -212825407, 681, 0x7e805c4ba3c11c68L, 774, 1150310476}, 335 | {0x50f29d7a37c00e29L, -1339773583, 683, 0x65337d094fcdb053L, 776, 1779241840}, 336 | {0x652f44d8c5b011b4L, 0x1c2dd8ceL, 685, 0x50f5fda10ca48d0fL, 778, -2012580365}, 337 | {0x7e7b160ef71c1621L, 0x23394f01L, 687, 0x40c4cae73d5070d9L, 780, 966916085}, 338 | {0x4f0cedc95a718dd4L, -1241263775, 690, 0x67a144a52ee71af5L, 783, 688072278}, 339 | {0x62d0293bb10df149L, -477837895, 692, 0x52e76a1dbf1f48c4L, 785, 550457822}, 340 | {0x7b84338a9d516d9cL, 0x5c65f727L, 694, 0x4252bb4aff4c3a36L, 787, -2136614120}, 341 | {0x4d32a036a252e481L, -1178617224, 697, 0x6a1df877fee05d24L, 790, 17391245}, 342 | {0x607f48444ae79da2L, 0x282fa917L, 699, 0x54e4c6c665804a83L, 792, 872906455}, 343 | {0x789f1a555da1850aL, -1304718500, 701, 0x43ea389eb799d535L, 794, -1019661754}, 344 | {0x4b6370755a84f326L, -1352319974, 704, 0x6ca9f43125c2eebcL, 797, 1804515030}, 345 | {0x5e3c4c92b1262ff0L, 0x5b3e8b20L, 706, 0x56ee5cf41e358bc9L, 799, -274374894}, 346 | {0x75cb5fb75d6fbbecL, 0x720e2de8L, 708, 0x458b7d90182ad63bL, 801, 639493544}, 347 | {0x499f1bd29a65d573L, -951526223, 711, 0x6f4595b359de2391L, 804, -694797248}, 348 | {0x5c06e2c740ff4ad0L, -1189407779, 713, 0x590477c2ae4b4fa7L, 806, -555837799}, 349 | {0x73089b79113f1d84L, -413017899, 715, 0x4736c635583c3fb9L, 808, 2132310138}, 350 | {0x47e5612baac77273L, 0x109d2785L, 718, 0x71f13d2226c6cc5bL, 811, -24277615}, 351 | {0x59deb97695794f0fL, -725323418, 720, 0x5b27641b5238a37cL, 813, -878415551}, 352 | {0x705667d43ad7a2d3L, -906654272, 722, 0x48ec5015db6082caL, 815, 1015254477}, 353 | {0x463600e4a4c6c5c4L, 0x5e397898L, 725, 0x74ad4cefc56737a9L, 818, -93579754}, 354 | {0x57c3811dcdf87735L, 0x75c7d6beL, 727, 0x5d5770bfd11f5fbbL, 820, 784129656}, 355 | {0x6db4616541769502L, -751186835, 729, 0x4aac5a330db2b2fcL, 822, 627303724}, 356 | {0x4490bcdf48ea1d21L, -1006362684, 732, 0x777a29eb491deb2dL, 825, 144692500} 357 | }; 358 | for (int i = 0; i < ed5datas.length; i++) 359 | ED5_A[i] = new ED5(ed5datas[i]); 360 | } 361 | 362 | final long y; 363 | final long f; 364 | final short dfb; 365 | final long oy; 366 | final long of; 367 | final short ob; 368 | 369 | private ED5(final long[] data) { 370 | this.y = data[0]; 371 | this.f = data[1] & 0xffff_ffffL; 372 | this.dfb = (short)data[2]; 373 | this.oy = data[3]; 374 | this.ob = (short)data[4]; 375 | this.of = data[5] & 0xffff_ffffL; 376 | } 377 | } 378 | 379 | private static final long MOD_DOUBLE_MANTISSA = (1L << 52) - 1; 380 | private static final double[] POSITIVE_DECIMAL_POWER = new double[39]; 381 | private static final double[] NEGTIVE_DECIMAL_POWER = new double[64]; 382 | private static final long[] POW5_LONG_VALUES = new long[27]; 383 | private static final BigInteger[] POW5_BI_VALUES = new BigInteger[343]; 384 | 385 | static { 386 | for (int i = 0; i < POSITIVE_DECIMAL_POWER.length; i++) 387 | POSITIVE_DECIMAL_POWER[i] = Math.pow(10, i); 388 | for (int i = 0; i < NEGTIVE_DECIMAL_POWER.length; i++) 389 | NEGTIVE_DECIMAL_POWER[i] = Math.pow(10, -i); 390 | 391 | long val = 1; 392 | for (int i = 0; i < POW5_LONG_VALUES.length; i++) { 393 | POW5_LONG_VALUES[i] = val; 394 | val *= 5; 395 | } 396 | 397 | final BigInteger five = BigInteger.valueOf(5); 398 | POW5_BI_VALUES[0] = BigInteger.ONE; 399 | for (int i = 1; i < POW5_BI_VALUES.length; i++) 400 | POW5_BI_VALUES[i] = five.pow(i); 401 | } 402 | 403 | private static boolean checkLowCarry(final long l, final long x, final long y32) { 404 | return l + ((Math.multiplyHigh(x, y32) << 32) + ((x * y32) >>> 32)) >= 0; 405 | } 406 | 407 | private static double longBitsToDecimalDouble(final long l62, final int e52, int sr) { 408 | long e2, mantissa0; 409 | if (e52 < -1074) { 410 | sr += -1074 - e52; 411 | e2 = 0; 412 | if (sr >= 62) 413 | return 0; 414 | mantissa0 = ((l62 >> (sr - 1)) + 1) >> 1; 415 | } else { 416 | e2 = e52 + 1075; 417 | mantissa0 = ((l62 >>> (sr - 1)) + 1) >> 1; 418 | if (mantissa0 == 1L << 53) { 419 | mantissa0 = 1L << 52; 420 | e2++; 421 | } 422 | } 423 | return Double.longBitsToDouble((e2 << 52) + (mantissa0 & MOD_DOUBLE_MANTISSA)); 424 | } 425 | 426 | private static double longBitsToIntegerDouble(final long l62, long e2, final int sr) { 427 | if (e2 >= 2047) 428 | return Double.POSITIVE_INFINITY; 429 | long mantissa0 = ((l62 >>> (sr - 1)) + 1) >> 1; 430 | if (mantissa0 == 1L << 53) { 431 | mantissa0 = 1L << 52; 432 | e2++; 433 | } 434 | return Double.longBitsToDouble((e2 << 52) + (mantissa0 & MOD_DOUBLE_MANTISSA)); 435 | } 436 | 437 | private static double scientificToIEEEDouble(final long val, final int scale) { 438 | if (val <= 0) 439 | return 0; 440 | if (scale == 0) 441 | return val; 442 | final long diff; 443 | long mantissa0, e2; 444 | if (scale > 0) { 445 | if (scale > 342) 446 | return 0; 447 | final ED5 ed5 = ED5.ED5_A[scale]; 448 | final int leadingZeros = Long.numberOfLeadingZeros(val); 449 | final long left = val << (leadingZeros - 1); 450 | final long h = Math.multiplyHigh(left, ed5.oy), l; // h is 61~62 bits 451 | int sr = h >= 1L << 61 ? 9 : 8; 452 | final int mask = (1 << (sr - 1)) - 1; 453 | final int e52 = 33 - scale - ed5.ob - leadingZeros + sr; 454 | if ((h & mask) != mask || (e52 > -1075 && ((h >> sr - 1) & 1) == 1) || (l = left * ed5.oy) > 0 || !checkLowCarry(l, left, ed5.of + 1)) 455 | return longBitsToDecimalDouble(h, e52, sr); 456 | // ensure l < 0 457 | if (checkLowCarry(l, left, ed5.of)) // tail h like 10000000 458 | return longBitsToDecimalDouble(h + 1, e52, sr); 459 | // The code here is basically unreachable, as the double range is too large to fully cover the test. 460 | // If it can be confirmed that the last method call checkLowCarry can also be optimized, it will greatly improve overall performance 461 | // If it is reached, use the difference method to determine (the result is guaranteed to be correct) 462 | if (scale < POW5_LONG_VALUES.length) { 463 | // if reach here, there is a high probability that val can be evenly divided by p5sv 464 | long p5sv = POW5_LONG_VALUES[scale]; 465 | mantissa0 = h >>> sr; 466 | long bits = ((long)(e52 + 1075) << 52) + (mantissa0 & MOD_DOUBLE_MANTISSA); 467 | int sb = 1 - scale - e52; 468 | // difference comparison method: diff = dv - dv0 >= 1/2 * 2^e52 -> val * 2^sb - mantissa0 * 2 * p5sv >= p5sv 469 | diff = sb > 0 470 | ? (val << sb) - (mantissa0 << 1) * p5sv - p5sv 471 | : val - (mantissa0 << (1 - sb)) * p5sv - (p5sv << -sb); 472 | if (diff > 0 || diff == 0 && (mantissa0 & 1) == 1) 473 | bits++; 474 | return Double.longBitsToDouble(bits); 475 | } 476 | mantissa0 = h >>> sr; 477 | if (e52 < -1074) { 478 | sr += -1074 - e52; 479 | e2 = 0; 480 | if (sr >= 62) 481 | return 0; 482 | } else 483 | e2 = e52 + 1075; 484 | diff = BigInteger.valueOf(val).shiftLeft(1 - e52 - scale) 485 | .compareTo(POW5_BI_VALUES[scale].multiply(BigInteger.valueOf((mantissa0 << 1) + 1))); 486 | } else { 487 | final int e10 = -scale; 488 | if (e10 < 23 && val < 9007199254740993L) // 1L << 53 489 | return val * POSITIVE_DECIMAL_POWER[e10]; 490 | if (e10 > 308) 491 | return Double.POSITIVE_INFINITY; 492 | final ED5 ed5 = ED5.ED5_A[e10]; 493 | final int leadingZeros = Long.numberOfLeadingZeros(val); 494 | final long left = val << (leadingZeros - 1); 495 | final long h = Math.multiplyHigh(left, ed5.y), l; // h is 61~62 bits 496 | final int sr = h >= 1L << 61 ? 9 : 8; 497 | final int mmask = (1 << sr) - 1; 498 | int mask = mmask >> 1; 499 | long e = e10 + ed5.dfb + 1140 - leadingZeros + sr; 500 | if ((h & mmask) != mask || (l = left * ed5.y) > 0 || !checkLowCarry(l, left, ed5.f + 1)) 501 | return longBitsToIntegerDouble(h, e, sr); 502 | // l < 0 503 | if (checkLowCarry(l, left, ed5.f)) // tail h like 10000000 504 | return longBitsToIntegerDouble(h + 1, e, sr); 505 | // The code here is basically unreachable, as the double range is too large to fully cover the test. 506 | // If it can be confirmed that the last method call checkLowCarry can also be optimized, it will greatly improve overall performance 507 | // If it is reached, use the difference method to determine (the result is guaranteed to be correct) 508 | final int e52 = e10 - leadingZeros + ed5.dfb + sr + 65; 509 | if (e52 >= 972) 510 | return Double.POSITIVE_INFINITY; 511 | mantissa0 = h >>> sr; 512 | e2 = e52 + 1075; 513 | diff = BigInteger.valueOf(val).multiply(POW5_BI_VALUES[e10]) 514 | .compareTo(BigInteger.valueOf((mantissa0 << 1) + 1).shiftLeft(-1 + e52 - e10)); 515 | } 516 | if ((diff > 0 || diff == 0 && (mantissa0 & 1) == 1) && ++mantissa0 == 1L << 53) { 517 | mantissa0 = 1L << 52; 518 | e2++; 519 | } 520 | return Double.longBitsToDouble((e2 << 52) + (mantissa0 & MOD_DOUBLE_MANTISSA)); 521 | } 522 | 523 | public static double parseDoubleWast(final byte[] buf, int pos) { 524 | int b = buf[pos++]; 525 | final boolean neg; 526 | if ((neg = (b == '-')) || b == '+') 527 | b = buf[pos++]; 528 | long v = 0; 529 | int s = 0, ev = 0, dotPos = 0; 530 | for (; ; b = buf[pos++]) { 531 | if (((b - '0') & 0x7fff_ffff) < 10) { 532 | if (v <= (Long.MAX_VALUE - 9) / 10) 533 | v = v * 10 + b - '0'; 534 | else if (dotPos == 0) 535 | s--; 536 | else 537 | break; 538 | } else if (b == '.') 539 | dotPos = pos + 1; 540 | else if ((b | 0x20) == 'e') { // b == 'e' || b == 'E' 541 | if (dotPos != 0) { 542 | s += pos - dotPos; 543 | dotPos = 0; 544 | } 545 | b = buf[pos++]; 546 | boolean expNeg; 547 | if ((expNeg = (b == '-')) || b == '+') 548 | b = buf[pos++]; 549 | for (; ((b - '0') & 0x7fff_ffff) < 10; b = buf[pos++]) 550 | ev = ev * 10 + b - '0'; 551 | if (expNeg) 552 | ev = -ev; 553 | break; 554 | } else 555 | break; 556 | } 557 | if (dotPos != 0) 558 | s += pos - dotPos; 559 | final double f = scientificToIEEEDouble(v, s - ev); 560 | return neg ? -f : f; 561 | } 562 | 563 | private static float scientificToIEEEFloat(final long val, final int scale) { 564 | if (scale > 0) 565 | return scale < 64 ? (float)(val * NEGTIVE_DECIMAL_POWER[scale]) : 0; 566 | if (scale == 0) 567 | return val; 568 | return scale > -39 ? (float)(val * POSITIVE_DECIMAL_POWER[-scale]) : Float.POSITIVE_INFINITY; 569 | } 570 | 571 | public static float parseFloatWast(final byte[] buf, int pos) { 572 | int b = buf[pos++]; 573 | final boolean neg; 574 | if ((neg = (b == '-')) || b == '+') 575 | b = buf[pos++]; 576 | long v = 0; 577 | int s = 0, ev = 0, dotPos = 0; 578 | for (; ; b = buf[pos++]) { 579 | if (((b - '0') & 0x7fff_ffff) < 10) { 580 | if (v <= (Long.MAX_VALUE - 9) / 10) 581 | v = v * 10 + b - '0'; 582 | else if (dotPos == 0) 583 | s--; 584 | else 585 | break; 586 | } else if (b == '.') 587 | dotPos = pos + 1; 588 | else if ((b | 0x20) == 'e') { // b == 'e' || b == 'E' 589 | if (dotPos != 0) { 590 | s += pos - dotPos; 591 | dotPos = 0; 592 | } 593 | b = buf[pos++]; 594 | boolean expNeg; 595 | if ((expNeg = (b == '-')) || b == '+') 596 | b = buf[pos++]; 597 | for (; ((b - '0') & 0x7fff_ffff) < 10; b = buf[pos++]) 598 | ev = ev * 10 + b - '0'; 599 | if (expNeg) 600 | ev = -ev; 601 | break; 602 | } else 603 | break; 604 | } 605 | if (dotPos != 0) 606 | s += pos - dotPos; 607 | final float f = scientificToIEEEFloat(v, s - ev); 608 | return neg ? -f : f; 609 | } 610 | 611 | public static void testRandomWastDoubleParser() { 612 | final ThreadLocalRandom r = ThreadLocalRandom.current(); 613 | final long t = System.nanoTime(); 614 | for (int i = 0; i < 10_000_000; i++) { 615 | long v; 616 | if (i < 400) { 617 | if (i < 100) 618 | v = i; 619 | else if (i < 200) 620 | v = 0x10_0000_0000_0000L - (i - 99); 621 | else if (i < 300) 622 | v = 0x7fe0_0000_0000_0000L + (i - 200); 623 | else 624 | v = 0x7ff0_0000_0000_0000L - (i - 299); 625 | } else { 626 | do 627 | v = r.nextLong(); 628 | while ((v & 0x7ff0_0000_0000_0000L) == 0x7ff0_0000_0000_0000L); 629 | } 630 | final double f = Double.longBitsToDouble(v); 631 | final double f2 = parseDoubleWast((f + " ").getBytes(StandardCharsets.ISO_8859_1), 0); 632 | if (f != f2) 633 | throw new AssertionError("testRandomWastDoubleParser[" + i + "]: " + f + " != " + f2); 634 | } 635 | System.out.println("testRandomWastDoubleParser OK! " + (System.nanoTime() - t) / 1_000_000 + " ms"); 636 | } 637 | 638 | public static void testRandomWastFloatParser() { 639 | final ThreadLocalRandom r = ThreadLocalRandom.current(); 640 | final long t = System.nanoTime(); 641 | for (int i = 0; i < 10_000_000; i++) { 642 | int v; 643 | if (i < 400) { 644 | if (i < 100) 645 | v = i; 646 | else if (i < 200) 647 | v = 0x80_0000 - (i - 99); 648 | else if (i < 300) 649 | v = 0x7f00_0000 + (i - 200); 650 | else 651 | v = 0x7f80_0000 - (i - 299); 652 | } else { 653 | do 654 | v = r.nextInt(); 655 | while ((v & 0x7f80_0000) == 0x7f80_0000); 656 | } 657 | final float f = Float.intBitsToFloat(v); 658 | final float f2 = parseFloatWast((f + " ").getBytes(StandardCharsets.ISO_8859_1), 0); 659 | if (f != f2) 660 | throw new AssertionError("testRandomWastFloatParser[" + i + "]: " + f + " != " + f2); 661 | } 662 | System.out.println("testRandomWastFloatParser OK! " + (System.nanoTime() - t) / 1_000_000 + " ms"); 663 | } 664 | 665 | private static final byte[][] testBytes = {"3.1234567 ".getBytes(), "31234567 ".getBytes(), 666 | "0.31234567 ".getBytes(), "312.34567 ".getBytes(), "3.1234567e7 ".getBytes(), "3.1234567E-7 ".getBytes(), 667 | "0 ".getBytes(), "1.0 ".getBytes()}; 668 | 669 | public static void benchmarkWastParser() { 670 | double r = 0.0; 671 | long t = System.nanoTime(); 672 | for (int i = 0; i < 10_000_000; i++) { 673 | for (int j = 0; j < 8; j++) 674 | r += parseDoubleWast(testBytes[j], 0); 675 | } 676 | System.out.format("benchmarkWastParser: %15.6f (%d ms)%n", r, (System.nanoTime() - t) / 1_000_000); // 624694507922444.400000 677 | } 678 | 679 | public static void main(String[] args) { 680 | // System.out.println(parseDoubleWast("375857.6195 ".getBytes(), 0)); 681 | 682 | for (int i = 0; i < 5; i++) 683 | testRandomWastDoubleParser(); 684 | for (int i = 0; i < 5; i++) 685 | testRandomWastFloatParser(); 686 | for (int i = 0; i < 5; i++) 687 | benchmarkWastParser(); 688 | } 689 | } 690 | -------------------------------------------------------------------------------- /src/jason/JsonWriter.java: -------------------------------------------------------------------------------- 1 | package jason; 2 | 3 | import java.lang.reflect.Array; 4 | import java.nio.charset.StandardCharsets; 5 | import java.util.Arrays; 6 | import java.util.Collection; 7 | import java.util.Map; 8 | import java.util.Map.Entry; 9 | import org.eclipse.jdt.annotation.NonNull; 10 | import org.eclipse.jdt.annotation.Nullable; 11 | import static jason.Json.*; 12 | 13 | public final class JsonWriter { 14 | //@formatter:off 15 | private static final long DOUBLE_SIGN_MASK = 0x8000_0000_0000_0000L; 16 | private static final long DOUBLE_EXP_MASK = 0x7FF0_0000_0000_0000L; 17 | private static final long DOUBLE_SIGNIFICAND_MASK = 0x000F_FFFF_FFFF_FFFFL; // low 52-bit 18 | private static final long DOUBLE_HIDDEN_BIT = 0x0010_0000_0000_0000L; // 1e52 19 | private static final int DOUBLE_SIGNIFICAND_SIZE = 52; 20 | private static final int DOUBLE_EXP_SIZE = 64 - DOUBLE_SIGNIFICAND_SIZE - 2; // 10 21 | private static final int DOUBLE_EXP_BIAS = 0x3FF + DOUBLE_SIGNIFICAND_SIZE; // 0x433 22 | 23 | public static final int FLAG_PRETTY_FORMAT = 0x1; 24 | public static final int FLAG_NO_QUOTE_KEY = 0x2; 25 | public static final int FLAG_WRITE_NULL = 0x4; 26 | public static final int FLAG_WRAP_ELEMENT = 0x8; // need FLAG_PRETTY_FORMAT 27 | public static final int FLAG_ALL = 0xf; 28 | public static final int FLAG_PRETTY_FORMAT_AND_WRAP_ELEMENT = FLAG_PRETTY_FORMAT | FLAG_WRAP_ELEMENT; 29 | //@formatter:on 30 | 31 | private static final byte[] LONG_MIN_BYTES = "-9223372036854775808".getBytes(StandardCharsets.ISO_8859_1); 32 | 33 | private static final byte[] DIGITES_LUT = { // [200] 34 | '0', '0', '0', '1', '0', '2', '0', '3', '0', '4', '0', '5', '0', '6', '0', '7', '0', '8', '0', '9', '1', 35 | '0', '1', '1', '1', '2', '1', '3', '1', '4', '1', '5', '1', '6', '1', '7', '1', '8', '1', '9', '2', '0', 36 | '2', '1', '2', '2', '2', '3', '2', '4', '2', '5', '2', '6', '2', '7', '2', '8', '2', '9', '3', '0', '3', 37 | '1', '3', '2', '3', '3', '3', '4', '3', '5', '3', '6', '3', '7', '3', '8', '3', '9', '4', '0', '4', '1', 38 | '4', '2', '4', '3', '4', '4', '4', '5', '4', '6', '4', '7', '4', '8', '4', '9', '5', '0', '5', '1', '5', 39 | '2', '5', '3', '5', '4', '5', '5', '5', '6', '5', '7', '5', '8', '5', '9', '6', '0', '6', '1', '6', '2', 40 | '6', '3', '6', '4', '6', '5', '6', '6', '6', '7', '6', '8', '6', '9', '7', '0', '7', '1', '7', '2', '7', 41 | '3', '7', '4', '7', '5', '7', '6', '7', '7', '7', '8', '7', '9', '8', '0', '8', '1', '8', '2', '8', '3', 42 | '8', '4', '8', '5', '8', '6', '8', '7', '8', '8', '8', '9', '9', '0', '9', '1', '9', '2', '9', '3', '9', 43 | '4', '9', '5', '9', '6', '9', '7', '9', '8', '9', '9'}; 44 | 45 | private static final long[] POW10 = { // [19] 46 | 1, 10, 100, 1000, 1_0000, 10_0000, 100_0000, 1000_0000, 1_0000_0000, 10_0000_0000, 100_0000_0000L, 47 | 1000_0000_0000L, 1_0000_0000_0000L, 10_0000_0000_0000L, 100_0000_0000_0000L, 1000_0000_0000_0000L, 48 | 1_0000_0000_0000_0000L, 10_0000_0000_0000_0000L, 100_0000_0000_0000_0000L}; 49 | 50 | private static final long[] CACHED_POWERS_F = { 51 | 0xfa8fd5a0_081c0288L, 0xbaaee17f_a23ebf76L, 0x8b16fb20_3055ac76L, 52 | 0xcf42894a_5dce35eaL, 0x9a6bb0aa_55653b2dL, 0xe61acf03_3d1a45dfL, 0xab70fe17_c79ac6caL, 53 | 0xff77b1fc_bebcdc4fL, 0xbe5691ef_416bd60cL, 0x8dd01fad_907ffc3cL, 0xd3515c28_31559a83L, 54 | 0x9d71ac8f_ada6c9b5L, 0xea9c2277_23ee8bcbL, 0xaecc4991_4078536dL, 0x823c1279_5db6ce57L, 55 | 0xc2109436_4dfb5637L, 0x9096ea6f_3848984fL, 0xd77485cb_25823ac7L, 0xa086cfcd_97bf97f4L, 56 | 0xef340a98_172aace5L, 0xb23867fb_2a35b28eL, 0x84c8d4df_d2c63f3bL, 0xc5dd4427_1ad3cdbaL, 57 | 0x936b9fce_bb25c996L, 0xdbac6c24_7d62a584L, 0xa3ab6658_0d5fdaf6L, 0xf3e2f893_dec3f126L, 58 | 0xb5b5ada8_aaff80b8L, 0x87625f05_6c7c4a8bL, 0xc9bcff60_34c13053L, 0x964e858c_91ba2655L, 59 | 0xdff97724_70297ebdL, 0xa6dfbd9f_b8e5b88fL, 0xf8a95fcf_88747d94L, 0xb9447093_8fa89bcfL, 60 | 0x8a08f0f8_bf0f156bL, 0xcdb02555_653131b6L, 0x993fe2c6_d07b7facL, 0xe45c10c4_2a2b3b06L, 61 | 0xaa242499_697392d3L, 0xfd87b5f2_8300ca0eL, 0xbce50864_92111aebL, 0x8cbccc09_6f5088ccL, 62 | 0xd1b71758_e219652cL, 0x9c400000_00000000L, 0xe8d4a510_00000000L, 0xad78ebc5_ac620000L, 63 | 0x813f3978_f8940984L, 0xc097ce7b_c90715b3L, 0x8f7e32ce_7bea5c70L, 0xd5d238a4_abe98068L, 64 | 0x9f4f2726_179a2245L, 0xed63a231_d4c4fb27L, 0xb0de6538_8cc8ada8L, 0x83c7088e_1aab65dbL, 65 | 0xc45d1df9_42711d9aL, 0x924d692c_a61be758L, 0xda01ee64_1a708deaL, 0xa26da399_9aef774aL, 66 | 0xf209787b_b47d6b85L, 0xb454e4a1_79dd1877L, 0x865b8692_5b9bc5c2L, 0xc83553c5_c8965d3dL, 67 | 0x952ab45c_fa97a0b3L, 0xde469fbd_99a05fe3L, 0xa59bc234_db398c25L, 0xf6c69a72_a3989f5cL, 68 | 0xb7dcbf53_54e9beceL, 0x88fcf317_f22241e2L, 0xcc20ce9b_d35c78a5L, 0x98165af3_7b2153dfL, 69 | 0xe2a0b5dc_971f303aL, 0xa8d9d153_5ce3b396L, 0xfb9b7cd9_a4a7443cL, 0xbb764c4c_a7a44410L, 70 | 0x8bab8eef_b6409c1aL, 0xd01fef10_a657842cL, 0x9b10a4e5_e9913129L, 0xe7109bfb_a19c0c9dL, 71 | 0xac2820d9_623bf429L, 0x80444b5e_7aa7cf85L, 0xbf21e440_03acdd2dL, 0x8e679c2f_5e44ff8fL, 72 | 0xd433179d_9c8cb841L, 0x9e19db92_b4e31ba9L, 0xeb96bf6e_badf77d9L, 0xaf87023b_9bf0ee6bL}; 73 | 74 | private static final int[] CACHED_POWERS_E = { 75 | -1220, -1193, -1166, -1140, -1113, -1087, -1060, -1034, -1007, -980, -954, -927, -901, -874, -847, -821, 76 | -794, -768, -741, -715, -688, -661, -635, -608, -582, -555, -529, -502, -475, -449, -422, -396, -369, -343, 77 | -316, -289, -263, -236, -210, -183, -157, -130, -103, -77, -50, -24, 3, 30, 56, 83, 109, 136, 162, 189, 216, 78 | 242, 269, 295, 322, 348, 375, 402, 428, 455, 481, 508, 534, 561, 588, 614, 641, 667, 694, 720, 747, 774, 79 | 800, 827, 853, 880, 907, 933, 960, 986, 1013, 1039, 1066}; 80 | 81 | private static final byte[] ESCAPE = { //@formatter:off 82 | // 0 1 2 3 4 5 6 7 8 9 A B C D E F 83 | 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'b', 't', 'n', 'u', 'f', 'r', 'u', 'u', // 0x0x 84 | 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', // 0x1x 85 | 0 , 0 , '"', 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , // 0x2x 86 | 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , // 0x3x 87 | 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , // 0x4x 88 | 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 ,'\\', 0 , 0 , 0 , // 0x5x 89 | 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , // 0x6x 90 | 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , // 0x7x 91 | }; //@formatter:on 92 | 93 | private static final byte[] EMPTY = new byte[0]; 94 | 95 | public interface BlockAllocator { 96 | @NonNull 97 | Block alloc(int minLen); 98 | 99 | default @NonNull Block alloc() { 100 | return alloc(4096); 101 | } 102 | 103 | default void free(@SuppressWarnings("unused") @NonNull Block block) { 104 | } 105 | } 106 | 107 | public static class Block { 108 | public byte[] buf; 109 | public int len; // current len of buf for non-tail 110 | Block next; // always non-null 111 | } 112 | 113 | private static final @NonNull ThreadLocal localWriters = ensureNonNull( 114 | ThreadLocal.withInitial(JsonWriter::new)); 115 | 116 | public static @NonNull JsonWriter local() { 117 | return ensureNonNull(localWriters.get()); 118 | } 119 | 120 | public static void removeLocal() { 121 | localWriters.remove(); 122 | } 123 | 124 | private final @NonNull BlockAllocator allocator; 125 | private @NonNull Block tail; // the last block of circular linked list; head = tail.next 126 | private byte[] buf; // tail.buf 127 | private int pos; // current pos of buf 128 | private int size; // sum of len in all blocks except tail 129 | private int flags = 0x10_0000; // (depth=16) << 16 130 | private int tabs; // current depth 131 | 132 | public JsonWriter() { 133 | this(null); 134 | } 135 | 136 | public JsonWriter(@Nullable BlockAllocator allocator) { 137 | if (allocator == null) { 138 | allocator = minLen -> { 139 | Block block = new Block(); 140 | block.buf = new byte[Math.max(minLen, 4096)]; 141 | return block; 142 | }; 143 | } 144 | this.allocator = allocator; 145 | Block block = allocator.alloc(); 146 | block.next = block; 147 | tail = block; 148 | buf = block.buf; 149 | } 150 | 151 | public int getDepthLimit() { 152 | return flags >>> 16; 153 | } 154 | 155 | public @NonNull JsonWriter setDepthLimit(int depth) { 156 | flags = (flags & FLAG_ALL) | (depth << 16); 157 | return this; 158 | } 159 | 160 | public int getFlags() { 161 | return flags & FLAG_ALL; 162 | } 163 | 164 | public @NonNull JsonWriter setFlags(int flags) { 165 | this.flags = this.flags & ~FLAG_ALL | flags & FLAG_ALL; 166 | return this; 167 | } 168 | 169 | public @NonNull JsonWriter setFlagsAndDepthLimit(int flags, int depth) { 170 | this.flags = (flags & FLAG_ALL) | (depth << 16); 171 | return this; 172 | } 173 | 174 | public boolean isPrettyFormat() { 175 | return (flags & FLAG_PRETTY_FORMAT) != 0; 176 | } 177 | 178 | public @NonNull JsonWriter setPrettyFormat(boolean enable) { 179 | if (enable) 180 | flags |= FLAG_PRETTY_FORMAT; 181 | else 182 | flags &= ~FLAG_PRETTY_FORMAT; 183 | return this; 184 | } 185 | 186 | public boolean isNoQuoteKey() { 187 | return (flags & FLAG_NO_QUOTE_KEY) != 0; 188 | } 189 | 190 | public @NonNull JsonWriter setNoQuoteKey(boolean enable) { 191 | if (enable) 192 | flags |= FLAG_NO_QUOTE_KEY; 193 | else 194 | flags &= ~FLAG_NO_QUOTE_KEY; 195 | return this; 196 | } 197 | 198 | public boolean isWriteNull() { 199 | return (flags & FLAG_WRITE_NULL) != 0; 200 | } 201 | 202 | public @NonNull JsonWriter setWriteNull(boolean enable) { 203 | if (enable) 204 | flags |= FLAG_WRITE_NULL; 205 | else 206 | flags &= ~FLAG_WRITE_NULL; 207 | return this; 208 | } 209 | 210 | public boolean isWrapElement() { 211 | return (flags & FLAG_WRAP_ELEMENT) != 0; 212 | } 213 | 214 | public @NonNull JsonWriter setWrapElement(boolean enable) { 215 | if (enable) 216 | flags |= FLAG_WRAP_ELEMENT; 217 | else 218 | flags &= ~FLAG_WRAP_ELEMENT; 219 | return this; 220 | } 221 | 222 | public @NonNull JsonWriter clear() { // leave the empty head block 223 | Block head = ensureNonNull(tail.next); 224 | for (Block block = head.next; block != head; block = block.next) 225 | allocator.free(ensureNonNull(block)); 226 | tail = head; 227 | head.next = head; 228 | buf = head.buf; 229 | pos = 0; 230 | size = 0; 231 | tabs = 0; 232 | return this; 233 | } 234 | 235 | public @NonNull JsonWriter free() { // can be reused by ensure() 236 | for (Block block = tail.next; ; block = block.next) { 237 | allocator.free(ensureNonNull(block)); 238 | if (block == tail) 239 | break; 240 | } 241 | //noinspection ConstantConditions 242 | tail = null; 243 | buf = EMPTY; 244 | pos = 0; 245 | size = 0; 246 | tabs = 0; 247 | return this; 248 | } 249 | 250 | public int size() { 251 | return size + pos; 252 | } 253 | 254 | public int charSize() { 255 | int len = 0; 256 | tail.len = pos; 257 | for (Block block = tail.next; ; block = block.next) { 258 | byte[] buffer = block.buf; 259 | for (int i = 0, n = block.len; i < n; len++) { 260 | int b = buffer[i]; 261 | if (b >= 0) 262 | i++; 263 | else if (b >= -0x20) { 264 | b = (b >> 4) & 1; 265 | i += 3 + b; 266 | len += b; 267 | } else 268 | i += 2; 269 | } 270 | if (block == tail) 271 | return len; 272 | } 273 | } 274 | 275 | public boolean hasWideChar() { 276 | tail.len = pos; 277 | for (Block block = tail.next; ; block = block.next) { 278 | byte[] buffer = block.buf; 279 | for (int i = 0, n = block.len; i < n; i++) 280 | if (buffer[i] < 0) 281 | return true; 282 | if (block == tail) 283 | return false; 284 | } 285 | } 286 | 287 | @SuppressWarnings({"null", "unused"}) 288 | void appendBlock(int len) { 289 | Block block = allocator.alloc(len); 290 | //noinspection ConstantConditions 291 | if (tail != null) { 292 | block.next = tail.next; 293 | tail.next = block; 294 | tail.len = pos; 295 | size += pos; 296 | pos = 0; 297 | } else 298 | block.next = block; 299 | tail = block; 300 | buf = block.buf; 301 | } 302 | 303 | public void ensure(int len) { 304 | if (pos + len > buf.length) 305 | appendBlock(len); 306 | } 307 | 308 | public void writeByte(byte b) { 309 | ensure(1); 310 | buf[pos++] = b; 311 | } 312 | 313 | public void writeByteUnsafe(byte b) { 314 | buf[pos++] = b; 315 | } 316 | 317 | public void incTab() { 318 | tabs++; 319 | } 320 | 321 | public void decTab() { 322 | tabs--; 323 | } 324 | 325 | // ensure +2 326 | public void writeNewLineTabs() { 327 | int n = tabs; 328 | ensure(3 + n); 329 | buf[pos++] = '\n'; 330 | for (int i = 0; i < n; i++) 331 | buf[pos++] = '\t'; 332 | } 333 | 334 | // ensure +1 335 | public @NonNull JsonWriter write(@Nullable Object obj) { 336 | return write(Json.instance, obj); 337 | } 338 | 339 | // ensure +1 340 | public @NonNull JsonWriter write(@NonNull Json json, @Nullable Object obj) { 341 | if (obj == null) { 342 | ensure(5); 343 | buf[pos++] = 'n'; 344 | buf[pos++] = 'u'; 345 | buf[pos++] = 'l'; 346 | buf[pos++] = 'l'; 347 | return this; 348 | } 349 | boolean noQuote = (flags & FLAG_NO_QUOTE_KEY) != 0; 350 | boolean wrapArray = (flags & FLAG_PRETTY_FORMAT_AND_WRAP_ELEMENT) == FLAG_PRETTY_FORMAT_AND_WRAP_ELEMENT; 351 | Class klass = obj.getClass(); 352 | switch (ClassMeta.getType(klass)) { 353 | case TYPE_WRAP_FLAG + TYPE_BOOLEAN: 354 | if ((Boolean)obj) { 355 | ensure(5); 356 | buf[pos++] = 't'; 357 | buf[pos++] = 'r'; 358 | buf[pos++] = 'u'; 359 | } else { 360 | ensure(6); 361 | buf[pos++] = 'f'; 362 | buf[pos++] = 'a'; 363 | buf[pos++] = 'l'; 364 | buf[pos++] = 's'; 365 | } 366 | buf[pos++] = 'e'; 367 | break; 368 | case TYPE_WRAP_FLAG + TYPE_BYTE: 369 | ensure(5); 370 | write(((Byte)obj).byteValue()); 371 | break; 372 | case TYPE_WRAP_FLAG + TYPE_SHORT: 373 | ensure(7); 374 | write(((Short)obj).shortValue()); 375 | break; 376 | case TYPE_WRAP_FLAG + TYPE_CHAR: 377 | ensure(6); 378 | write(((Character)obj).charValue()); 379 | break; 380 | case TYPE_WRAP_FLAG + TYPE_INT: 381 | ensure(12); 382 | write(((Integer)obj).intValue()); 383 | break; 384 | case TYPE_WRAP_FLAG + TYPE_LONG: 385 | ensure(21); 386 | write(((Long)obj).longValue()); 387 | break; 388 | case TYPE_WRAP_FLAG + TYPE_FLOAT: 389 | ensure(26); 390 | write(((Float)obj).floatValue()); 391 | break; 392 | case TYPE_WRAP_FLAG + TYPE_DOUBLE: 393 | ensure(26); 394 | write(((Double)obj).doubleValue()); 395 | break; 396 | case TYPE_STRING: 397 | //noinspection LocalVariableUsedAndDeclaredInDifferentSwitchBranches 398 | String s = (String)obj; 399 | ensure(s.length() * 6 + 3); // "xxxxxx" 400 | write(s, false); 401 | break; 402 | case TYPE_POS: 403 | ensure(12); 404 | write(((Pos)obj).pos); 405 | break; 406 | case TYPE_OBJECT: 407 | case TYPE_CUSTOM: 408 | if (tabs >= getDepthLimit()) { 409 | ensure(14); 410 | buf[pos++] = '"'; 411 | buf[pos++] = '!'; 412 | buf[pos++] = 'O'; 413 | buf[pos++] = 'V'; 414 | buf[pos++] = 'E'; 415 | buf[pos++] = 'R'; 416 | buf[pos++] = 'D'; 417 | buf[pos++] = 'E'; 418 | buf[pos++] = 'P'; 419 | buf[pos++] = 'T'; 420 | buf[pos++] = 'H'; 421 | buf[pos++] = '!'; 422 | buf[pos++] = '"'; 423 | break; 424 | } 425 | ClassMeta classMeta = json.getClassMeta(klass); 426 | Writer writer = classMeta.writer; 427 | if (writer != null) { 428 | writer.write0(this, classMeta, obj); 429 | break; 430 | } 431 | boolean comma = false; 432 | if (obj instanceof Collection) { 433 | ensure(1); 434 | buf[pos++] = '['; 435 | if (wrapArray) { 436 | tabs++; 437 | for (Object o : (Collection)obj) { 438 | if (comma) 439 | buf[pos++] = ','; 440 | writeNewLineTabs(); 441 | write(json, o); 442 | comma = true; 443 | } 444 | tabs--; 445 | if (comma) 446 | writeNewLineTabs(); 447 | else 448 | ensure(2); 449 | } else { 450 | for (Object o : (Collection)obj) { 451 | if (comma) 452 | buf[pos++] = ','; 453 | write(json, o); 454 | comma = true; 455 | } 456 | ensure(2); 457 | } 458 | buf[pos++] = ']'; 459 | break; 460 | } 461 | if (klass.isArray()) { 462 | ensure(1); 463 | buf[pos++] = '['; 464 | if (wrapArray) { 465 | tabs++; 466 | for (int i = 0, n = Array.getLength(obj); i < n; i++) { 467 | if (comma) 468 | buf[pos++] = ','; 469 | writeNewLineTabs(); 470 | write(json, Array.get(obj, i)); 471 | comma = true; 472 | } 473 | tabs--; 474 | if (comma) 475 | writeNewLineTabs(); 476 | else 477 | ensure(2); 478 | } else { 479 | for (int i = 0, n = Array.getLength(obj); i < n; i++) { 480 | if (comma) 481 | buf[pos++] = ','; 482 | write(json, Array.get(obj, i)); 483 | comma = true; 484 | } 485 | ensure(2); 486 | } 487 | buf[pos++] = ']'; 488 | break; 489 | } 490 | if (obj instanceof Map) { 491 | ensure(1); 492 | buf[pos++] = '{'; 493 | if ((flags & FLAG_PRETTY_FORMAT) == 0) { 494 | for (Entry e : ((Map)obj).entrySet()) { 495 | Object value = e.getValue(); 496 | if (value == null && (flags & FLAG_WRITE_NULL) == 0) 497 | continue; 498 | if (comma) 499 | buf[pos++] = ','; 500 | Object k = e.getKey(); 501 | if (k == null || Json.ClassMeta.isInKeyReaderMap(k.getClass())) { 502 | s = String.valueOf(k); 503 | ensure(s.length() * 6 + 3); // "xxxxxx": 504 | write(s, noQuote && s.indexOf(':') < 0); 505 | } else { 506 | byte[] keyStr = new JsonWriter().setFlags(FLAG_NO_QUOTE_KEY).write(json, k).toBytes(); 507 | ensure(keyStr.length * 6 + 3); // "xxxxxx": 508 | write(keyStr, false); 509 | } 510 | buf[pos++] = ':'; 511 | write(json, value); 512 | comma = true; 513 | } 514 | ensure(2); 515 | } else { 516 | for (Entry e : ((Map)obj).entrySet()) { 517 | Object value = e.getValue(); 518 | if (value == null && (flags & FLAG_WRITE_NULL) == 0) 519 | continue; 520 | if (comma) 521 | buf[pos++] = ','; 522 | else { 523 | tabs++; 524 | comma = true; 525 | } 526 | writeNewLineTabs(); 527 | Object k = e.getKey(); 528 | if (k == null || Json.ClassMeta.isInKeyReaderMap(k.getClass())) { 529 | s = String.valueOf(k); 530 | ensure(s.length() * 6 + 4); // "xxxxxx":_ 531 | write(s, noQuote && s.indexOf(':') < 0); 532 | } else { 533 | byte[] keyStr = new JsonWriter().setFlags(FLAG_NO_QUOTE_KEY).write(json, k).toBytes(); 534 | ensure(keyStr.length * 6 + 4); // "xxxxxx":_ 535 | write(keyStr, false); 536 | } 537 | buf[pos++] = ':'; 538 | buf[pos++] = ' '; 539 | write(json, value); 540 | } 541 | if (comma) { 542 | tabs--; 543 | writeNewLineTabs(); 544 | } else 545 | ensure(2); 546 | } 547 | buf[pos++] = '}'; 548 | break; 549 | } 550 | ensure(1); 551 | buf[pos++] = '{'; 552 | tabs++; 553 | boolean prettyFormat = (flags & FLAG_PRETTY_FORMAT) != 0; 554 | boolean writeNull = (flags & FLAG_WRITE_NULL) != 0; 555 | for (FieldMeta fieldMeta : classMeta.fieldMetas) { 556 | Object subObj = null; 557 | int type = fieldMeta.type; 558 | long offset = fieldMeta.offset; 559 | if (type > TYPE_DOUBLE && (subObj = unsafe.getObject(obj, offset)) == null && !writeNull) 560 | continue; 561 | byte[] name = fieldMeta.name; 562 | int posBegin = pos; 563 | if (comma) 564 | buf[pos++] = ','; 565 | if (!prettyFormat) { 566 | ensure(name.length + 3); // "xxxxxx": 567 | write(name, noQuote); 568 | buf[pos++] = ':'; 569 | } else { 570 | writeNewLineTabs(); 571 | ensure(name.length + 4); // "xxxxxx":_ 572 | write(name, noQuote); 573 | buf[pos++] = ':'; 574 | buf[pos++] = ' '; 575 | } 576 | switch (type) { 577 | case TYPE_BOOLEAN: 578 | if (unsafe.getBoolean(obj, offset)) { 579 | ensure(5); 580 | buf[pos++] = 't'; 581 | buf[pos++] = 'r'; 582 | buf[pos++] = 'u'; 583 | } else { 584 | ensure(6); 585 | buf[pos++] = 'f'; 586 | buf[pos++] = 'a'; 587 | buf[pos++] = 'l'; 588 | buf[pos++] = 's'; 589 | } 590 | buf[pos++] = 'e'; 591 | break; 592 | case TYPE_BYTE: 593 | ensure(5); 594 | write(unsafe.getByte(obj, offset)); 595 | break; 596 | case TYPE_SHORT: 597 | ensure(7); 598 | write(unsafe.getShort(obj, offset)); 599 | break; 600 | case TYPE_CHAR: 601 | ensure(7); 602 | write(unsafe.getChar(obj, offset)); 603 | break; 604 | case TYPE_INT: 605 | ensure(12); 606 | write(unsafe.getInt(obj, offset)); 607 | break; 608 | case TYPE_LONG: 609 | ensure(21); 610 | write(unsafe.getLong(obj, offset)); 611 | break; 612 | case TYPE_FLOAT: 613 | ensure(26); 614 | write(unsafe.getFloat(obj, offset)); 615 | break; 616 | case TYPE_DOUBLE: 617 | ensure(26); 618 | write(unsafe.getDouble(obj, offset)); 619 | break; 620 | case TYPE_STRING: 621 | if (subObj == null) { 622 | ensure(5); 623 | buf[pos++] = 'n'; 624 | buf[pos++] = 'u'; 625 | buf[pos++] = 'l'; 626 | buf[pos++] = 'l'; 627 | break; 628 | } 629 | s = (String)subObj; 630 | ensure(s.length() * 6 + 3); // "xxxxxx", 631 | write(s, false); 632 | break; 633 | case TYPE_POS: 634 | pos = posBegin; 635 | continue; 636 | default: 637 | write(json, subObj); 638 | break; 639 | } 640 | comma = true; 641 | } 642 | tabs--; 643 | if ((flags & FLAG_PRETTY_FORMAT) != 0 && comma) 644 | writeNewLineTabs(); 645 | else 646 | ensure(2); 647 | buf[pos++] = '}'; 648 | } 649 | return this; 650 | } 651 | 652 | public byte[] toBytes() { 653 | Block block = tail.next; 654 | if (block == tail) 655 | return Arrays.copyOf(buf, pos); 656 | tail.len = pos; 657 | int p = 0; 658 | for (; ; block = block.next) { 659 | p += block.len; 660 | if (block == tail) 661 | break; 662 | } 663 | byte[] res = new byte[p]; 664 | p = 0; 665 | for (block = tail.next; ; block = block.next) { 666 | System.arraycopy(block.buf, 0, res, p, block.len); 667 | p += block.len; 668 | if (block == tail) 669 | return res; 670 | } 671 | } 672 | 673 | public char[] toChars() { 674 | char[] res = new char[charSize()]; 675 | int p = 0; 676 | tail.len = pos; 677 | for (Block block = tail.next; ; block = block.next) { 678 | byte[] buffer = block.buf; 679 | for (int i = 0, n = block.len; i < n; ) { 680 | int b = buffer[i]; 681 | if (b >= 0) { // 0xxx xxxx 682 | res[p++] = (char)b; 683 | i++; 684 | } else if (b >= -0x20) { 685 | if (b >= -0x10) { // 1111 0xxx 10xx xxxx 10xx xxxx 10xx xxxx 686 | b = (b << 18) + (buffer[i + 1] << 12) + (buffer[i + 2] << 6) + buffer[i + 3] 687 | + ((0x10 << 18) + (0x80 << 12) + (0x80 << 6) + 0x80 - 0x10000); 688 | res[p++] = (char)(0xd800 + ((b >> 10) & 0x3ff)); 689 | res[p++] = (char)(0xdc00 + (b & 0x3ff)); 690 | i += 4; 691 | } else { // 1110 xxxx 10xx xxxx 10xx xxxx 692 | res[p++] = (char)((b << 12) + (buffer[i + 1] << 6) + buffer[i + 2] 693 | + ((0x20 << 12) + (0x80 << 6) + 0x80)); 694 | i += 3; 695 | } 696 | } else { // 110x xxxx 10xx xxxx 697 | res[p++] = (char)((b << 6) + buffer[i + 1] + ((0x40 << 6) + 0x80)); 698 | i += 2; 699 | } 700 | } 701 | if (block == tail) 702 | return res; 703 | } 704 | } 705 | 706 | @Override 707 | public @NonNull String toString() { 708 | if (BYTE_STRING) { // for JDK9+ 709 | byte[] b; 710 | int i, n; 711 | if (tail == tail.next) { 712 | b = buf; 713 | n = pos; 714 | } else { 715 | b = toBytes(); 716 | n = b.length; 717 | } 718 | for (i = 0; i < n; i++) 719 | if (b[i] < 0) 720 | break; 721 | if (i == n) { 722 | try { 723 | return (String)Json.stringCtorMH.invokeExact((byte[])(b == buf ? Arrays.copyOf(b, n) : b), (byte)0); 724 | } catch (Throwable e) { // MethodHandle.invoke 725 | throw new RuntimeException(e); 726 | } 727 | } 728 | return new String(b, 0, n, StandardCharsets.UTF_8); 729 | } 730 | try { 731 | return (String)Json.stringCtorMH.invokeExact(toChars(), false); 732 | } catch (Throwable e) { // MethodHandle.invoke 733 | throw new RuntimeException(e); 734 | } 735 | } 736 | 737 | public static long umulHigh(long a, long b) { // for JDK8- 738 | long a1 = a >> 32; 739 | long a2 = a & 0xffff_ffffL; 740 | long b1 = b >> 32; 741 | long b2 = b & 0xffff_ffffL; 742 | long c2 = a2 * b2; 743 | long t = a1 * b2 + (c2 >>> 32); 744 | long c1 = t & 0xffff_ffffL; 745 | long c0 = t >> 32; 746 | c1 += a2 * b1; 747 | long mh = a1 * b1 + c0 + (c1 >> 32); 748 | mh += (b & (a >> 63)); 749 | mh += (a & (b >> 63)); 750 | return mh; 751 | } 752 | 753 | public static long umulHigh9(long a, long b) { // for JDK9+ 754 | long r = Math.multiplyHigh(a, b); 755 | r += (b & (a >> 63)); 756 | r += (a & (b >> 63)); 757 | return r; 758 | } 759 | 760 | public static long umulHigh18(long a, long b) { // for JDK18+ 761 | return Math.unsignedMultiplyHigh(a, b); 762 | } 763 | 764 | void grisuRound(final int len, final long delta, long rest, final long tenKappa, final long mpf) { 765 | while (Long.compareUnsigned(rest, mpf) < 0 && Long.compareUnsigned(delta - rest, tenKappa) >= 0 766 | && (Long.compareUnsigned(rest + tenKappa, mpf) < 0 || // closer 767 | Long.compareUnsigned(mpf - rest, rest + tenKappa - mpf) > 0)) { 768 | buf[pos + len - 1]--; 769 | rest += tenKappa; 770 | } 771 | } 772 | 773 | void grisu2(long f, final int maxDecimalPlaces) { // f = Double.doubleToRawLongBits(d) 774 | // {f,e}.reset(d) 775 | int e = (int)(f >>> DOUBLE_SIGNIFICAND_SIZE); // [0,0x3ff] 776 | f &= DOUBLE_SIGNIFICAND_MASK; // [0,1e52) 777 | if (e != 0) { 778 | f += DOUBLE_HIDDEN_BIT; // [1e52,1e53) 779 | e -= DOUBLE_EXP_BIAS; // [-0x432,-0x34] 780 | } else 781 | e = 1 - DOUBLE_EXP_BIAS; // -0x432 (1+DOUBLE_MIN_EXP) 782 | // {f,e}.normalizedBoundaries(mf/me, pf/pe); 783 | int pe = e - 1; // [-0x433,-0x35] 784 | long pf = (f << 1) + 1; // [1,1e54) 785 | //{ pf/e.normalizeBoundary(); // pf <<= Long.numberOfLeadingZeros(pf << DOUBLE_EXP_SIZE) + DOUBLE_EXP_SIZE; 786 | while ((pf & (DOUBLE_HIDDEN_BIT << 1)) == 0) { // max loop count: 53 787 | pe--; 788 | pf <<= 1; 789 | } 790 | pe -= DOUBLE_EXP_SIZE; // [-0x432-0x35-0xa=-0x3f3,-0x35-0xa=-0x3f] 791 | pf <<= DOUBLE_EXP_SIZE; // highest bit == 1 792 | //} 793 | long mf; 794 | final int me; 795 | if (f == DOUBLE_HIDDEN_BIT) { 796 | mf = (f << 2) - 1; 797 | me = e - 2; 798 | } else { 799 | mf = (f << 1) - 1; 800 | me = e - 1; 801 | } 802 | mf <<= me - pe; 803 | //} 804 | f <<= Long.numberOfLeadingZeros(f); // f.normalize(), highest bit == 1 805 | 806 | // getCachedPower(pe) 807 | // int k = static_cast(ceil((-61 - e) * 0.30102999566398114)) + 374; 808 | final double dk = (-61 - pe) * 0.30102999566398114 + 347; // dk must be positive, so can do ceiling in positive 809 | int kk = (int)dk; 810 | if (dk - kk > 0) 811 | kk++; 812 | final int idx = (kk >> 3) + 1; 813 | kk = 348 - (idx << 3); // decimal exponent no need lookup table 814 | 815 | final long cmkf = CACHED_POWERS_F[idx]; // highest bit == 1 816 | if (javaVersion >= 18) { // for JDK18+ 817 | f = umulHigh18(f, cmkf) + ((f * cmkf) >>> 63); 818 | pf = umulHigh18(pf, cmkf) + ((pf * cmkf) >>> 63); 819 | mf = umulHigh18(mf, cmkf) + ((mf * cmkf) >>> 63); 820 | } else if (javaVersion >= 9) { // for JDK9+ 821 | f = umulHigh9(f, cmkf) + ((f * cmkf) >>> 63); 822 | pf = umulHigh9(pf, cmkf) + ((pf * cmkf) >>> 63); 823 | mf = umulHigh9(mf, cmkf) + ((mf * cmkf) >>> 63); 824 | } else { // for JDK8- 825 | f = umulHigh(f, cmkf) + ((f * cmkf) >>> 63); 826 | pf = umulHigh(pf, cmkf) + ((pf * cmkf) >>> 63); 827 | mf = umulHigh(mf, cmkf) + ((mf * cmkf) >>> 63); 828 | } 829 | e = -(pe + CACHED_POWERS_E[idx] + 64); 830 | long delta = pf-- - mf - 2; 831 | 832 | // digitGen(f, pf, e, delta) 833 | final long ff = 1L << e; 834 | int p1 = (int)(pf >>> e) & 0x7fff_ffff; 835 | long p2 = pf & (ff - 1), tmp; 836 | pf -= f; 837 | int len = 0, kappa, v; // kappa in [0, 9] 838 | // simple pure C++ implementation was faster than __builtin_clz version in this situation. @formatter:off 839 | if (p1 < 10) kappa = 1; 840 | else if (p1 < 100) kappa = 2; 841 | else if (p1 < 1000) kappa = 3; 842 | else if (p1 < 1_0000) kappa = 4; 843 | else if (p1 < 10_0000) kappa = 5; 844 | else if (p1 < 100_0000) kappa = 6; 845 | else if (p1 < 1000_0000) kappa = 7; 846 | else if (p1 < 1_0000_0000) kappa = 8; 847 | else kappa = 9; // will not reach 10 digits: if (p1 < 10_0000_0000) kappa = 9; kappa = 10; 848 | // @formatter:on 849 | do { 850 | switch (kappa) { //@formatter:off 851 | case 1: v = p1; p1 = 0; break; 852 | case 2: v = p1 / 10; p1 %= 10; break; 853 | case 3: v = p1 / 100; p1 %= 100; break; 854 | case 4: v = p1 / 1000; p1 %= 1000; break; 855 | case 5: v = p1 / 1_0000; p1 %= 1_0000; break; 856 | case 6: v = p1 / 10_0000; p1 %= 10_0000; break; 857 | case 7: v = p1 / 100_0000; p1 %= 100_0000; break; 858 | case 8: v = p1 / 1000_0000; p1 %= 1000_0000; break; 859 | case 9: v = p1 / 1_0000_0000; p1 %= 1_0000_0000; break; 860 | default: continue; 861 | } //@formatter:on 862 | if ((v | len) != 0) 863 | buf[pos + len++] = (byte)('0' + v); 864 | } while (Long.compareUnsigned((tmp = ((long)p1 << e) + p2), delta) > 0 && --kappa > 0); 865 | if (kappa != 0) { 866 | kk += --kappa; 867 | grisuRound(len, delta, tmp, POW10[kappa] << e, pf); 868 | } else { // kappa == 0 869 | for (; ; ) { 870 | p2 *= 10; 871 | delta *= 10; 872 | final int b = (int)(p2 >>> e); 873 | if ((b | len) != 0) 874 | buf[pos + len++] = (byte)('0' + b); 875 | p2 &= ff - 1; 876 | kappa++; 877 | if (Long.compareUnsigned(p2, delta) < 0) { 878 | kk -= kappa; 879 | grisuRound(len, delta, p2, ff, kappa < 19 ? POW10[kappa] * pf : 0); 880 | break; 881 | } 882 | } 883 | } 884 | 885 | // prettify(len, maxDecimalPlaces) 886 | int k = len + kk; // 10^(k-1) <= v < 10^k 887 | if (k <= 21) { 888 | if (kk >= 0) { // 1234e7 -> 12340000000 889 | for (int i = len; i < k; i++) 890 | buf[pos + i] = '0'; 891 | buf[pos + k] = '.'; 892 | buf[pos + k + 1] = '0'; 893 | pos += k + 2; 894 | return; 895 | } 896 | if (k > 0) { // 1234e-2 -> 12.34 897 | System.arraycopy(buf, pos + k, buf, pos + k + 1, len - k); 898 | buf[pos + k] = '.'; 899 | if (kk + maxDecimalPlaces < 0) { 900 | // when maxDecimalPlaces = 2, 1.2345 -> 1.23, 1.102 -> 1.1 901 | // remove extra trailing zeros (at least one) after truncation. 902 | for (int i = k + maxDecimalPlaces; i > k + 1; i--) 903 | if (buf[pos + i] != '0') { 904 | pos += i + 1; 905 | return; 906 | } 907 | pos += k + 2; // reserve one zero 908 | return; 909 | } 910 | pos += len + 1; 911 | return; 912 | } 913 | } 914 | if (-6 < k && k <= 0) { // 1234e-6 -> 0.001234 915 | final int offset = 2 - k; 916 | System.arraycopy(buf, pos, buf, pos + offset, len); 917 | buf[pos] = '0'; 918 | buf[pos + 1] = '.'; 919 | for (int i = 2; i < offset; i++) 920 | buf[pos + i] = '0'; 921 | if (len - k > maxDecimalPlaces) { 922 | // when maxDecimalPlaces = 2, 0.123 -> 0.12, 0.102 -> 0.1 923 | // remove extra trailing zeros (at least one) after truncation 924 | for (int i = maxDecimalPlaces + 1; i > 2; i--) 925 | if (buf[pos + i] != '0') { 926 | pos += i + 1; 927 | return; 928 | } 929 | pos += 3; // reserve one zero 930 | return; 931 | } 932 | pos += len + offset; 933 | return; 934 | } 935 | if (k < -maxDecimalPlaces) { // truncate to zero 936 | buf[pos++] = '0'; 937 | buf[pos++] = '.'; 938 | buf[pos++] = '0'; 939 | return; 940 | } 941 | if (len == 1) { // 1e30 942 | buf[pos + 1] = 'e'; 943 | pos += 2; 944 | } else { // 1234e30 -> 1.234e33 945 | System.arraycopy(buf, pos + 1, buf, pos + 2, len - 1); 946 | buf[pos + 1] = '.'; 947 | buf[pos + len + 1] = 'e'; 948 | pos += len + 2; 949 | } 950 | // writeExponent(--k) 951 | if (--k < 0) { 952 | buf[pos++] = '-'; 953 | k = -k; 954 | } 955 | if (k < 10) { 956 | buf[pos++] = (byte)('0' + k); 957 | return; 958 | } 959 | if (k >= 100) { 960 | buf[pos++] = (byte)('0' + k / 100); 961 | k %= 100; 962 | } 963 | buf[pos++] = (byte)('0' + k / 10); 964 | buf[pos++] = (byte)('0' + k % 10); 965 | } 966 | 967 | public void write(final double d, final int maxDecimalPlaces) { 968 | long u = Double.doubleToRawLongBits(d); 969 | if ((u & (DOUBLE_EXP_MASK | DOUBLE_SIGNIFICAND_MASK)) == 0) { // d == 0 970 | if ((u & DOUBLE_SIGN_MASK) != 0) // d < 0 971 | buf[pos++] = '-'; 972 | buf[pos++] = '0'; 973 | buf[pos++] = '.'; 974 | buf[pos++] = '0'; 975 | return; 976 | } 977 | if ((u & DOUBLE_EXP_MASK) == DOUBLE_EXP_MASK) { // !Double.isFinite() 978 | if ((u & DOUBLE_SIGNIFICAND_MASK) == 0) { // Double.isInfinite() 979 | if ((u & DOUBLE_SIGN_MASK) != 0) // d < 0 980 | buf[pos++] = '-'; 981 | buf[pos++] = 'I'; 982 | buf[pos++] = 'n'; 983 | buf[pos++] = 'f'; 984 | buf[pos++] = 'i'; 985 | buf[pos++] = 'n'; 986 | buf[pos++] = 'i'; 987 | buf[pos++] = 't'; 988 | buf[pos++] = 'y'; 989 | } else { 990 | buf[pos++] = 'N'; 991 | buf[pos++] = 'a'; 992 | buf[pos++] = 'N'; 993 | } 994 | return; 995 | } 996 | if ((u & DOUBLE_SIGN_MASK) != 0) { // d < 0 997 | buf[pos++] = '-'; 998 | u &= (DOUBLE_EXP_MASK | DOUBLE_SIGNIFICAND_MASK); // d = Math.abs(d) 999 | } 1000 | grisu2(u, maxDecimalPlaces); 1001 | } 1002 | 1003 | public void write(final double d) { 1004 | write(d, 324); 1005 | } 1006 | 1007 | public void write(int value) { 1008 | if (value < 0) { 1009 | if (value == Integer.MIN_VALUE) { 1010 | write((long)value); 1011 | return; 1012 | } 1013 | buf[pos++] = '-'; 1014 | value = -value; 1015 | } 1016 | if (value < 1_0000) { 1017 | if (value < 10) 1018 | buf[pos++] = (byte)('0' + value); 1019 | else { 1020 | final int d1 = (value / 100) << 1; 1021 | final int d2 = (value % 100) << 1; 1022 | if (value >= 100) { 1023 | if (value >= 1000) 1024 | buf[pos++] = DIGITES_LUT[d1]; 1025 | buf[pos++] = DIGITES_LUT[d1 + 1]; 1026 | } 1027 | buf[pos++] = DIGITES_LUT[d2]; 1028 | buf[pos++] = DIGITES_LUT[d2 + 1]; 1029 | } 1030 | } else if (value < 1_0000_0000) { // value = bbbb_cccc 1031 | final int b = value / 1_0000; 1032 | final int c = value % 1_0000; 1033 | final int d3 = (c / 100) << 1; 1034 | final int d4 = (c % 100) << 1; 1035 | if (value < 10_0000) 1036 | buf[pos++] = (byte)('0' + b); 1037 | else { 1038 | final int d1 = (b / 100) << 1; 1039 | final int d2 = (b % 100) << 1; 1040 | if (value >= 100_0000) { 1041 | if (value >= 1000_0000) 1042 | buf[pos++] = DIGITES_LUT[d1]; 1043 | buf[pos++] = DIGITES_LUT[d1 + 1]; 1044 | } 1045 | buf[pos++] = DIGITES_LUT[d2]; 1046 | buf[pos++] = DIGITES_LUT[d2 + 1]; 1047 | } 1048 | buf[pos++] = DIGITES_LUT[d3]; 1049 | buf[pos++] = DIGITES_LUT[d3 + 1]; 1050 | buf[pos++] = DIGITES_LUT[d4]; 1051 | buf[pos++] = DIGITES_LUT[d4 + 1]; 1052 | } else { // value = aa_bbbb_cccc in decimal 1053 | final int a = value / 1_0000_0000; // [1,21] 1054 | value %= 1_0000_0000; 1055 | final int b = value / 1_0000; 1056 | final int c = value % 1_0000; 1057 | final int d1 = (b / 100) << 1; 1058 | final int d2 = (b % 100) << 1; 1059 | final int d3 = (c / 100) << 1; 1060 | final int d4 = (c % 100) << 1; 1061 | if (a < 10) 1062 | buf[pos++] = (byte)('0' + a); 1063 | else { 1064 | final int i = a << 1; 1065 | buf[pos++] = DIGITES_LUT[i]; 1066 | buf[pos++] = DIGITES_LUT[i + 1]; 1067 | } 1068 | buf[pos++] = DIGITES_LUT[d1]; 1069 | buf[pos++] = DIGITES_LUT[d1 + 1]; 1070 | buf[pos++] = DIGITES_LUT[d2]; 1071 | buf[pos++] = DIGITES_LUT[d2 + 1]; 1072 | buf[pos++] = DIGITES_LUT[d3]; 1073 | buf[pos++] = DIGITES_LUT[d3 + 1]; 1074 | buf[pos++] = DIGITES_LUT[d4]; 1075 | buf[pos++] = DIGITES_LUT[d4 + 1]; 1076 | } 1077 | } 1078 | 1079 | public void write(long value) { // 7FFF_FFFF_FFFF_FFFF = 922_3372_0368_5477_5807 1080 | if (value < 0) { 1081 | if (value == Long.MIN_VALUE) { 1082 | System.arraycopy(LONG_MIN_BYTES, 0, buf, pos, 20); 1083 | pos += 20; 1084 | return; 1085 | } 1086 | buf[pos++] = '-'; 1087 | value = -value; 1088 | } 1089 | if (value < 1_0000_0000) { 1090 | int v = (int)value; 1091 | if (v < 1_0000) { 1092 | if (v < 10) 1093 | buf[pos++] = (byte)('0' + v); 1094 | else { 1095 | final int d1 = (v / 100) << 1; 1096 | final int d2 = (v % 100) << 1; 1097 | if (v >= 100) { 1098 | if (v >= 1000) 1099 | buf[pos++] = DIGITES_LUT[d1]; 1100 | buf[pos++] = DIGITES_LUT[d1 + 1]; 1101 | } 1102 | buf[pos++] = DIGITES_LUT[d2]; 1103 | buf[pos++] = DIGITES_LUT[d2 + 1]; 1104 | } 1105 | } else { // value = bbbb_cccc 1106 | final int b = v / 1_0000; 1107 | final int c = v % 1_0000; 1108 | final int d3 = (c / 100) << 1; 1109 | final int d4 = (c % 100) << 1; 1110 | if (v < 10_0000) 1111 | buf[pos++] = (byte)('0' + b); 1112 | else { 1113 | final int d1 = (b / 100) << 1; 1114 | final int d2 = (b % 100) << 1; 1115 | if (v >= 100_0000) { 1116 | if (v >= 1000_0000) 1117 | buf[pos++] = DIGITES_LUT[d1]; 1118 | buf[pos++] = DIGITES_LUT[d1 + 1]; 1119 | } 1120 | buf[pos++] = DIGITES_LUT[d2]; 1121 | buf[pos++] = DIGITES_LUT[d2 + 1]; 1122 | } 1123 | buf[pos++] = DIGITES_LUT[d3]; 1124 | buf[pos++] = DIGITES_LUT[d3 + 1]; 1125 | buf[pos++] = DIGITES_LUT[d4]; 1126 | buf[pos++] = DIGITES_LUT[d4 + 1]; 1127 | } 1128 | } else if (value < 1_0000_0000_0000_0000L) { 1129 | final int v0 = (int)(value / 1_0000_0000); 1130 | final int v1 = (int)(value % 1_0000_0000); 1131 | final int b1 = v1 / 1_0000; 1132 | final int c1 = v1 % 1_0000; 1133 | final int d5 = (b1 / 100) << 1; 1134 | final int d6 = (b1 % 100) << 1; 1135 | final int d7 = (c1 / 100) << 1; 1136 | final int d8 = (c1 % 100) << 1; 1137 | if (value < 10_0000_0000L) 1138 | buf[pos++] = (byte)('0' + v0); 1139 | else { 1140 | final int d4 = (v0 % 100) << 1; 1141 | if (value >= 100_0000_0000L) { 1142 | final int v2 = v0 / 100; 1143 | final int d3 = (v2 % 100) << 1; 1144 | if (value >= 1000_0000_0000L) { 1145 | if (value >= 1_0000_0000_0000L) { 1146 | final int v3 = v2 / 100; 1147 | final int d2 = (v3 % 100) << 1; 1148 | if (value >= 10_0000_0000_0000L) { 1149 | if (value >= 100_0000_0000_0000L) { 1150 | final int d1 = (v3 / 100 % 100) << 1; 1151 | if (value >= 1000_0000_0000_0000L) 1152 | buf[pos++] = DIGITES_LUT[d1]; 1153 | buf[pos++] = DIGITES_LUT[d1 + 1]; 1154 | } 1155 | buf[pos++] = DIGITES_LUT[d2]; 1156 | } 1157 | buf[pos++] = DIGITES_LUT[d2 + 1]; 1158 | } 1159 | buf[pos++] = DIGITES_LUT[d3]; 1160 | } 1161 | buf[pos++] = DIGITES_LUT[d3 + 1]; 1162 | } 1163 | buf[pos++] = DIGITES_LUT[d4]; 1164 | buf[pos++] = DIGITES_LUT[d4 + 1]; 1165 | } 1166 | buf[pos++] = DIGITES_LUT[d5]; 1167 | buf[pos++] = DIGITES_LUT[d5 + 1]; 1168 | buf[pos++] = DIGITES_LUT[d6]; 1169 | buf[pos++] = DIGITES_LUT[d6 + 1]; 1170 | buf[pos++] = DIGITES_LUT[d7]; 1171 | buf[pos++] = DIGITES_LUT[d7 + 1]; 1172 | buf[pos++] = DIGITES_LUT[d8]; 1173 | buf[pos++] = DIGITES_LUT[d8 + 1]; 1174 | } else { 1175 | final int a = (int)(value / 1_0000_0000_0000_0000L); // [1,922] 1176 | value %= 1_0000_0000_0000_0000L; 1177 | final int v0 = (int)(value / 1_0000_0000); 1178 | final int v1 = (int)(value % 1_0000_0000); 1179 | final int b0 = v0 / 1_0000; 1180 | final int c0 = v0 % 1_0000; 1181 | final int d1 = (b0 / 100) << 1; 1182 | final int d2 = (b0 % 100) << 1; 1183 | final int d3 = (c0 / 100) << 1; 1184 | final int d4 = (c0 % 100) << 1; 1185 | final int b1 = v1 / 1_0000; 1186 | final int c1 = v1 % 1_0000; 1187 | final int d5 = (b1 / 100) << 1; 1188 | final int d6 = (b1 % 100) << 1; 1189 | final int d7 = (c1 / 100) << 1; 1190 | final int d8 = (c1 % 100) << 1; 1191 | if (a < 10) 1192 | buf[pos++] = (byte)('0' + a); 1193 | else if (a < 100) { 1194 | final int i = a << 1; 1195 | buf[pos++] = DIGITES_LUT[i]; 1196 | buf[pos++] = DIGITES_LUT[i + 1]; 1197 | } else { 1198 | buf[pos++] = (byte)('0' + a / 100); 1199 | final int i = (a % 100) << 1; 1200 | buf[pos++] = DIGITES_LUT[i]; 1201 | buf[pos++] = DIGITES_LUT[i + 1]; 1202 | } 1203 | buf[pos++] = DIGITES_LUT[d1]; 1204 | buf[pos++] = DIGITES_LUT[d1 + 1]; 1205 | buf[pos++] = DIGITES_LUT[d2]; 1206 | buf[pos++] = DIGITES_LUT[d2 + 1]; 1207 | buf[pos++] = DIGITES_LUT[d3]; 1208 | buf[pos++] = DIGITES_LUT[d3 + 1]; 1209 | buf[pos++] = DIGITES_LUT[d4]; 1210 | buf[pos++] = DIGITES_LUT[d4 + 1]; 1211 | buf[pos++] = DIGITES_LUT[d5]; 1212 | buf[pos++] = DIGITES_LUT[d5 + 1]; 1213 | buf[pos++] = DIGITES_LUT[d6]; 1214 | buf[pos++] = DIGITES_LUT[d6 + 1]; 1215 | buf[pos++] = DIGITES_LUT[d7]; 1216 | buf[pos++] = DIGITES_LUT[d7 + 1]; 1217 | buf[pos++] = DIGITES_LUT[d8]; 1218 | buf[pos++] = DIGITES_LUT[d8 + 1]; 1219 | } 1220 | } 1221 | 1222 | public static int num2Hex(int n) { 1223 | return n + '0' + (((9 - n) >> 31) & ('A' - '9' - 1)); 1224 | } 1225 | 1226 | public void write(final byte[] str, final boolean noQuote) { 1227 | write(str, 0, str.length, noQuote); 1228 | } 1229 | 1230 | public void write(final byte[] str, int p, int n, final boolean noQuote) { 1231 | if (!noQuote) 1232 | buf[pos++] = '"'; 1233 | int i = p, q = p + n, c; 1234 | for (byte b; i < q; ) { 1235 | if ((c = str[i++]) >= 0 && (b = ESCAPE[c]) != 0) { 1236 | if ((n = i - p - 1) > 0) { 1237 | System.arraycopy(str, p, buf, pos, n); 1238 | pos += n; 1239 | } 1240 | p = i; 1241 | buf[pos++] = '\\'; 1242 | buf[pos++] = b; 1243 | if (b == 'u') { 1244 | buf[pos++] = '0'; 1245 | buf[pos++] = '0'; 1246 | buf[pos++] = (byte)('0' + (c >> 4)); 1247 | buf[pos++] = (byte)num2Hex(c & 0xf); 1248 | } 1249 | } 1250 | } 1251 | if ((n = i - p) > 0) { 1252 | System.arraycopy(str, p, buf, pos, n); 1253 | pos += n; 1254 | } 1255 | if (!noQuote) 1256 | buf[pos++] = '"'; 1257 | } 1258 | 1259 | public void write(final @NonNull String str, final boolean noQuote) { 1260 | if (!noQuote) 1261 | buf[pos++] = '"'; 1262 | if (BYTE_STRING && unsafe.getByte(str, STRING_CODE_OFFSET) == 0) // for JDK9+ 1263 | writeLatin1((byte[])unsafe.getObject(str, STRING_VALUE_OFFSET)); 1264 | else // for JDK8- 1265 | write8(str); 1266 | if (!noQuote) 1267 | buf[pos++] = '"'; 1268 | } 1269 | 1270 | private void writeLatin1(final byte @NonNull [] str) { 1271 | for (int c : str) { 1272 | if (c >= 0) { 1273 | byte b = ESCAPE[c]; 1274 | if (b == 0) 1275 | buf[pos++] = (byte)c; // 0xxx xxxx 1276 | else { 1277 | buf[pos++] = '\\'; 1278 | buf[pos++] = b; 1279 | if (b == 'u') { 1280 | buf[pos++] = '0'; 1281 | buf[pos++] = '0'; 1282 | buf[pos++] = (byte)('0' + (c >> 4)); 1283 | buf[pos++] = (byte)num2Hex(c & 0xf); 1284 | } 1285 | } 1286 | } else { 1287 | buf[pos++] = (byte)(0xc0 + ((c >> 6) & 3)); // 110x xxxx 10xx xxxx 1288 | buf[pos++] = (byte)(0x80 + (c & 0x3f)); 1289 | } 1290 | } 1291 | } 1292 | 1293 | private void write8(final @NonNull String str) { 1294 | for (int i = 0, n = str.length(), d; i < n; i++) { 1295 | int c = str.charAt(i); 1296 | if (c < 0x80) { 1297 | byte b = ESCAPE[c]; 1298 | if (b == 0) 1299 | buf[pos++] = (byte)c; // 0xxx xxxx 1300 | else { 1301 | buf[pos++] = '\\'; 1302 | buf[pos++] = b; 1303 | if (b == 'u') { 1304 | buf[pos++] = '0'; 1305 | buf[pos++] = '0'; 1306 | buf[pos++] = (byte)('0' + (c >> 4)); 1307 | buf[pos++] = (byte)num2Hex(c & 0xf); 1308 | } 1309 | } 1310 | } else { 1311 | if (c < 0x800) 1312 | buf[pos++] = (byte)(0xc0 + (c >> 6)); // 110x xxxx 10xx xxxx 1313 | else { 1314 | if ((c & 0xfc00) == 0xd800 && i + 1 < n && ((d = str.charAt(i + 1)) & 0xfc00) == 0xdc00) { // UTF-16 surrogate 1315 | c = (c << 10) + d + (0x10000 - (0xd800 << 10) - 0xdc00); 1316 | i++; 1317 | buf[pos++] = (byte)(0xf0 + (c >> 18)); // 1111 0xxx 10xx xxxx 10xx xxxx 10xx xxxx 1318 | buf[pos++] = (byte)(0x80 + ((c >> 12) & 0x3f)); 1319 | } else 1320 | buf[pos++] = (byte)(0xe0 + (c >> 12)); // 1110 xxxx 10xx xxxx 10xx xxxx 1321 | buf[pos++] = (byte)(0x80 + ((c >> 6) & 0x3f)); 1322 | } 1323 | buf[pos++] = (byte)(0x80 + (c & 0x3f)); 1324 | } 1325 | } 1326 | } 1327 | } 1328 | --------------------------------------------------------------------------------