groovy-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From cchamp...@apache.org
Subject [07/10] groovy git commit: Cache classNamed lookups
Date Wed, 23 May 2018 19:28:15 GMT
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/12d37585
Tree: http://git-wip-us.apache.org/repos/asf/groovy/tree/12d37585
Diff: http://git-wip-us.apache.org/repos/asf/groovy/diff/12d37585

Branch: refs/heads/master
Commit: 12d375852d0c83b5e5924a12d09af6035496aaa2
Parents: a5c49a0
Author: Cedric Champeau <cchampeau@apache.org>
Authored: Wed May 23 11:58:11 2018 +0200
Committer: Cedric Champeau <cchampeau@apache.org>
Committed: Wed May 23 11:58:11 2018 +0200

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


http://git-wip-us.apache.org/repos/asf/groovy/blob/12d37585/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;
+            }
+        }
+    }
+
 }


Mime
View raw message