From commits-return-6725-archive-asf-public=cust-asf.ponee.io@groovy.apache.org Wed May 23 21:28:30 2018 Return-Path: X-Original-To: archive-asf-public@cust-asf.ponee.io Delivered-To: archive-asf-public@cust-asf.ponee.io Received: from mail.apache.org (hermes.apache.org [140.211.11.3]) by mx-eu-01.ponee.io (Postfix) with SMTP id 836121807A3 for ; Wed, 23 May 2018 21:28:28 +0200 (CEST) Received: (qmail 59049 invoked by uid 500); 23 May 2018 19:28:27 -0000 Mailing-List: contact commits-help@groovy.apache.org; run by ezmlm Precedence: bulk List-Help: List-Unsubscribe: List-Post: List-Id: Reply-To: dev@groovy.apache.org Delivered-To: mailing list commits@groovy.apache.org Received: (qmail 58958 invoked by uid 99); 23 May 2018 19:28:27 -0000 Received: from git1-us-west.apache.org (HELO git1-us-west.apache.org) (140.211.11.23) by apache.org (qpsmtpd/0.29) with ESMTP; Wed, 23 May 2018 19:28:27 +0000 Received: by git1-us-west.apache.org (ASF Mail Server at git1-us-west.apache.org, from userid 33) id 7697EE1146; Wed, 23 May 2018 19:28:27 +0000 (UTC) Content-Type: text/plain; charset="us-ascii" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit From: cchampeau@apache.org To: commits@groovy.apache.org Date: Wed, 23 May 2018 19:28:33 -0000 Message-Id: <5875cac40fe24b51ac7e1e7cd35b0dee@git.apache.org> In-Reply-To: <4e5c53bb62c44eb4b9345da717f3738f@git.apache.org> References: <4e5c53bb62c44eb4b9345da717f3738f@git.apache.org> X-Mailer: ASF-Git Admin Mailer Subject: [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 Authored: Wed May 23 11:58:11 2018 +0200 Committer: Cedric Champeau 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 equivalentPackageImports; private List classDocValues = null; private final Map cachedResolvedClasses = new HashMap(); + private final ClassNamedCache classNamedCache; private String description = ""; @@ -47,6 +48,7 @@ public class SimpleGroovyRootDoc extends SimpleGroovyDoc implements GroovyRootDo packageDocs = new LinkedHashMap(); classDocs = new LinkedHashMap(); equivalentPackageImports = new HashMap(); + 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 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 classDocs; + private final Map store = new HashMap<>(); + + private ClassNamedCache(final Map 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 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; + } + } + } + }