You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@groovy.apache.org by cc...@apache.org on 2018/05/23 19:28:33 UTC

[7/9] groovy git commit: Cache classNamed lookups

Cache classNamed lookups

The calls to `substring` are pretty expensive and done again and again
on the same classes. This is extremely inefficient, so this commit adds
an adhoc cache for this. Note that the relativeness to GroovyClassDoc
seems related to a poorly designed modeled, it can certainly be even
faster.


Project: http://git-wip-us.apache.org/repos/asf/groovy/repo
Commit: http://git-wip-us.apache.org/repos/asf/groovy/commit/2f60bd5a
Tree: http://git-wip-us.apache.org/repos/asf/groovy/tree/2f60bd5a
Diff: http://git-wip-us.apache.org/repos/asf/groovy/diff/2f60bd5a

Branch: refs/heads/GROOVY_2_5_X
Commit: 2f60bd5ac1101e8477fb4525e3ed71c9713bfe74
Parents: 89e2423
Author: Cedric Champeau <cc...@apache.org>
Authored: Wed May 23 11:58:11 2018 +0200
Committer: Cedric Champeau <cc...@apache.org>
Committed: Wed May 23 21:23:53 2018 +0200

----------------------------------------------------------------------
 .../tools/groovydoc/SimpleGroovyRootDoc.java    | 100 +++++++++++++++----
 1 file changed, 82 insertions(+), 18 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/groovy/blob/2f60bd5a/subprojects/groovy-groovydoc/src/main/java/org/codehaus/groovy/tools/groovydoc/SimpleGroovyRootDoc.java
----------------------------------------------------------------------
diff --git a/subprojects/groovy-groovydoc/src/main/java/org/codehaus/groovy/tools/groovydoc/SimpleGroovyRootDoc.java b/subprojects/groovy-groovydoc/src/main/java/org/codehaus/groovy/tools/groovydoc/SimpleGroovyRootDoc.java
index 3748907..d88fca3 100644
--- a/subprojects/groovy-groovydoc/src/main/java/org/codehaus/groovy/tools/groovydoc/SimpleGroovyRootDoc.java
+++ b/subprojects/groovy-groovydoc/src/main/java/org/codehaus/groovy/tools/groovydoc/SimpleGroovyRootDoc.java
@@ -39,6 +39,7 @@ public class SimpleGroovyRootDoc extends SimpleGroovyDoc implements GroovyRootDo
     private final Map<String, String> equivalentPackageImports;
     private List<GroovyClassDoc> classDocValues = null;
     private final Map<String, GroovyClassDoc> cachedResolvedClasses = new HashMap<String, GroovyClassDoc>();
+    private final ClassNamedCache classNamedCache;
 
     private String description = "";
 
@@ -47,6 +48,7 @@ public class SimpleGroovyRootDoc extends SimpleGroovyDoc implements GroovyRootDo
         packageDocs = new LinkedHashMap<String, GroovyPackageDoc>();
         classDocs = new LinkedHashMap<String, GroovyClassDoc>();
         equivalentPackageImports = new HashMap<String, String>();
+        classNamedCache = new ClassNamedCache(classDocs);
     }
 
     public GroovyClassDoc classNamed(GroovyClassDoc groovyClassDoc, String name) {
@@ -54,24 +56,7 @@ public class SimpleGroovyRootDoc extends SimpleGroovyDoc implements GroovyRootDo
         if (doc != null) {
             return doc;
         }
-        // look for full match or match excluding package
-        String fullPathName = groovyClassDoc != null ? groovyClassDoc.getFullPathName() : null;
-        boolean hasPackage = (fullPathName != null && fullPathName.lastIndexOf('/') > 0);
-        if (hasPackage) {
-            fullPathName = fullPathName.substring(0, fullPathName.lastIndexOf('/'));
-        }
-
-        for (Map.Entry<String, GroovyClassDoc> entry : classDocs.entrySet()) {
-            String key = entry.getKey();
-            int lastSlashIdx = key.lastIndexOf('/');
-            if (lastSlashIdx > 0) {
-                String shortKey = key.substring(lastSlashIdx + 1);
-                if (shortKey.equals(name) && (!hasPackage || key.startsWith(fullPathName))) {
-                    return entry.getValue();
-                }
-            }
-        }
-        return null;
+        return classNamedCache.search(groovyClassDoc, name);
     }
 
     public GroovyClassDoc classNamedExact(String name) {
@@ -175,4 +160,83 @@ public class SimpleGroovyRootDoc extends SimpleGroovyDoc implements GroovyRootDo
 
     }
 
+    private static class ClassNamedCache {
+        private final Map<String, GroovyClassDoc> classDocs;
+        private final Map<Entry, GroovyClassDoc> store = new HashMap<>();
+
+        private ClassNamedCache(final Map<String, GroovyClassDoc> classDocs) {
+            this.classDocs = classDocs;
+        }
+
+        public GroovyClassDoc search(GroovyClassDoc groovyClassDoc, String name) {
+            Entry entry = new Entry(groovyClassDoc, name);
+            GroovyClassDoc result = store.get(entry);
+            if (result == null) {
+                if (store.containsKey(entry)) {
+                    return null;
+                }
+                result = performLookup(groovyClassDoc, name);
+                store.put(entry, result);
+            }
+            return result;
+        }
+
+        private GroovyClassDoc performLookup(GroovyClassDoc groovyClassDoc, String name) {
+            // look for full match or match excluding package
+            String fullPathName = groovyClassDoc != null ? groovyClassDoc.getFullPathName() : null;
+            boolean hasPackage = (fullPathName != null && fullPathName.lastIndexOf('/') > 0);
+            if (hasPackage) {
+                fullPathName = fullPathName.substring(0, fullPathName.lastIndexOf('/'));
+            }
+
+            for (Map.Entry<String, GroovyClassDoc> entry : classDocs.entrySet()) {
+                String key = entry.getKey();
+                int lastSlashIdx = key.lastIndexOf('/');
+                if (lastSlashIdx > 0) {
+                    String shortKey = key.substring(lastSlashIdx + 1);
+                    if (shortKey.equals(name) && (!hasPackage || key.startsWith(fullPathName))) {
+                        GroovyClassDoc value = entry.getValue();
+                        return value;
+                    }
+                }
+            }
+            return null;
+        }
+
+        private static class Entry {
+            private final GroovyClassDoc groovyClass;
+            private final String name;
+            private final int hashCode;
+
+            private Entry(final GroovyClassDoc groovyClass, final String name) {
+                this.groovyClass = groovyClass;
+                this.name = name;
+                this.hashCode = computeHash();
+            }
+
+            @Override
+            public boolean equals(final Object o) {
+                if (this == o) return true;
+                if (o == null || getClass() != o.getClass()) return false;
+
+                final Entry entry = (Entry) o;
+
+                if (groovyClass != null ? !groovyClass.equals(entry.groovyClass) : entry.groovyClass != null)
+                    return false;
+                return name.equals(entry.name);
+            }
+
+            private int computeHash() {
+                int result = groovyClass != null ? groovyClass.hashCode() : 0;
+                result = 31 * result + name.hashCode();
+                return result;
+            }
+
+            @Override
+            public int hashCode() {
+                return hashCode;
+            }
+        }
+    }
+
 }