package com.jsoniter; import java.lang.reflect.Type; import java.util.*; class CodegenImplArray { final static Set<Class> WITH_CAPACITY_COLLECTION_CLASSES = new HashSet<Class>() {{ add(ArrayList.class); add(HashSet.class); add(Vector.class); }}; public static String genArray(Class clazz) { Class compType = clazz.getComponentType(); if (compType.isArray()) { throw new IllegalArgumentException("nested array not supported: " + clazz.getCanonicalName()); } StringBuilder lines = new StringBuilder(); append(lines, "com.jsoniter.CodegenAccess.resetExistingObject(iter);"); append(lines, "byte nextToken = com.jsoniter.CodegenAccess.readByte(iter);"); append(lines, "if (nextToken != '[') {"); append(lines, "if (nextToken == 'n') {"); append(lines, "com.jsoniter.CodegenAccess.skipFixedBytes(iter, 3);"); append(lines, "com.jsoniter.CodegenAccess.resetExistingObject(iter); return null;"); append(lines, "} else {"); append(lines, "nextToken = com.jsoniter.CodegenAccess.nextToken(iter);"); append(lines, "if (nextToken == 'n') {"); append(lines, "com.jsoniter.CodegenAccess.skipFixedBytes(iter, 3);"); append(lines, "com.jsoniter.CodegenAccess.resetExistingObject(iter); return null;"); append(lines, "}"); append(lines, "}"); append(lines, "}"); append(lines, "nextToken = com.jsoniter.CodegenAccess.nextToken(iter);"); append(lines, "if (nextToken == ']') {"); append(lines, "return new {{comp}}[0];"); append(lines, "}"); append(lines, "com.jsoniter.CodegenAccess.unreadByte(iter);"); append(lines, "{{comp}} a1 = {{op}};"); append(lines, "if (!com.jsoniter.CodegenAccess.nextTokenIsComma(iter)) {"); append(lines, "return new {{comp}}[]{ a1 };"); append(lines, "}"); append(lines, "{{comp}} a2 = {{op}};"); append(lines, "if (!com.jsoniter.CodegenAccess.nextTokenIsComma(iter)) {"); append(lines, "return new {{comp}}[]{ a1, a2 };"); append(lines, "}"); append(lines, "{{comp}} a3 = {{op}};"); append(lines, "if (!com.jsoniter.CodegenAccess.nextTokenIsComma(iter)) {"); append(lines, "return new {{comp}}[]{ a1, a2, a3 };"); append(lines, "}"); append(lines, "{{comp}} a4 = ({{comp}}) {{op}};"); append(lines, "if (!com.jsoniter.CodegenAccess.nextTokenIsComma(iter)) {"); append(lines, "return new {{comp}}[]{ a1, a2, a3, a4 };"); append(lines, "}"); append(lines, "{{comp}} a5 = ({{comp}}) {{op}};"); append(lines, "{{comp}}[] arr = new {{comp}}[10];"); append(lines, "arr[0] = a1;"); append(lines, "arr[1] = a2;"); append(lines, "arr[2] = a3;"); append(lines, "arr[3] = a4;"); append(lines, "arr[4] = a5;"); append(lines, "int i = 5;"); append(lines, "while (com.jsoniter.CodegenAccess.nextTokenIsComma(iter)) {"); append(lines, "if (i == arr.length) {"); append(lines, "{{comp}}[] newArr = new {{comp}}[arr.length * 2];"); append(lines, "System.arraycopy(arr, 0, newArr, 0, arr.length);"); append(lines, "arr = newArr;"); append(lines, "}"); append(lines, "arr[i++] = {{op}};"); append(lines, "}"); // append(lines, "if (c != ']') { com.jsoniter.CodegenAccess.reportIncompleteArray(iter); }"); append(lines, "{{comp}}[] result = new {{comp}}[i];"); append(lines, "System.arraycopy(arr, 0, result, 0, i);"); append(lines, "return result;"); return lines.toString().replace( "{{comp}}", compType.getCanonicalName()).replace( "{{op}}", CodegenImplNative.genReadOp(compType)); } public static String genCollection(Class clazz, Type[] typeArgs) { if (WITH_CAPACITY_COLLECTION_CLASSES.contains(clazz)) { return CodegenImplArray.genCollectionWithCapacity(clazz, typeArgs[0]); } else { return CodegenImplArray.genCollectionWithoutCapacity(clazz, typeArgs[0]); } } private static String genCollectionWithCapacity(Class clazz, Type compType) { StringBuilder lines = new StringBuilder(); append(lines, "{{clazz}} col = ({{clazz}})com.jsoniter.CodegenAccess.resetExistingObject(iter);"); append(lines, "if (iter.readNull()) { com.jsoniter.CodegenAccess.resetExistingObject(iter); return null; }"); append(lines, "if (!com.jsoniter.CodegenAccess.readArrayStart(iter)) {"); append(lines, "return col == null ? new {{clazz}}(0): ({{clazz}})com.jsoniter.CodegenAccess.reuseCollection(col);"); append(lines, "}"); append(lines, "Object a1 = {{op}};"); append(lines, "if (com.jsoniter.CodegenAccess.nextToken(iter) != ',') {"); append(lines, "{{clazz}} obj = col == null ? new {{clazz}}(1): ({{clazz}})com.jsoniter.CodegenAccess.reuseCollection(col);"); append(lines, "obj.add(a1);"); append(lines, "return obj;"); append(lines, "}"); append(lines, "Object a2 = {{op}};"); append(lines, "if (com.jsoniter.CodegenAccess.nextToken(iter) != ',') {"); append(lines, "{{clazz}} obj = col == null ? new {{clazz}}(2): ({{clazz}})com.jsoniter.CodegenAccess.reuseCollection(col);"); append(lines, "obj.add(a1);"); append(lines, "obj.add(a2);"); append(lines, "return obj;"); append(lines, "}"); append(lines, "Object a3 = {{op}};"); append(lines, "if (com.jsoniter.CodegenAccess.nextToken(iter) != ',') {"); append(lines, "{{clazz}} obj = col == null ? new {{clazz}}(3): ({{clazz}})com.jsoniter.CodegenAccess.reuseCollection(col);"); append(lines, "obj.add(a1);"); append(lines, "obj.add(a2);"); append(lines, "obj.add(a3);"); append(lines, "return obj;"); append(lines, "}"); append(lines, "Object a4 = {{op}};"); append(lines, "{{clazz}} obj = col == null ? new {{clazz}}(8): ({{clazz}})com.jsoniter.CodegenAccess.reuseCollection(col);"); append(lines, "obj.add(a1);"); append(lines, "obj.add(a2);"); append(lines, "obj.add(a3);"); append(lines, "obj.add(a4);"); append(lines, "while (com.jsoniter.CodegenAccess.nextToken(iter) == ',') {"); append(lines, "obj.add({{op}});"); append(lines, "}"); append(lines, "return obj;"); return lines.toString().replace( "{{clazz}}", clazz.getName()).replace( "{{op}}", CodegenImplNative.genReadOp(compType)); } private static String genCollectionWithoutCapacity(Class clazz, Type compType) { StringBuilder lines = new StringBuilder(); append(lines, "if (iter.readNull()) { com.jsoniter.CodegenAccess.resetExistingObject(iter); return null; }"); append(lines, "{{clazz}} col = ({{clazz}})com.jsoniter.CodegenAccess.resetExistingObject(iter);"); append(lines, "if (!com.jsoniter.CodegenAccess.readArrayStart(iter)) {"); append(lines, "return col == null ? new {{clazz}}(): ({{clazz}})com.jsoniter.CodegenAccess.reuseCollection(col);"); append(lines, "}"); append(lines, "Object a1 = {{op}};"); append(lines, "if (com.jsoniter.CodegenAccess.nextToken(iter) != ',') {"); append(lines, "{{clazz}} obj = col == null ? new {{clazz}}(): ({{clazz}})com.jsoniter.CodegenAccess.reuseCollection(col);"); append(lines, "obj.add(a1);"); append(lines, "return obj;"); append(lines, "}"); append(lines, "Object a2 = {{op}};"); append(lines, "if (com.jsoniter.CodegenAccess.nextToken(iter) != ',') {"); append(lines, "{{clazz}} obj = col == null ? new {{clazz}}(): ({{clazz}})com.jsoniter.CodegenAccess.reuseCollection(col);"); append(lines, "obj.add(a1);"); append(lines, "obj.add(a2);"); append(lines, "return obj;"); append(lines, "}"); append(lines, "Object a3 = {{op}};"); append(lines, "if (com.jsoniter.CodegenAccess.nextToken(iter) != ',') {"); append(lines, "{{clazz}} obj = col == null ? new {{clazz}}(): ({{clazz}})com.jsoniter.CodegenAccess.reuseCollection(col);"); append(lines, "obj.add(a1);"); append(lines, "obj.add(a2);"); append(lines, "obj.add(a3);"); append(lines, "return obj;"); append(lines, "}"); append(lines, "Object a4 = {{op}};"); append(lines, "{{clazz}} obj = col == null ? new {{clazz}}(): ({{clazz}})com.jsoniter.CodegenAccess.reuseCollection(col);"); append(lines, "obj.add(a1);"); append(lines, "obj.add(a2);"); append(lines, "obj.add(a3);"); append(lines, "obj.add(a4);"); append(lines, "while (com.jsoniter.CodegenAccess.nextToken(iter) == ',') {"); append(lines, "obj.add({{op}});"); append(lines, "}"); // append(lines, "if (c != ']') { com.jsoniter.CodegenAccess.reportIncompleteArray(iter); }"); append(lines, "return obj;"); return lines.toString().replace( "{{clazz}}", clazz.getName()).replace( "{{op}}", CodegenImplNative.genReadOp(compType)); } private static void append(StringBuilder lines, String str) { lines.append(str); lines.append("\n"); } }