classpath-patches
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [cp-patches] FYI: Fix for BoxLayout


From: Roman Kennke
Subject: Re: [cp-patches] FYI: Fix for BoxLayout
Date: Wed, 29 Jun 2005 11:33:18 +0200
User-agent: Mozilla Thunderbird 1.0.2 (X11/20050317)

Hi,

Tom Tromey wrote:

Roman> +  public static Component[] getVisibleChildren(Container c)
Roman> +  {
Roman> +    Component[] children = c.getComponents();
Roman> +    Vector visible = new Vector();
Roman> +    for (int i = 0; i < children.length; i++)
Roman> +      if (children[i].isVisible())
Roman> +        visible.add(children[i]);
Roman> +    return (Component[]) visible.toArray(new Container[visible.size()]);

This means multiple allocations per layout.
I wonder whether that is noticeable in a profile.

I have optimized this. Now no new array is allocated at all. A List implementation is returned instead that iterates over the components and returns only the visible ones. The List itself is cached in a WeakHashMap, so multiple layouts for one Container will reuse the same List impl, still if the Component (more precisely: its children array) is no longer in use, it can be garbage collected. We still have one allocation though: the Iterator. But this is minimal and I regard the overhead of caching this as not worth the effort.

2005-06-29 Roman Kennke <address@hidden>

* gnu/java/awt/AWTUtilities.java
(VisibleComponentList): Added List implementation that iterates over
the child components of a Container and only returns Components
that are actually visible.
(getVisibleChildren): Now returns a List instead of an array. This
list is cached. This greatly decreases allocations in
LayoutManagers.
* javax/swing/BoxLayout.java:
Updated to use the new AWTUtilities.getVisibleChildren() method.

/Roman

Index: javax/swing/BoxLayout.java
===================================================================
RCS file: /cvsroot/classpath/classpath/javax/swing/BoxLayout.java,v
retrieving revision 1.13
diff -u -r1.13 BoxLayout.java
--- javax/swing/BoxLayout.java  27 Jun 2005 14:41:10 -0000      1.13
+++ javax/swing/BoxLayout.java  29 Jun 2005 09:24:30 -0000
@@ -47,6 +47,7 @@
 import java.io.Serializable;
 import java.util.Collection;
 import java.util.Iterator;
+import java.util.List;
 import java.util.Vector;
 
 import gnu.java.awt.AWTUtilities;
@@ -404,16 +405,16 @@
     int x = 0;
     int y = 0;
 
-    Component[] children = AWTUtilities.getVisibleChildren(parent);
+    List children = AWTUtilities.getVisibleChildren(parent);
 
     if (isHorizontalIn(parent))
       {        
         x = insets.left + insets.right;
         // sum up preferred widths of components, find maximum of preferred
         // heights
-        for (int index = 0; index < children.length; index++)
+        for (Iterator i = children.iterator(); i.hasNext();)
           {
-            Component comp = children[index];
+            Component comp = (Component) i.next();
             Dimension sz = comp.getPreferredSize();
             x += sz.width;
             y = Math.max(y, sz.height);
@@ -425,9 +426,9 @@
         y = insets.top + insets.bottom;
         // sum up preferred heights of components, find maximum of
         //  preferred widths
-        for (int index = 0; index < children.length; index++)
+        for (Iterator i = children.iterator(); i.hasNext();)
           {
-            Component comp = children[index];
+            Component comp = (Component) i.next();
             Dimension sz = comp.getPreferredSize();
             y += sz.height;
             x = Math.max(x, sz.width);
@@ -454,15 +455,15 @@
     int x = insets.left + insets.right;
     int y = insets.bottom + insets.top;
 
-    Component[] children = AWTUtilities.getVisibleChildren(parent);
+    List children = AWTUtilities.getVisibleChildren(parent);
 
     if (isHorizontalIn(parent))
       {
         // sum up preferred widths of components, find maximum of preferred
         // heights
-        for (int index = 0; index < children.length; index++)
+        for (Iterator i = children.iterator(); i.hasNext();)
           {
-            Component comp = children[index];
+           Component comp = (Component) i.next();
             Dimension sz = comp.getMinimumSize();
             x += sz.width;
             y = Math.max(y, sz.height);
@@ -472,9 +473,9 @@
       {
         // sum up preferred heights of components, find maximum of
         //  preferred widths
-        for (int index = 0; index < children.length; index++)
+        for (Iterator i = children.iterator(); i.hasNext();)
           {
-            Component comp = children[index];
+           Component comp = (Component) i.next();
             Dimension sz = comp.getMinimumSize();
             y += sz.height;
             x = Math.max(x, sz.width);
@@ -565,16 +566,16 @@
     int x = insets.left + insets.right;
     int y = insets.top + insets.bottom;
 
-    Component[] children = AWTUtilities.getVisibleChildren(parent);
+    List children = AWTUtilities.getVisibleChildren(parent);
 
     if (isHorizontalIn(parent))
       {
         
         // sum up preferred widths of components, find maximum of preferred
         // heights
-        for (int index = 0; index < children.length; index++)
+        for (Iterator i = children.iterator(); i.hasNext();)
           {
-            Component comp = children[index];
+            Component comp = (Component) i.next();
             Dimension sz = comp.getMaximumSize();
             x += sz.width;
             // Check for overflow.
@@ -587,9 +588,9 @@
       {
         // sum up preferred heights of components, find maximum of
         //  preferred widths
-        for (int index = 0; index < children.length; index++)
+        for (Iterator i = children.iterator(); i.hasNext();)
           {
-            Component comp = children[index];
+            Component comp = (Component) i.next();
             Dimension sz = comp.getMaximumSize();
             y += sz.height;
             // Check for overflow
@@ -624,12 +625,12 @@
     // Set all components to their preferredSizes and sum up the allocated
     // space. Create SizeReqs for each component and store them in
     // sizeReqs. Find the maximum size in the crossing direction.
-    Component[] children = AWTUtilities.getVisibleChildren(parent);
+    List children = AWTUtilities.getVisibleChildren(parent);
     Vector sizeReqs = new Vector();
     int allocated = 0;
-    for (int i = 0; i < children.length; i++)
+    for (Iterator i = children.iterator(); i.hasNext();)
       {
-       Component c = children[i];
+       Component c = (Component) i.next();
        SizeReq sizeReq = new SizeReq(c, layoutDir);
        int preferred = layoutDir.size(c.getPreferredSize());
        sizeReq.size = preferred;
Index: gnu/java/awt/AWTUtilities.java
===================================================================
RCS file: /cvsroot/classpath/classpath/gnu/java/awt/AWTUtilities.java,v
retrieving revision 1.1
diff -u -r1.1 AWTUtilities.java
--- gnu/java/awt/AWTUtilities.java      24 Jun 2005 14:39:49 -0000      1.1
+++ gnu/java/awt/AWTUtilities.java      29 Jun 2005 09:24:30 -0000
@@ -39,7 +39,11 @@
 
 import java.awt.Component;
 import java.awt.Container;
-import java.util.Vector;
+import java.util.AbstractSequentialList;
+import java.util.List;
+import java.util.ListIterator;
+import java.util.NoSuchElementException;
+import java.util.WeakHashMap;
 
 /**
  * This class provides utility methods that are commonly used in AWT
@@ -49,6 +53,248 @@
 {
 
   /**
+   * This List implementation wraps the Component[] returned by
+   * address@hidden Container#getComponents()} and iterates over the visible 
Components
+   * in that array. This class is used in address@hidden #getVisibleChildren}.
+   */
+  static class VisibleComponentList extends AbstractSequentialList
+  {
+    /**
+     * The ListIterator for this List.
+     */
+    class VisibleComponentIterator implements ListIterator
+    {
+      /** The current index in the Component[]. */
+      int index;
+
+      /** The index in the List of visible Components. */
+      int listIndex;
+
+      /**
+       * Creates a new VisibleComponentIterator that starts at the specified
+       * <code>listIndex</code>. The array of Components is searched from
+       * the beginning to find the matching array index.
+       *
+       * @param listIndex the index from where to begin iterating
+       */
+      VisibleComponentIterator(int listIndex)
+      {
+       this.listIndex = listIndex;
+       int visibleComponentsFound = 0;
+       for (index = 0; visibleComponentsFound != listIndex; index++)
+         {
+           if (components[index].isVisible())
+             visibleComponentsFound++;
+         }
+      }
+
+      /**
+       * Returns <code>true</code> if there are more visible components in the
+       * array, <code>false</code> otherwise.
+       *
+       * @return <code>true</code> if there are more visible components in the
+       *     array, <code>false</code> otherwise
+       */
+      public boolean hasNext()
+      {
+       boolean hasNext = false;
+       for (int i = index; i < components.length; i++)
+         {
+           if (components[i].isVisible())
+             {
+               hasNext = true;
+               break;
+             }
+         }
+       return hasNext;
+      }
+
+      /**
+       * Returns the next visible <code>Component</code> in the List.
+       *
+       * @return the next visible <code>Component</code> in the List
+       *
+       * @throws if there is no next element
+       */
+      public Object next()
+      {
+       Object o = null;
+       for (; index < components.length; index++)
+         {
+           if (components[index].isVisible())
+             {
+               o = components[index];
+               break;
+             }
+         }
+       if (o != null)
+         {
+           index++;
+           listIndex++;
+           return o;
+         }
+       else
+         throw new NoSuchElementException();
+      }
+
+      /**
+       * Returns <code>true</code> if there are more visible components in the
+       * array in the reverse direction, <code>false</code> otherwise.
+       *
+       * @return <code>true</code> if there are more visible components in the
+       *     array in the reverse direction, <code>false</code> otherwise
+       */
+      public boolean hasPrevious()
+      {
+       boolean hasPrevious = false;
+       for (int i = index - 1; i >= 0; i--)
+         {
+           if (components[i].isVisible())
+             {
+               hasPrevious = true;
+               break;
+             }
+         }
+       return hasPrevious;
+      }
+
+      /**
+       * Returns the previous visible <code>Component</code> in the List.
+       *
+       * @return the previous visible <code>Component</code> in the List
+       *
+       * @throws NoSuchElementException if there is no previous element
+       */
+      public Object previous()
+      {
+       Object o = null;
+       for (index--; index >= 0; index--)
+         {
+           if (components[index].isVisible())
+             {
+               o = components[index];
+               break;
+             }
+         }
+       if (o != null)
+         {
+           listIndex--;
+           return o;
+         }
+       else
+         throw new NoSuchElementException();
+      }
+
+      /**
+       * Returns the index of the next element in the List.
+       *
+       * @return the index of the next element in the List
+       */
+      public int nextIndex()
+      {
+       return listIndex + 1;
+      }
+
+      /**
+       * Returns the index of the previous element in the List.
+       *
+       * @return the index of the previous element in the List
+       */
+      public int previousIndex()
+      {
+       return listIndex - 1;
+      }
+
+      /**
+       * This operation is not supported because the List is immutable.
+       *
+       * @throws UnsupportedOperationException because the List is immutable
+       */
+      public void remove()
+      {
+       throw new UnsupportedOperationException
+         ("VisibleComponentList is immutable");
+      }
+
+      /**
+       * This operation is not supported because the List is immutable.
+       *
+       * @param o not used here
+       *
+       * @throws UnsupportedOperationException because the List is immutable
+       */
+      public void set(Object o)
+      {
+       throw new UnsupportedOperationException
+         ("VisibleComponentList is immutable");
+      }
+
+      /**
+       * This operation is not supported because the List is immutable.
+       *
+       * @param o not used here
+       *
+       * @throws UnsupportedOperationException because the List is immutable
+       */
+      public void add(Object o)
+      {
+       throw new UnsupportedOperationException
+         ("VisibleComponentList is immutable");
+      }
+    }
+
+    /**
+     * The components over which we iterate. Only the visible components
+     * are returned by this List.
+     */
+    Component[] components;
+
+    /**
+     * Creates a new instance of VisibleComponentList that wraps the specified
+     * <code>Component[]</code>.
+     *
+     * @param c the <code>Component[]</code> to be wrapped.
+     */
+    VisibleComponentList(Component[] c)
+    {
+      components = c;
+    }
+
+    /**
+     * Returns a address@hidden ListIterator} for iterating over this List.
+     *
+     * @return a address@hidden ListIterator} for iterating over this List
+     */
+    public ListIterator listIterator(int index)
+    {
+      return new VisibleComponentIterator(index);
+    }
+
+    /**
+     * Returns the number of visible components in the wrapped Component[].
+     *
+     * @return the number of visible components
+     */
+    public int size()
+    {
+      int visibleComponents = 0;
+      for (int i = 0; i < components.length; i++)
+       if (components[i].isVisible())
+         visibleComponents++;
+      return visibleComponents;
+    }
+  }
+
+  /**
+   * The cache for our List instances. We try to hold one instance of
+   * VisibleComponentList for each Component[] that is requested. Note
+   * that we use a WeakHashMap for caching, so that the cache itself
+   * does not keep the array or the List from beeing garbage collected
+   * if no other objects hold references to it.
+   */
+  static WeakHashMap visibleChildrenCache = new WeakHashMap();
+
+  /**
    * Returns the visible children of a address@hidden Container}. This method 
is
    * commonly needed in LayoutManagers, because they only have to layout
    * the visible children of a Container.
@@ -57,13 +303,19 @@
    *
    * @return the visible children of <code>c</code>
    */
-  public static Component[] getVisibleChildren(Container c)
+  public static List getVisibleChildren(Container c)
   {
     Component[] children = c.getComponents();
-    Vector visible = new Vector();
-    for (int i = 0; i < children.length; i++)
-      if (children[i].isVisible())
-        visible.add(children[i]);
-    return (Component[]) visible.toArray(new Container[visible.size()]);
+    Object o = visibleChildrenCache.get(children);
+    VisibleComponentList visibleChildren = null;
+    if (o == null)
+      {
+       visibleChildren = new VisibleComponentList(children);
+       visibleChildrenCache.put(children, visibleChildren);
+      }
+    else
+      visibleChildren = (VisibleComponentList) o;
+
+    return visibleChildren;
   }
 }

reply via email to

[Prev in Thread] Current Thread [Next in Thread]