You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@myfaces.apache.org by lu...@apache.org on 2012/03/06 17:58:54 UTC
svn commit: r1297574 - in
/myfaces/core/branches/2.0.x/api/src/main/java/javax/faces/component:
UIComponent.java UIComponentBase.java UIInput.java _ArrayMap.java
_ComponentFacetMap.java behavior/BehaviorBase.java
Author: lu4242
Date: Tue Mar 6 16:58:54 2012
New Revision: 1297574
URL: http://svn.apache.org/viewvc?rev=1297574&view=rev
Log:
MYFACES-3435 [perf] _DeltaList: use ArrayList as parent (adjust size of structures to match typical values and replace HashMap with alternative ArrayMap).
Added:
myfaces/core/branches/2.0.x/api/src/main/java/javax/faces/component/_ArrayMap.java (with props)
Modified:
myfaces/core/branches/2.0.x/api/src/main/java/javax/faces/component/UIComponent.java
myfaces/core/branches/2.0.x/api/src/main/java/javax/faces/component/UIComponentBase.java
myfaces/core/branches/2.0.x/api/src/main/java/javax/faces/component/UIInput.java
myfaces/core/branches/2.0.x/api/src/main/java/javax/faces/component/_ComponentFacetMap.java
myfaces/core/branches/2.0.x/api/src/main/java/javax/faces/component/behavior/BehaviorBase.java
Modified: myfaces/core/branches/2.0.x/api/src/main/java/javax/faces/component/UIComponent.java
URL: http://svn.apache.org/viewvc/myfaces/core/branches/2.0.x/api/src/main/java/javax/faces/component/UIComponent.java?rev=1297574&r1=1297573&r2=1297574&view=diff
==============================================================================
--- myfaces/core/branches/2.0.x/api/src/main/java/javax/faces/component/UIComponent.java (original)
+++ myfaces/core/branches/2.0.x/api/src/main/java/javax/faces/component/UIComponent.java Tue Mar 6 16:58:54 2012
@@ -789,7 +789,9 @@ public abstract class UIComponent implem
// Make sure the list for class exists
if (listeners == null)
{
- listeners = new _DeltaList<SystemEventListener>(new ArrayList<SystemEventListener>(2));
+ // how many listeners per event type can single component have?
+ // We use 3 here as expected number, but it is a question
+ listeners = new _DeltaList<SystemEventListener>(new ArrayList<SystemEventListener>(3));
_systemEventListenerClassMap.put(eventClass, listeners);
}
Modified: myfaces/core/branches/2.0.x/api/src/main/java/javax/faces/component/UIComponentBase.java
URL: http://svn.apache.org/viewvc/myfaces/core/branches/2.0.x/api/src/main/java/javax/faces/component/UIComponentBase.java?rev=1297574&r1=1297573&r2=1297574&view=diff
==============================================================================
--- myfaces/core/branches/2.0.x/api/src/main/java/javax/faces/component/UIComponentBase.java (original)
+++ myfaces/core/branches/2.0.x/api/src/main/java/javax/faces/component/UIComponentBase.java Tue Mar 6 16:58:54 2012
@@ -359,7 +359,9 @@ public abstract class UIComponentBase ex
List<ClientBehavior> behaviorsForEvent = _behaviorsMap.get(eventName);
if(behaviorsForEvent == null)
{
- behaviorsForEvent = new _DeltaList<ClientBehavior>(new ArrayList<ClientBehavior>());
+ // Normally have client only 1 client behaviour per event name,
+ // so size 2 must be sufficient:
+ behaviorsForEvent = new _DeltaList<ClientBehavior>(new ArrayList<ClientBehavior>(2));
_behaviorsMap.put(eventName, behaviorsForEvent);
}
@@ -1143,7 +1145,8 @@ public abstract class UIComponentBase ex
}
if (_facesListeners == null)
{
- _facesListeners = new _DeltaList<FacesListener>(new ArrayList<FacesListener>());
+ // How many facesListeners have single component normally?
+ _facesListeners = new _DeltaList<FacesListener>(new ArrayList<FacesListener>(5));
}
_facesListeners.add(listener);
}
Modified: myfaces/core/branches/2.0.x/api/src/main/java/javax/faces/component/UIInput.java
URL: http://svn.apache.org/viewvc/myfaces/core/branches/2.0.x/api/src/main/java/javax/faces/component/UIInput.java?rev=1297574&r1=1297573&r2=1297574&view=diff
==============================================================================
--- myfaces/core/branches/2.0.x/api/src/main/java/javax/faces/component/UIInput.java (original)
+++ myfaces/core/branches/2.0.x/api/src/main/java/javax/faces/component/UIInput.java Tue Mar 6 16:58:54 2012
@@ -786,7 +786,8 @@ public class UIInput extends UIOutput im
if (_validatorList == null)
{
- _validatorList = new _DeltaList<Validator>(new ArrayList<Validator>());
+ //normally add user 0-3 validators:
+ _validatorList = new _DeltaList<Validator>(new ArrayList<Validator>(3));
}
_validatorList.add(validator);
Added: myfaces/core/branches/2.0.x/api/src/main/java/javax/faces/component/_ArrayMap.java
URL: http://svn.apache.org/viewvc/myfaces/core/branches/2.0.x/api/src/main/java/javax/faces/component/_ArrayMap.java?rev=1297574&view=auto
==============================================================================
--- myfaces/core/branches/2.0.x/api/src/main/java/javax/faces/component/_ArrayMap.java (added)
+++ myfaces/core/branches/2.0.x/api/src/main/java/javax/faces/component/_ArrayMap.java Tue Mar 6 16:58:54 2012
@@ -0,0 +1,637 @@
+/*
+ * 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 javax.faces.component;
+
+import java.util.AbstractMap;
+import java.util.AbstractSet;
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.NoSuchElementException;
+import java.util.Set;
+
+/**
+ * A Map implementation that stores its contents in a single
+ * array. This approach is significantly faster for small sets of
+ * data than the use of a HashMap or Hashtable, though potentially
+ * much slower for very large sets.
+ * <p>
+ * ArrayMap is optimized for many-reads-few-write. In particular,
+ * it reallocates its array on any insertion or deletion.
+ * <p>
+ * ArrayMap also includes a series of static methods for managing the
+ * Object array. These may be used in place of instantiating an
+ * ArrayMap for clients that don't need a Map implementation.
+ * Clients using these methods must be careful to store the returned
+ * Object array on any mutator method. They also must provide their
+ * own synchronization, if needed. When using these static methods,
+ * clients can opt to search for objects by identity (via
+ * <code>getByIdentity()</code>) instead of equality, while the static
+ * <code>get()</code> method will try identity before equality. This
+ * latter approach is extremely fast but still safe for retrieval of
+ * Strings that have all been interned, especially if misses are
+ * infrequent (since misses do require a scan using Object.equals()).
+ * It's worth remembering that String constants are always interned,
+ * as required by the language specification.
+ * <p>
+ * @version $Name: $ ($Revision: adfrt/faces/adf-faces-api/src/main/java/oracle/adf/view/faces/util/ArrayMap.java#0 $) $Date: 10-nov-2005.19:08:36 $
+ */
+// -= Simon Lessard =-
+// Using a single array for both the key and the value leads to many
+// problems, especially with type safety. Using parallel arrays or
+// a single array containing nodes would be a much cleaner/safer idea.
+// =-= AdamWiner =-=
+// True, but the whole point of this class is maximal efficiency for
+// small, transient arrays. The type safety problems are entirely internal,
+// not exposed to clients. Parallel arrays or arrays containing nodes
+// would be less efficient - if you're willing to allocate bonus objects,
+// and don't care about efficiency, just use HashMap.
+class _ArrayMap<K, V> extends AbstractMap<K, V> implements Cloneable
+{
+ /**
+ * Creates an empty ArrayMap, preallocating nothing.
+ */
+ public _ArrayMap()
+ {
+ this(0, 1);
+ }
+
+ /**
+ * Creates an ArrayMap, preallocating for a certain size.
+ * @param size the number of elements to pre-allocate for
+ */
+ public _ArrayMap(int size)
+ {
+ this(size, 1);
+ }
+
+ /**
+ * Creates an ArrayMap, preallocating for a certain size.
+ * @param size the number of elements to pre-allocate for
+ * @param increment the number of additional elements to
+ * allocate for when overruning
+ */
+ public _ArrayMap(int size, int increment)
+ {
+ if ((increment < 1) || (size < 0))
+ {
+ throw new IllegalArgumentException();
+ }
+
+ if (size > 0)
+ {
+ _array = new Object[2 * size];
+ }
+
+ _increment = increment;
+ }
+
+ /**
+ * Returns the key at a specific index in the map.
+ */
+ @SuppressWarnings("unchecked")
+ public K getKey(int index)
+ {
+ if ((index < 0) || (index >= size()))
+ {
+ throw new IndexOutOfBoundsException();
+ }
+ return (K) _array[index * 2];
+ }
+
+ /**
+ * Returns the value at a specific index in the map.
+ */
+ @SuppressWarnings("unchecked")
+ public V getValue(int index)
+ {
+ if ((index < 0) || (index >= size()))
+ {
+ throw new IndexOutOfBoundsException();
+ }
+ return (V) _array[index * 2 + 1];
+ }
+
+ /**
+ * Gets the object stored with the given key. Scans first
+ * by object identity, then by object equality.
+ */
+ static public Object get(Object[] array, Object key)
+ {
+ Object o = getByIdentity(array, key);
+ if (o != null)
+ {
+ return o;
+ }
+
+ return getByEquality(array, key);
+ }
+
+ /**
+ * Gets the object stored with the given key, using
+ * only object identity.
+ */
+ static public Object getByIdentity(Object[] array, Object key)
+ {
+ if (array != null)
+ {
+ int length = array.length;
+ for (int i = 0; i < length; i += 2)
+ {
+ if (array[i] == key)
+ {
+ return array[i + 1];
+ }
+ }
+ }
+
+ return null;
+ }
+
+ /**
+ * Gets the object stored with the given key, using
+ * only object equality.
+ */
+ static public Object getByEquality(Object[] array, Object key)
+ {
+ if (array != null)
+ {
+ int length = array.length;
+
+ for (int i = 0; i < length; i += 2)
+ {
+ Object targetKey = array[i];
+ if (targetKey == null)
+ {
+ return null;
+ }
+ else if (targetKey.equals(key))
+ {
+ return array[i + 1];
+ }
+ }
+ }
+
+ return null;
+ }
+
+ /**
+ * Adds the key/value pair to the array, returning a
+ * new array if necessary.
+ */
+ static public Object[] put(Object[] array, Object key, Object value)
+ {
+ if (array != null)
+ {
+ int length = array.length;
+
+ for (int i = 0; i < length; i += 2)
+ {
+ Object curKey = array[i];
+
+ if (((curKey != null) && (curKey.equals(key)))
+ || (curKey == key))
+ {
+ array[i + 1] = value;
+ return array;
+ }
+ }
+ }
+
+ return _addToArray(array, key, value, 1);
+ }
+
+ /**
+ * Removes the value for the key from the array, returning a
+ * new array if necessary.
+ */
+ static public Object[] remove(Object[] array, Object key)
+ {
+ return remove(array, key, true);
+ }
+
+ /**
+ * Removes the value for the key from the array, returning a
+ * new array if necessary.
+ */
+ static public Object[] remove(Object[] array, Object key, boolean reallocate)
+ {
+ if (array != null)
+ {
+ int length = array.length;
+
+ for (int i = 0; i < length; i += 2)
+ {
+ Object curKey = array[i];
+
+ if (((curKey != null) && curKey.equals(key)) || (curKey == key))
+ {
+ Object[] newArray = array;
+
+ if (reallocate)
+ {
+ newArray = new Object[length - 2];
+ System.arraycopy(array, 0, newArray, 0, i);
+ }
+
+ System.arraycopy(array, i + 2, newArray, i, length - i - 2);
+
+ if (!reallocate)
+ {
+ array[length - 1] = null;
+ array[length - 2] = null;
+ }
+
+ return newArray;
+ }
+ }
+ }
+
+ return array;
+ }
+
+ //
+ // GENERIC MAP API
+ //
+ @Override
+ public int size()
+ {
+ return _size;
+ }
+
+ @Override
+ public boolean containsValue(Object value)
+ {
+ int entryCount = size() * 2;
+ for (int i = 0; i < entryCount; i += 2)
+ {
+ if (_equals(value, _array[i + 1]))
+ {
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ @Override
+ public boolean containsKey(Object key)
+ {
+ int entryCount = size() * 2;
+ for (int i = 0; i < entryCount; i += 2)
+ {
+ if (_equals(key, _array[i]))
+ {
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ /**
+ * Returns an enumeration of the keys in this map.
+ * the Iterator methods on the returned object to fetch the elements
+ * sequentially.
+ */
+ @SuppressWarnings("unchecked")
+ public Iterator<K> keys()
+ {
+ int size = _size;
+
+ if (size == 0)
+ {
+ return null;
+ }
+ ArrayList<K> keyList = new ArrayList<K>();
+ int i = (size - 1) * 2;
+ while (i >= 0)
+ {
+ keyList.add((K) _array[i]);
+ i = i - 2;
+ }
+ return keyList.iterator();
+ }
+
+ /**
+ * Returns an Iterator of keys in the array.
+ */
+ public static Iterator<Object> getKeys(Object[] array)
+ {
+ if (array == null)
+ {
+ return null;
+ }
+ ArrayList<Object> keyList = new ArrayList<Object>();
+ int i = array.length - 2;
+ while (i >= 0)
+ {
+ keyList.add(array[i]);
+ i = i - 2;
+ }
+ return keyList.iterator();
+ }
+
+ /**
+ * Returns an Iterator of values in the array.
+ */
+ public static Iterator<Object> getValues(Object[] array)
+ {
+ if (array == null)
+ {
+ return null;
+ }
+ ArrayList<Object> valueList = new ArrayList<Object>();
+ int i = array.length - 1;
+ while (i >= 0)
+ {
+ valueList.add(array[i]);
+ i = i - 2;
+ }
+ return valueList.iterator();
+ }
+
+ /**
+ * Clones the map.
+ */
+ @SuppressWarnings("unchecked")
+ @Override
+ public Object clone()
+ {
+ try
+ {
+ _ArrayMap<K, V> am = (_ArrayMap<K, V>) super.clone();
+
+ am._array = _array.clone();
+ am._size = _size;
+ am._increment = _increment;
+ return am;
+ }
+ catch (CloneNotSupportedException cnse)
+ {
+ // Should never reach here
+ return null;
+ }
+ }
+
+ @Override
+ public Set<Map.Entry<K, V>> entrySet()
+ {
+ if (_entrySet == null)
+ {
+ _entrySet = new AbstractSet<Map.Entry<K, V>>()
+ {
+ @Override
+ public int size()
+ {
+ return _ArrayMap.this.size();
+ }
+
+ @Override
+ public Iterator<Map.Entry<K, V>> iterator()
+ {
+ return new Iterator<Map.Entry<K, V>>()
+ {
+ public boolean hasNext()
+ {
+ return (_index < _ArrayMap.this.size());
+ }
+
+ public void remove()
+ {
+ // remove() removes the last entry returned by next(),
+ // not the one about to be seen; so that's actually
+ // the entry at (_index - 1).
+ if ((_index == 0) || _removed)
+ {
+ throw new IllegalStateException();
+ }
+
+ _removed = true;
+ // Shrink the array by one
+ int size = _ArrayMap.this.size();
+ Object[] array = _ArrayMap.this._array;
+ if (size > _index)
+ {
+ System.arraycopy(array, _index * 2, array,
+ (_index - 1) * 2, (size - _index) * 2);
+ }
+
+ // Null out the last elements (for GC)
+ array[size * 2 - 2] = null;
+ array[size * 2 - 1] = null;
+
+ _ArrayMap.this._size = size - 1;
+
+ // And push the index back one
+ _index = _index - 1;
+ }
+
+ public Map.Entry<K, V> next()
+ {
+ if (!hasNext())
+ {
+ throw new NoSuchElementException();
+ }
+
+ final int index = _index;
+ _removed = false;
+ _index = index + 1;
+
+ return new Map.Entry<K, V>()
+ {
+ public K getKey()
+ {
+ return _ArrayMap.this.getKey(index);
+ }
+
+ public V getValue()
+ {
+ return _ArrayMap.this.getValue(index);
+ }
+
+ public V setValue(V value)
+ {
+ V oldValue = getValue();
+ _ArrayMap.this._array[index * 2 + 1] = value;
+ return oldValue;
+ }
+
+ @SuppressWarnings("unchecked")
+ @Override
+ public boolean equals(Object o)
+ {
+ if (!(o instanceof Map.Entry))
+ {
+ return false;
+ }
+ Map.Entry<K, V> e = (Map.Entry<K, V>) o;
+ return _equals(getKey(), e.getKey())
+ && _equals(getValue(), e.getValue());
+ }
+
+ @Override
+ public int hashCode()
+ {
+ Object key = getKey();
+ Object value = getValue();
+ return ((key == null) ? 0 : key.hashCode())
+ ^ ((value == null) ? 0 : value
+ .hashCode());
+ }
+ };
+ }
+
+ private int _index;
+ private boolean _removed;
+ };
+ }
+ };
+ }
+
+ return _entrySet;
+ }
+
+ @SuppressWarnings("unchecked")
+ @Override
+ public V get(Object key)
+ {
+ return (V) getByEquality(_array, key);
+ //return getByIdentity(_array, key);
+ }
+
+ @SuppressWarnings("unchecked")
+ public V getByIdentity(Object key)
+ {
+ return (V) getByIdentity(_array, key);
+ }
+
+ @SuppressWarnings("unchecked")
+ @Override
+ public V put(K key, V value)
+ {
+ if (value == null)
+ {
+ return remove(key);
+ }
+
+ Object[] array = _array;
+ // Use getByEquality(). In the vast majority
+ // of cases, the object isn't there. So getByIdentity()
+ // will fail, and we'll call getByEquality() anyway.
+ Object o = getByEquality(array, key);
+
+ if (o == null)
+ {
+ int size = _size * 2;
+ if ((array != null) && (size < array.length))
+ {
+ array[size] = key;
+ array[size + 1] = value;
+ }
+ else
+ {
+ _array = _addToArray(array, key, value, _increment);
+ }
+
+ _size = _size + 1;
+ }
+ else
+ {
+ // (Actually, I know in this case that the returned array
+ // isn't going to change, but that'd be a good way to introduce
+ // a bug if we ever to change the implementation)
+ _array = put(array, key, value);
+ }
+
+ return (V) o;
+ }
+
+ @SuppressWarnings("unchecked")
+ @Override
+ public V remove(Object key)
+ {
+ Object[] array = _array;
+ Object o = get(array, key);
+ if (o != null)
+ {
+ remove(array, key, false);
+ _size = _size - 1;
+ }
+
+ return (V) o;
+ }
+
+ /**
+ * Removes all elements from the ArrayMap.
+ */
+ @Override
+ public void clear()
+ {
+ int size = _size;
+ if (size > 0)
+ {
+ size = size * 2;
+ for (int i = 0; i < size; i++)
+ {
+ _array[i] = null;
+ }
+
+ _size = 0;
+ }
+ }
+
+ /**
+ * Adds the key/value pair to the array, returning a
+ * new array if necessary.
+ */
+ private static Object[] _addToArray(Object[] array, Object key,
+ Object value, int increment)
+ {
+ Object[] newArray = null;
+ if (array != null)
+ {
+ int length = array.length;
+ newArray = new Object[length + (2 * increment)];
+ System.arraycopy(array, 0, newArray, 2, length);
+ }
+ else
+ {
+ newArray = new Object[2 * increment];
+ }
+
+ newArray[0] = key;
+ newArray[1] = value;
+ return newArray;
+ }
+
+ private static boolean _equals(Object a, Object b)
+ {
+ if (a == null)
+ {
+ return b == null;
+ }
+ return a.equals(b);
+ }
+
+ private Object[] _array;
+ private int _size;
+ private int _increment;
+ private Set<Map.Entry<K, V>> _entrySet;
+}
Propchange: myfaces/core/branches/2.0.x/api/src/main/java/javax/faces/component/_ArrayMap.java
------------------------------------------------------------------------------
svn:eol-style = native
Modified: myfaces/core/branches/2.0.x/api/src/main/java/javax/faces/component/_ComponentFacetMap.java
URL: http://svn.apache.org/viewvc/myfaces/core/branches/2.0.x/api/src/main/java/javax/faces/component/_ComponentFacetMap.java?rev=1297574&r1=1297573&r2=1297574&view=diff
==============================================================================
--- myfaces/core/branches/2.0.x/api/src/main/java/javax/faces/component/_ComponentFacetMap.java (original)
+++ myfaces/core/branches/2.0.x/api/src/main/java/javax/faces/component/_ComponentFacetMap.java Tue Mar 6 16:58:54 2012
@@ -22,7 +22,6 @@ import java.io.Serializable;
import java.util.AbstractCollection;
import java.util.AbstractSet;
import java.util.Collection;
-import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
@@ -35,7 +34,7 @@ class _ComponentFacetMap<V extends UICom
{
private static final long serialVersionUID = -3456937594422167629L;
private UIComponent _component;
- private Map<String, V> _map = new HashMap<String, V>();
+ private Map<String, V> _map = new _ArrayMap<String, V>(0,5);
private Set<Entry<String, V>> _entrySet = null;
private Set<String> _keySet = null;
private Collection<V> _valueCollection = null;
Modified: myfaces/core/branches/2.0.x/api/src/main/java/javax/faces/component/behavior/BehaviorBase.java
URL: http://svn.apache.org/viewvc/myfaces/core/branches/2.0.x/api/src/main/java/javax/faces/component/behavior/BehaviorBase.java?rev=1297574&r1=1297573&r2=1297574&view=diff
==============================================================================
--- myfaces/core/branches/2.0.x/api/src/main/java/javax/faces/component/behavior/BehaviorBase.java (original)
+++ myfaces/core/branches/2.0.x/api/src/main/java/javax/faces/component/behavior/BehaviorBase.java Tue Mar 6 16:58:54 2012
@@ -267,8 +267,9 @@ public class BehaviorBase implements Beh
if (_behaviorListeners == null)
{
- // Lazy instanciation
- _behaviorListeners = new _DeltaList<BehaviorListener>(new ArrayList<BehaviorListener>());
+ // Lazy instanciation with size 1:
+ // the only posibility how to add listener is <f:ajax listener="" /> - there is no <f:ajaxListener/> tag
+ _behaviorListeners = new _DeltaList<BehaviorListener>(new ArrayList<BehaviorListener>(1));
}
_behaviorListeners.add(listener);