You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@myfaces.apache.org by ta...@apache.org on 2018/12/25 22:49:26 UTC

[myfaces] branch 2.3.x updated: [perf] optimize TagAttributesImpl access

This is an automated email from the ASF dual-hosted git repository.

tandraschko pushed a commit to branch 2.3.x
in repository https://gitbox.apache.org/repos/asf/myfaces.git


The following commit(s) were added to refs/heads/2.3.x by this push:
     new b044b21  [perf] optimize TagAttributesImpl access
b044b21 is described below

commit b044b212f4dde0801e4f7ddb18d1d0b7fb8dd008
Author: Thomas Andraschko <ta...@apache.org>
AuthorDate: Tue Dec 25 23:49:38 2018 +0100

    [perf] optimize TagAttributesImpl access
---
 .../view/facelets/tag/TagAttributesImpl.java       | 140 +++++++++------------
 .../view/facelets/tag/TagAttributesImplTest.java   |  59 +++++++++
 2 files changed, 119 insertions(+), 80 deletions(-)

diff --git a/impl/src/main/java/org/apache/myfaces/view/facelets/tag/TagAttributesImpl.java b/impl/src/main/java/org/apache/myfaces/view/facelets/tag/TagAttributesImpl.java
index 52694e6..dcdf070 100644
--- a/impl/src/main/java/org/apache/myfaces/view/facelets/tag/TagAttributesImpl.java
+++ b/impl/src/main/java/org/apache/myfaces/view/facelets/tag/TagAttributesImpl.java
@@ -20,8 +20,10 @@ package org.apache.myfaces.view.facelets.tag;
 
 import java.util.ArrayList;
 import java.util.Arrays;
+import java.util.HashMap;
 import java.util.HashSet;
 import java.util.List;
+import java.util.Map;
 import java.util.Set;
 
 import javax.faces.view.facelets.TagAttribute;
@@ -29,12 +31,7 @@ import javax.faces.view.facelets.TagAttributes;
 
 /**
  * A set of TagAttributes, usually representing all attributes on a Tag.
- * 
- * TODO: PROFILE - Explore the possibility of using HashMap instead of sorted arrays. 
- *       The footprint should be higher, but the instanciation and access speed should be faster 
- *       Instanciation: from O(n log n) to O(1)
- *       Access: from O(log n) to O(1)
- * 
+ *
  * See org.apache.myfaces.view.facelets.tag.Tag
  * See org.apache.myfaces.view.facelets.tag.TagAttributeImpl
  * @author Jacob Hookom
@@ -44,47 +41,52 @@ public final class TagAttributesImpl extends TagAttributes
 {
     private final static TagAttribute[] EMPTY = new TagAttribute[0];
 
-    private final TagAttribute[] _attributes;
-
-    private final String[] _namespaces;
-
-    private final List<TagAttribute[]> _nsattrs;
+    private final TagAttribute[] attributes;
+    private final String[] namespaces;
+    private final HashMap<String, TagAttribute[]> namespaceAttributes;
+    private final HashMap<String, Map<String, TagAttribute>> namespaceLocalNameAttributes;
 
-    /**
-     * 
-     */
-    public TagAttributesImpl(TagAttribute[] attrs)
+    public TagAttributesImpl(TagAttribute[] attributes)
     {
-        _attributes = attrs;
-
-        // grab namespaces
-        Set<String> set = new HashSet<String>();
-        for (TagAttribute attribute : _attributes)
-        {
-            set.add(attribute.getNamespace());
-        }
+        this.attributes = attributes;
+        this.namespaceAttributes = new HashMap<>(3);
+        this.namespaceLocalNameAttributes = new HashMap<>(3);
         
-        _namespaces = set.toArray(new String[set.size()]);
-        Arrays.sort(_namespaces);
-
-        // assign attrs
-        int size = _namespaces.length;
-        List<List<TagAttribute>> temp = new ArrayList<List<TagAttribute>>(size);
-        for (int i = 0; i < size; i++)
-        {
-            temp.add(new ArrayList<TagAttribute>());
-        }
+        Set<String> namespacesSet = new HashSet<>();
+        HashMap<String, List<TagAttribute>> namespaceAttributesAsList = new HashMap<>();
         
-        for (TagAttribute attribute : _attributes)
+        for (TagAttribute attribute : attributes)
         {
-            temp.get(Arrays.binarySearch(_namespaces, attribute.getNamespace())).add(attribute);
+            namespacesSet.add(attribute.getNamespace());
+
+            
+            List<TagAttribute> tagAttributes = namespaceAttributesAsList.get(attribute.getNamespace());
+            if (tagAttributes == null)
+            {
+                tagAttributes = new ArrayList<>(attributes.length);
+                namespaceAttributesAsList.put(attribute.getNamespace(), tagAttributes);
+            }
+            tagAttributes.add(attribute);
+            
+            
+            Map<String, TagAttribute> localeNameAttributes = namespaceLocalNameAttributes.get(attribute.getNamespace());
+            if (localeNameAttributes == null)
+            {
+                localeNameAttributes = new HashMap<>(attributes.length);
+                namespaceLocalNameAttributes.put(attribute.getNamespace(), localeNameAttributes);
+            }
+            localeNameAttributes.put(attribute.getLocalName(), attribute);
         }
+
+
+        this.namespaces = namespacesSet.toArray(new String[namespacesSet.size()]);
+        Arrays.sort(this.namespaces);
         
-        _nsattrs = new ArrayList<TagAttribute[]>(size);
-        for (int i = 0; i < size; i++)
+        for (Map.Entry<String, List<TagAttribute>> entry : namespaceAttributesAsList.entrySet())
         {
-            List<TagAttribute> l = temp.get(i);
-            _nsattrs.add(l.toArray(new TagAttribute[l.size()]));
+            String key = entry.getKey();
+            List<TagAttribute> value = entry.getValue();
+            this.namespaceAttributes.put(key, value.toArray(new TagAttribute[value.size()]));
         }
     }
 
@@ -93,19 +95,20 @@ public final class TagAttributesImpl extends TagAttributes
      * 
      * @return a non-null array of TagAttributes
      */
+    @Override
     public TagAttribute[] getAll()
     {
-        return _attributes;
+        return attributes;
     }
 
     /**
      * Using no namespace, find the TagAttribute
      * 
      * See #get(String, String)
-     * @param localName
-     *            tag attribute name
+     * @param localName tag attribute name
      * @return the TagAttribute found, otherwise null
      */
+    @Override
     public TagAttribute get(String localName)
     {
         return get("", localName);
@@ -114,57 +117,33 @@ public final class TagAttributesImpl extends TagAttributes
     /**
      * Find a TagAttribute that matches the passed namespace and local name.
      * 
-     * @param ns
-     *            namespace of the desired attribute
-     * @param localName
-     *            local name of the attribute
+     * @param ns namespace of the desired attribute
+     * @param localName local name of the attribute
      * @return a TagAttribute found, otherwise null
      */
+    @Override
     public TagAttribute get(String ns, String localName)
     {
-        if (ns != null && localName != null)
+        Map<String, TagAttribute> nsAttributes = namespaceLocalNameAttributes.get(ns);
+        if (nsAttributes != null)
         {
-            int idx = Arrays.binarySearch(_namespaces, ns);
-            if (idx >= 0)
-            {
-                for (TagAttribute attribute : _nsattrs.get(idx))
-                {
-                    if (localName.equals(attribute.getLocalName()))
-                    {
-                        return attribute;
-                    }
-                }
-            }
+            return nsAttributes.get(localName);
         }
-        
+
         return null;
     }
 
     /**
      * Get all TagAttributes for the passed namespace
      * 
-     * @param namespace
-     *            namespace to search
+     * @param namespace namespace to search
      * @return a non-null array of TagAttributes
      */
+    @Override
     public TagAttribute[] getAll(String namespace)
     {
-        int idx = 0;
-        if (namespace == null)
-        {
-            idx = Arrays.binarySearch(_namespaces, "");
-        }
-        else
-        {
-            idx = Arrays.binarySearch(_namespaces, namespace);
-        }
-        
-        if (idx >= 0)
-        {
-            return _nsattrs.get(idx);
-        }
-        
-        return EMPTY;
+        TagAttribute[] retVal = namespaceAttributes.get(namespace);
+        return retVal == null ? EMPTY : retVal;
     }
 
     /**
@@ -172,9 +151,10 @@ public final class TagAttributesImpl extends TagAttributes
      * 
      * @return a list of Namespaces found in this set
      */
+    @Override
     public String[] getNamespaces()
     {
-        return _namespaces;
+        return namespaces;
     }
 
     /*
@@ -185,8 +165,8 @@ public final class TagAttributesImpl extends TagAttributes
     @Override
     public String toString()
     {
-        StringBuffer sb = new StringBuffer();
-        for (TagAttribute attribute : _attributes)
+        StringBuilder sb = new StringBuilder();
+        for (TagAttribute attribute : attributes)
         {
             sb.append(attribute);
             sb.append(' ');
diff --git a/impl/src/test/java/org/apache/myfaces/view/facelets/tag/TagAttributesImplTest.java b/impl/src/test/java/org/apache/myfaces/view/facelets/tag/TagAttributesImplTest.java
new file mode 100644
index 0000000..86f5717
--- /dev/null
+++ b/impl/src/test/java/org/apache/myfaces/view/facelets/tag/TagAttributesImplTest.java
@@ -0,0 +1,59 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.myfaces.view.facelets.tag;
+
+import java.util.Arrays;
+import javax.faces.view.facelets.TagAttribute;
+import org.junit.Assert;
+import org.junit.Test;
+
+public class TagAttributesImplTest
+{
+    @Test
+    public void testNamespaceMapping()
+    {
+        TagAttributeImpl test1 = new TagAttributeImpl(null, "", "test1", null, "");
+        TagAttributeImpl test2 = new TagAttributeImpl(null, "", "test2", null, "");
+        TagAttributeImpl testTest1 = new TagAttributeImpl(null, "test", "test1", null, "");
+        
+        TagAttributesImpl impl = new TagAttributesImpl(new TagAttribute[] { test1, test2, testTest1 });
+        Assert.assertEquals(test1, impl.get("test1"));
+        Assert.assertEquals(test2, impl.get("test2"));
+        
+        Assert.assertEquals(testTest1, impl.get("test", "test1"));
+
+        
+        Assert.assertEquals(3, Arrays.asList(impl.getAll()).size());
+        Assert.assertTrue(Arrays.asList(impl.getAll()).contains(test1));
+        Assert.assertTrue(Arrays.asList(impl.getAll()).contains(test2));
+        Assert.assertTrue(Arrays.asList(impl.getAll()).contains(testTest1));
+        
+        Assert.assertEquals(2, Arrays.asList(impl.getAll("")).size());
+        Assert.assertTrue(Arrays.asList(impl.getAll()).contains(test1));
+        Assert.assertTrue(Arrays.asList(impl.getAll()).contains(test2));
+    }
+    
+    @Test
+    public void testNotAvailable()
+    {
+        TagAttributesImpl impl = new TagAttributesImpl(new TagAttribute[] { });
+        Assert.assertEquals(null, impl.get("test1"));
+        Assert.assertEquals(null, impl.get("test", "test2"));
+    }
+}