You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@wicket.apache.org by jc...@apache.org on 2008/03/03 17:19:18 UTC

svn commit: r633155 - in /wicket/trunk/jdk-1.4/wicket/src/main/java/org/apache/wicket: MarkupContainer.java markup/html/list/ListView.java

Author: jcompagner
Date: Mon Mar  3 08:19:17 2008
New Revision: 633155

URL: http://svn.apache.org/viewvc?rev=633155&view=rev
Log:
added optimization for remove/add of childs. Now a quick custom list is being used that grows *2. 
But the slow part for large things is still the add that does a linear search to get to the right component(id) 

Modified:
    wicket/trunk/jdk-1.4/wicket/src/main/java/org/apache/wicket/MarkupContainer.java
    wicket/trunk/jdk-1.4/wicket/src/main/java/org/apache/wicket/markup/html/list/ListView.java

Modified: wicket/trunk/jdk-1.4/wicket/src/main/java/org/apache/wicket/MarkupContainer.java
URL: http://svn.apache.org/viewvc/wicket/trunk/jdk-1.4/wicket/src/main/java/org/apache/wicket/MarkupContainer.java?rev=633155&r1=633154&r2=633155&view=diff
==============================================================================
--- wicket/trunk/jdk-1.4/wicket/src/main/java/org/apache/wicket/MarkupContainer.java (original)
+++ wicket/trunk/jdk-1.4/wicket/src/main/java/org/apache/wicket/MarkupContainer.java Mon Mar  3 08:19:17 2008
@@ -16,6 +16,7 @@
  */
 package org.apache.wicket;
 
+import java.util.AbstractList;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Collections;
@@ -469,6 +470,10 @@
 				sorted = new ArrayList(1);
 				sorted.add(children);
 			}
+			else if (children instanceof ChildList)
+			{
+				sorted = new ArrayList((ChildList)children);
+			}
 			else
 			{
 				sorted = Arrays.asList((Component[])children);
@@ -574,13 +579,17 @@
 			int size = children_size();
 			for (int i = 0; i < size; i++)
 			{
-				// Get next child
-				final Component child = children_get(i);
+				Object childObject = children_get(i, false);
+				if (childObject instanceof Component)
+				{
+					// Get next child
+					final Component child = (Component)childObject;
 
-				// Do not call remove() because the state change would than be
-				// recorded twice.
-				child.detachModel();
-				child.setParent(null);
+					// Do not call remove() because the state change would than be
+					// recorded twice.
+					child.detachModel();
+					child.setParent(null);
+				}
 			}
 
 			children = null;
@@ -917,23 +926,12 @@
 		}
 		else
 		{
-			// Get current list size
-			final int size = children_size();
-
-			// Create array that holds size + 1 elements
-			final Object[] children = new Object[size + 1];
-
-			// Loop through existing children copying them
-			for (int i = 0; i < size; i++)
+			if (!(children instanceof ChildList))
 			{
-				children[i] = children_get(i, false);
+				// Save new children
+				children = new ChildList(children);
 			}
-
-			// Add new child to the end
-			children[size] = child;
-
-			// Save new children
-			this.children = children;
+			((ChildList)children).add(child);
 		}
 	}
 
@@ -966,25 +964,39 @@
 	private final Object children_get(int index, boolean reconstruct)
 	{
 		Object component = null;
-		if (index == 0 && children != null && children instanceof Object[] == false)
+		if (children != null)
 		{
-			component = postprocess(children, reconstruct, this, 0);
-			if (children != component)
+			if (children instanceof Object[] == false && children instanceof ChildList == false)
 			{
-				children = component;
+				if (index != 0)
+					throw new ArrayIndexOutOfBoundsException("index " + index +
+						" is greater then 0");
+				component = postprocess(children, reconstruct, this, 0);
+				if (children != component)
+				{
+					children = component;
+				}
 			}
-		}
-		else
-		{
-			// we have a list
-			Object[] children = (Object[])this.children;
-			component = postprocess(children[index], reconstruct, this, index);
-			if (children[index] != component)
+			else
 			{
-				children[index] = component;
+				Object[] children = null;
+				if (this.children instanceof ChildList)
+				{
+					// we have a list
+					children = ((ChildList)this.children).childs;
+				}
+				else
+				{
+					// we have a object array
+					children = (Object[])this.children;
+				}
+				component = postprocess(children[index], reconstruct, this, index);
+				if (children[index] != component)
+				{
+					children[index] = component;
+				}
 			}
 		}
-
 		return component;
 	}
 
@@ -1013,30 +1025,46 @@
 
 	private final Component children_get(final String id)
 	{
+		if (children == null)
+		{
+			return null;
+		}
 		Component component = null;
-		if (children != null && children instanceof Object[] == false && getId(children).equals(id))
+		if (children instanceof Object[] == false && children instanceof List == false)
 		{
-			component = (Component)postprocess(children, true, this, 0);
-			if (children != component)
+			if (getId(children).equals(id))
 			{
-				children = component;
+				component = (Component)postprocess(children, true, this, 0);
+				if (children != component)
+				{
+					children = component;
+				}
 			}
 		}
-		else if (children instanceof Object[])
+		else
 		{
-			final Object[] children = (Object[])this.children;
+			Object[] children = null;
+			int size = 0;
+			if (this.children instanceof ChildList)
+			{
+				children = ((ChildList)this.children).childs;
+				size = ((ChildList)this.children).size;
+			}
+			else
 			{
-				for (int i = 0; i < children.length; i++)
+				children = (Object[])this.children;
+				size = children.length;
+			}
+			for (int i = 0; i < size; i++)
+			{
+				if (getId(children[i]).equals(id))
 				{
-					if (getId(children[i]).equals(id))
+					component = (Component)postprocess(children[i], true, this, i);
+					if (children[i] != component)
 					{
-						component = (Component)postprocess(children[i], true, this, i);
-						if (children[i] != component)
-						{
-							children[i] = component;
-						}
-						break;
+						children[i] = component;
 					}
+					break;
 				}
 			}
 		}
@@ -1045,15 +1073,33 @@
 
 	private final int children_indexOf(Component child)
 	{
-		if (children != null && children instanceof Object[] == false &&
-			getId(children).equals(child.getId()))
+		if (children == null)
 		{
-			return 0;
+			return -1;
 		}
-		else if (children instanceof Object[])
+		if (children instanceof Object[] == false && children instanceof ChildList == false)
 		{
-			final Object[] children = (Object[])this.children;
-			for (int i = 0; i < children.length; i++)
+			if (getId(children).equals(child.getId()))
+			{
+				return 0;
+			}
+		}
+		else
+		{
+			int size = 0;
+			Object[] children;
+			if (this.children instanceof Object[])
+			{
+				children = (Object[])this.children;
+				size = children.length;
+			}
+			else
+			{
+				children = ((ChildList)this.children).childs;
+				size = ((ChildList)this.children).size;
+			}
+
+			for (int i = 0; i < size; i++)
 			{
 				if (getId(children[i]).equals(child.getId()))
 				{
@@ -1076,6 +1122,9 @@
 
 	private final Component children_remove(int index)
 	{
+		if (children == null)
+			return null;
+
 		if (children instanceof Component || children instanceof ComponentSourceEntry)
 		{
 			if (index == 0)
@@ -1091,35 +1140,34 @@
 		}
 		else
 		{
-			Object[] c = ((Object[])children);
-			final Object removed = c[index];
-			if (c.length == 2)
-			{
-				if (index == 0)
-				{
-					children = c[1];
-				}
-				else if (index == 1)
-				{
-					children = c[0];
-				}
-				else
-				{
-					throw new IndexOutOfBoundsException();
-				}
-			}
-			else
+			if (children instanceof Object[])
 			{
-				Object[] newChildren = new Object[c.length - 1];
-				int j = 0;
-				for (int i = 0; i < c.length; i++)
+				Object[] c = ((Object[])children);
+				final Object removed = c[index];
+				if (c.length == 2)
 				{
-					if (i != index)
+					if (index == 0)
+					{
+						children = c[1];
+					}
+					else if (index == 1)
 					{
-						newChildren[j++] = c[i];
+						children = c[0];
 					}
+					else
+					{
+						throw new IndexOutOfBoundsException();
+					}
+					return (Component)postprocess(removed, true, null, -1);
 				}
-				children = newChildren;
+				children = new ChildList(children);
+			}
+
+			ChildList lst = (ChildList)children;
+			Object removed = lst.remove(index);
+			if (lst.size == 1)
+			{
+				children = lst.get(0);
 			}
 			return (Component)postprocess(removed, true, null, -1);
 		}
@@ -1128,19 +1176,25 @@
 	private final Object children_set(int index, Object child, boolean reconstruct)
 	{
 		Object replaced;
-		if (index < children_size())
+		if (index >= 0 && index < children_size())
 		{
-			if (children == null || children instanceof Component ||
-				children instanceof ComponentSourceEntry)
+			if (children instanceof Component || children instanceof ComponentSourceEntry)
 			{
 				replaced = children;
 				children = child;
 			}
 			else
 			{
-				final Object[] children = (Object[])this.children;
-				replaced = children[index];
-				children[index] = child;
+				if (children instanceof ChildList)
+				{
+					replaced = ((ChildList)children).set(index, child);
+				}
+				else
+				{
+					final Object[] children = (Object[])this.children;
+					replaced = children[index];
+					children[index] = child;
+				}
 			}
 		}
 		else
@@ -1167,6 +1221,10 @@
 			{
 				return 1;
 			}
+			else if (children instanceof ChildList)
+			{
+				return ((ChildList)children).size;
+			}
 			return ((Object[])children).length;
 		}
 	}
@@ -1465,6 +1523,13 @@
 				}
 			}
 		}
+		if (children instanceof ChildList)
+		{
+			ChildList lst = (ChildList)children;
+			Object[] tmp = new Object[lst.size];
+			System.arraycopy(lst.childs, 0, tmp, 0, lst.size);
+			children = tmp;
+		}
 	}
 
 	void internalMarkRendering()
@@ -1569,5 +1634,100 @@
 				return IVisitor.CONTINUE_TRAVERSAL;
 			}
 		});
+	}
+
+	private static class ChildList extends AbstractList
+	{
+		private int size;
+		private Object[] childs;
+
+		/**
+		 * Construct.
+		 * 
+		 * @param children
+		 */
+		public ChildList(Object children)
+		{
+			if (children instanceof Object[])
+			{
+				childs = (Object[])children;
+				size = childs.length;
+			}
+			else
+			{
+				childs = new Object[3];
+				add(children);
+			}
+		}
+
+		public Object get(int index)
+		{
+			return childs[index];
+		}
+
+		public int size()
+		{
+			return size;
+		}
+
+		public boolean add(Object o)
+		{
+			ensureCapacity(size + 1);
+			childs[size++] = o;
+			return true;
+		}
+
+		public void add(int index, Object element)
+		{
+			if (index > size || index < 0)
+				throw new IndexOutOfBoundsException("Index: " + index + ", Size: " + size);
+
+			ensureCapacity(size + 1);
+			System.arraycopy(childs, index, childs, index + 1, size - index);
+			childs[index] = element;
+			size++;
+		}
+
+		public Object set(int index, Object element)
+		{
+			if (index >= size)
+				throw new IndexOutOfBoundsException("Index: " + index + ", Size: " + size);
+
+			Object oldValue = childs[index];
+			childs[index] = element;
+			return oldValue;
+		}
+
+		public Object remove(int index)
+		{
+			if (index >= size)
+				throw new IndexOutOfBoundsException("Index: " + index + ", Size: " + size);
+
+			Object oldValue = childs[index];
+
+			int numMoved = size - index - 1;
+			if (numMoved > 0)
+				System.arraycopy(childs, index + 1, childs, index, numMoved);
+			childs[--size] = null; // Let gc do its work
+
+			return oldValue;
+		}
+
+		/**
+		 * @param minCapacity
+		 */
+		public void ensureCapacity(int minCapacity)
+		{
+			int oldCapacity = childs.length;
+			if (minCapacity > oldCapacity)
+			{
+				Object oldData[] = childs;
+				int newCapacity = oldCapacity * 2;
+				if (newCapacity < minCapacity)
+					newCapacity = minCapacity;
+				childs = new Object[newCapacity];
+				System.arraycopy(oldData, 0, childs, 0, size);
+			}
+		}
 	}
 }

Modified: wicket/trunk/jdk-1.4/wicket/src/main/java/org/apache/wicket/markup/html/list/ListView.java
URL: http://svn.apache.org/viewvc/wicket/trunk/jdk-1.4/wicket/src/main/java/org/apache/wicket/markup/html/list/ListView.java?rev=633155&r1=633154&r2=633155&view=diff
==============================================================================
--- wicket/trunk/jdk-1.4/wicket/src/main/java/org/apache/wicket/markup/html/list/ListView.java (original)
+++ wicket/trunk/jdk-1.4/wicket/src/main/java/org/apache/wicket/markup/html/list/ListView.java Mon Mar  3 08:19:17 2008
@@ -141,7 +141,7 @@
 		if (model == null)
 		{
 			throw new IllegalArgumentException(
-					"Null models are not allowed. If you have no model, you may prefer a Loop instead");
+				"Null models are not allowed. If you have no model, you may prefer a Loop instead");
 		}
 
 		// A reasonable default for viewSize can not be determined right now,
@@ -236,7 +236,7 @@
 		if ((Integer.MAX_VALUE - size) < firstIndex)
 		{
 			throw new IllegalStateException(
-					"firstIndex + size must be smaller than Integer.MAX_VALUE");
+				"firstIndex + size must be smaller than Integer.MAX_VALUE");
 		}
 
 		return size;
@@ -549,14 +549,17 @@
 				removeAll();
 			}
 
+			boolean hasChildren = size() != 0;
 			// Loop through the markup in this container for each item
 			for (int i = 0; i < size; i++)
 			{
 				// Get index
 				final int index = firstIndex + i;
 
-				// If this component does not already exist, populate it
-				ListItem item = (ListItem)get(Integer.toString(index));
+				ListItem item = null;
+				if (hasChildren)
+					// If this component does not already exist, populate it
+					item = (ListItem)get(Integer.toString(index));
 				if (item == null)
 				{
 					// Create item for index