package com.jsoniter; import java.util.*; class CodegenImplEnum { public static String genEnum(Class clazz) { StringBuilder lines = new StringBuilder(); append(lines, "if (iter.readNull()) { return null; }"); append(lines, "com.jsoniter.Slice field = com.jsoniter.CodegenAccess.readSlice(iter);"); append(lines, "switch (field.len()) {"); append(lines, renderTriTree(buildTriTree(Arrays.asList(clazz.getEnumConstants())))); append(lines, "}"); // end of switch append(lines, String.format("throw iter.reportError(\"decode enum\", field + \" is not valid enum for %s\");", clazz.getName())); return lines.toString(); } private static Map buildTriTree(List allConsts) { Map trieTree = new HashMap(); for (Object e : allConsts) { byte[] fromNameBytes = e.toString().getBytes(); Map current = (Map) trieTree.get(fromNameBytes.length); if (current == null) { current = new HashMap(); trieTree.put(fromNameBytes.length, current); } for (int i = 0; i < fromNameBytes.length - 1; i++) { byte b = fromNameBytes[i]; Map next = (Map) current.get(b); if (next == null) { next = new HashMap(); current.put(b, next); } current = next; } current.put(fromNameBytes[fromNameBytes.length - 1], e); } return trieTree; } private static String renderTriTree(Map trieTree) { StringBuilder switchBody = new StringBuilder(); for (Map.Entry entry : trieTree.entrySet()) { Integer len = entry.getKey(); append(switchBody, "case " + len + ": "); Map current = (Map) entry.getValue(); addFieldDispatch(switchBody, len, 0, current, new ArrayList()); append(switchBody, "break;"); } return switchBody.toString(); } private static void addFieldDispatch( StringBuilder lines, int len, int i, Map current, List bytesToCompare) { for (Map.Entry entry : current.entrySet()) { Byte b = entry.getKey(); if (i == len - 1) { append(lines, "if ("); for (int j = 0; j < bytesToCompare.size(); j++) { Byte a = bytesToCompare.get(j); append(lines, String.format("field.at(%d)==%s && ", i - bytesToCompare.size() + j, a)); } append(lines, String.format("field.at(%d)==%s", i, b)); append(lines, ") {"); Object e = entry.getValue(); append(lines, String.format("return %s.%s;", e.getClass().getName(), e.toString())); append(lines, "}"); continue; } Map next = (Map) entry.getValue(); if (next.size() == 1) { ArrayList nextBytesToCompare = new ArrayList(bytesToCompare); nextBytesToCompare.add(b); addFieldDispatch(lines, len, i + 1, next, nextBytesToCompare); continue; } append(lines, "if ("); for (int j = 0; j < bytesToCompare.size(); j++) { Byte a = bytesToCompare.get(j); append(lines, String.format("field.at(%d)==%s && ", i - bytesToCompare.size() + j, a)); } append(lines, String.format("field.at(%d)==%s", i, b)); append(lines, ") {"); addFieldDispatch(lines, len, i + 1, next, new ArrayList()); append(lines, "}"); } } private static void append(StringBuilder lines, String str) { lines.append(str); lines.append("\n"); } }