OSDN Git Service

GWT Reflection: Use switch instead of if-cascade
authorhneuer <hanno.neuer@gmail.com>
Sun, 22 Sep 2013 07:10:55 +0000 (09:10 +0200)
committerhneuer <hanno.neuer@gmail.com>
Sun, 22 Sep 2013 07:10:55 +0000 (09:10 +0200)
backends/gdx-backends-gwt/src/com/badlogic/gwtref/gen/ReflectionCacheSourceCreator.java

index 9ee6969..0503e3f 100644 (file)
@@ -18,10 +18,14 @@ package com.badlogic.gwtref.gen;
 
 import java.io.PrintWriter;
 import java.util.ArrayList;
+import java.util.HashMap;
 import java.util.HashSet;
 import java.util.List;
+import java.util.Map;
 import java.util.Set;
+import java.util.Map.Entry;
 
+import com.badlogic.gwtref.gen.SwitchedCodeBlocks.Code;
 import com.google.gwt.core.ext.BadPropertyValueException;
 import com.google.gwt.core.ext.ConfigurationProperty;
 import com.google.gwt.core.ext.GeneratorContext;
@@ -555,6 +559,8 @@ public class ReflectionCacheSourceCreator {
 
        private void invokeM () {
                p("public Object invoke(Method m, Object obj, Object[] params) {");
+               p("    String param = m.methodId;");
+               SwitchedCodeBlocks pc = new SwitchedCodeBlocks();
                int subN = 0;
                int nDispatch = 0;
                for (MethodStub stub : methodStubs) {
@@ -570,24 +576,26 @@ public class ReflectionCacheSourceCreator {
                                }
                        }
                        if (!paramsOk) continue;
-                       p("   if(m.methodId.equals(\"" + stub.methodId + "\")) {");
+                       buffer.setLength(0);
                        if (stub.returnType.equals("void")) {
-                               pn("      " + stub.methodId + "(");
+                               pbn("      " + stub.methodId + "(");
                                addParameters(stub);
-                               p(");");
-                               p("      return null;");
+                               pbn(");");
+                               pbn(" return null;");
                        } else {
-                               pn("      return " + stub.methodId + "(");
+                               pbn("      return " + stub.methodId + "(");
                                addParameters(stub);
-                               pn(");");
+                               pbn(");");
                        }
-                       p("   }");
+                       pc.add(stub.methodId, buffer.toString());
                        nDispatch++;
                        if (nDispatch > 1000) {
+                               pc.print();
+                               pc = new SwitchedCodeBlocks();
                                subN++;
-                               p("   return invoke" + subN + "(m, obj, params);");
+                               p("   return invoke" + subN + "(m, obj, params, param);");
                                p("}");
-                               p("public Object invoke" + subN + "(Method m, Object obj, Object[] params) {");
+                               p("public Object invoke" + subN + "(Method m, Object obj, Object[] params, String param) {");
                                nDispatch = 0;
                        }
                }
@@ -597,13 +605,13 @@ public class ReflectionCacheSourceCreator {
        }
 
        private void addParameters (MethodStub stub) {
-               pn("(" + stub.enclosingType + ")obj" + (stub.parameterTypes.size() > 0 ? "," : ""));
+               pbn("(" + stub.enclosingType + ")obj" + (stub.parameterTypes.size() > 0 ? "," : ""));
                for (int i = 0; i < stub.parameterTypes.size(); i++) {
                        String paramType = stub.parameterTypes.get(i);
                        if (isPrimitive(paramType)) {
-                               pn(castPrimitive(paramType, "params[" + i + "]") + (i < stub.parameterTypes.size() - 1 ? ", " : ""));
+                               pbn(castPrimitive(paramType, "params[" + i + "]") + (i < stub.parameterTypes.size() - 1 ? ", " : ""));
                        } else {
-                               pn("(" + stub.parameterTypes.get(i) + ")params[" + i + "]" + (i < stub.parameterTypes.size() - 1 ? ", " : ""));
+                               pbn("(" + stub.parameterTypes.get(i) + ")params[" + i + "]" + (i < stub.parameterTypes.size() - 1 ? ", " : ""));
                        }
                }
        }
@@ -628,30 +636,37 @@ public class ReflectionCacheSourceCreator {
 
        private void setF () {
                p("public void set(Field field, Object obj, Object value) throws IllegalAccessException {");
+               p("    String param = field.setter;");
+               SwitchedCodeBlocks pc = new SwitchedCodeBlocks();
                for (SetterGetterStub stub : setterGetterStubs) {
                        if (stub.enclosingType == null || stub.type == null || stub.isFinal || stub.unused) continue;
-                       p("   if(field.setter.equals(\"" + stub.setter + "\")) " + stub.setter + "((" + stub.enclosingType + ")obj, value);");
+                       pc.add(stub.setter, stub.setter + "((" + stub.enclosingType + ")obj, value);");
                }
+               pc.print();
                p("}");
        }
 
        private void getF () {
                p("public Object get(Field field, Object obj) throws IllegalAccessException {");
+               p("    String param = field.getter;");
+               SwitchedCodeBlocks pc = new SwitchedCodeBlocks();
                for (SetterGetterStub stub : setterGetterStubs) {
                        if (stub.enclosingType == null || stub.type == null || stub.unused) continue;
-                       p("   if(field.getter.equals(\"" + stub.getter + "\")) return " + stub.getter + "((" + stub.enclosingType + ")obj);");
+                       pc.add( stub.getter, "return " + stub.getter + "((" + stub.enclosingType + ")obj);");
                }
+               pc.print();
                p("   return null;");
                p("}");
        }
 
        private void newInstanceT () {
                p("public Object newInstance (Type type) {");
+               p("    String param = type.getName();");
+               SwitchedCodeBlocks pc = new SwitchedCodeBlocks();
                for (JType type : types) {
                        if (type instanceof JClassType) {
                                if (isInstantiableWithNewOperator((JClassType)type)) {
-                                       p("if(type.getName().equals(\"" + type.getErasedType().getQualifiedSourceName() + "\")) return new "
-                                               + type.getErasedType().getQualifiedSourceName() + "();");
+                                       pc.add(type.getErasedType().getQualifiedSourceName(), "return new "+ type.getErasedType().getQualifiedSourceName() + "();");
                                } else {
                                        logger.log(Type.INFO, "No public default constructor for '" + type.getQualifiedSourceName()
                                                + "', or type is an array, enum, abstract class or interface type");
@@ -660,6 +675,7 @@ public class ReflectionCacheSourceCreator {
                                logger.log(Type.INFO, "No public default constructor for primitive type '" + type.getQualifiedSourceName() + "'");
                        }
                }
+               pc.print();
                p("return null;");
                p("}");
        }
@@ -676,6 +692,8 @@ public class ReflectionCacheSourceCreator {
 
        private void setArrayElementT () {
                p("public void setArrayElement(Type type, Object obj, int i, Object value) {");
+               p("    String param = type.getName();");
+               SwitchedCodeBlocks pc = new SwitchedCodeBlocks();
                for (JType type : types) {
                        if (!(type instanceof JArrayType)) continue;
                        String value = ((JArrayType)type).getComponentType().getErasedType().getQualifiedSourceName();
@@ -684,37 +702,42 @@ public class ReflectionCacheSourceCreator {
                        } else {
                                value = "(" + value + ")value";
                        }
-                       p("   if(type.getName().equals(\"" + type.getQualifiedSourceName() + "\")) ((" + type.getQualifiedSourceName()
-                               + ")obj)[i] = " + value + ";");
+                       pc.add(type.getQualifiedSourceName() , "((" + type.getQualifiedSourceName() + ")obj)[i] = " + value + ";");
                }
+               pc.print();
                p("}");
        }
 
        private void getArrayElementT () {
                p("public Object getArrayElement(Type type, Object obj, int i) {");
+               p("    String param = type.getName();");
+               SwitchedCodeBlocks pc = new SwitchedCodeBlocks();
                for (JType type : types) {
                        if (!(type instanceof JArrayType)) continue;
-                       p("   if(type.getName().equals(\"" + type.getQualifiedSourceName() + "\")) return ((" + type.getQualifiedSourceName()
-                               + ")obj)[i];");
+                       pc.add(type.getQualifiedSourceName(), "return ((" + type.getQualifiedSourceName() + ")obj)[i];");
                }
+               pc.print();
                p("     return null;");
                p("}");
        }
 
        private void getArrayLengthT () {
                p("public int getArrayLength(Type type, Object obj) {");
+               p("    String param = type.getName();");
+               SwitchedCodeBlocks pc = new SwitchedCodeBlocks();
                for (JType type : types) {
                        if (!(type instanceof JArrayType)) continue;
-                       p("   if(type.getName().equals(\"" + type.getQualifiedSourceName() + "\")) return ((" + type.getQualifiedSourceName()
-                               + ")obj).length;");
+                       pc.add(type.getQualifiedSourceName(), "return ((" + type.getQualifiedSourceName() + ")obj).length;");
                }
+               pc.print();
                p("     return 0;");
                p("}");
        }
 
        private void newArrayC () {
                p("public Object newArray (Class componentType, int size) {");
-               p("    String typeName = componentType.getName().replace('$', '.');");
+               p("    String param = componentType.getName().replace('$', '.');");
+               SwitchedCodeBlocks pc = new SwitchedCodeBlocks();
                for (JType type : types) {
                        if (type.getQualifiedSourceName().equals("void")) continue;
                        if (type.getQualifiedSourceName().endsWith("Void")) continue;
@@ -723,8 +746,9 @@ public class ReflectionCacheSourceCreator {
                                arrayType = type.getErasedType().getQualifiedSourceName();
                                arrayType = arrayType.replaceFirst("\\[\\]", "[size]") + "[]";
                        }
-                       p("   if(typeName.equals(\"" + type.getQualifiedSourceName() + "\")) return new " + arrayType + ";");
+                       pc.add(type.getQualifiedSourceName(), "return new " + arrayType + ";");
                }
+               pc.print();
                p("     throw new RuntimeException(\"Couldn't create array with element type \" + componentType.getName());");
                p("}");
        }
@@ -762,4 +786,40 @@ public class ReflectionCacheSourceCreator {
        private void pbn (String line) {
                buffer.append(line);
        }
+
+       class SwitchedCodeBlocks {
+               private Map<Integer, List<KeyedCodeBlock>> keyHash2CodeBlock = new HashMap();
+
+               public void add (String key, String codeBlock) {
+                       int keyHash = key.hashCode();
+                       List<KeyedCodeBlock> blocks = keyHash2CodeBlock.get(keyHash);
+                       if (blocks == null) {
+                               blocks = new ArrayList<SwitchedCodeBlocks.KeyedCodeBlock>();
+                               keyHash2CodeBlock.put(keyHash, blocks);
+                       }
+                       KeyedCodeBlock c = new KeyedCodeBlock();
+                       c.key = key;
+                       c.codeBlock = codeBlock;
+                       blocks.add(c);
+               }
+
+               void print () {
+                       p("    switch(param.hashCode()) {");
+                       for (Entry<Integer, List<KeyedCodeBlock>> e : keyHash2CodeBlock.entrySet()) {
+                               p("    case " + e.getKey() + ":");
+                               String prefix = "        ";
+                               for (KeyedCodeBlock c : e.getValue()) {
+                                       p(prefix + "if(\"" + c.key + "\".equals(param)) {" + c.codeBlock + "}");
+                                       prefix = "        else ";
+                               }
+                               p("    break;");
+                       }
+                       p("}");
+               }
+
+               class KeyedCodeBlock {
+                       String key;
+                       String codeBlock;
+               }
+       }
 }