package com.jsoniter; import java.lang.reflect.Type; import java.util.*; class CodegenImplArray { final static Set WITH_CAPACITY_COLLECTION_CLASSES = new HashSet() {{ 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, "if (iter.readNull()) { return null; }"); append(lines, "if (!com.jsoniter.CodegenAccess.readArrayStart(iter)) {"); append(lines, "return new {{comp}}[0];"); append(lines, "}"); append(lines, "{{comp}} a1 = {{op}};"); append(lines, "if (com.jsoniter.CodegenAccess.nextToken(iter) != ',') {"); append(lines, "return new {{comp}}[]{ a1 };"); append(lines, "}"); append(lines, "{{comp}} a2 = {{op}};"); append(lines, "if (com.jsoniter.CodegenAccess.nextToken(iter) != ',') {"); append(lines, "return new {{comp}}[]{ a1, a2 };"); append(lines, "}"); append(lines, "{{comp}} a3 = {{op}};"); append(lines, "if (com.jsoniter.CodegenAccess.nextToken(iter) != ',') {"); append(lines, "return new {{comp}}[]{ a1, a2, a3 };"); append(lines, "}"); append(lines, "{{comp}} a4 = ({{comp}}) {{op}};"); append(lines, "{{comp}}[] arr = new {{comp}}[8];"); append(lines, "arr[0] = a1;"); append(lines, "arr[1] = a2;"); append(lines, "arr[2] = a3;"); append(lines, "arr[3] = a4;"); append(lines, "int i = 4;"); append(lines, "while (com.jsoniter.CodegenAccess.nextToken(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) { Type compType = Object.class; if (typeArgs.length == 0) { // default to List } else if (typeArgs.length == 1) { compType = typeArgs[0]; } else { throw new IllegalArgumentException( "can not bind to generic collection without argument types, " + "try syntax like TypeLiteral>{}"); } if (clazz == List.class) { clazz = ArrayList.class; } else if (clazz == Set.class) { clazz = HashSet.class; } if (WITH_CAPACITY_COLLECTION_CLASSES.contains(clazz)) { return CodegenImplArray.genCollectionWithCapacity(clazz, compType); } else { return CodegenImplArray.genCollectionWithoutCapacity(clazz, compType); } } private static String genCollectionWithCapacity(Class clazz, Type compType) { StringBuilder lines = new StringBuilder(); append(lines, "if (iter.readNull()) { 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}}(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, "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 String genCollectionWithoutCapacity(Class clazz, Type compType) { StringBuilder lines = new StringBuilder(); append(lines, "if (iter.readNull()) { 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"); } }