[jbosscache-commits] JBoss Cache SVN: r6377 - in core/trunk/src/main/java/org/jboss/cache: buddyreplication and 6 other directories.
jbosscache-commits at lists.jboss.org
jbosscache-commits at lists.jboss.org
Wed Jul 23 10:23:32 EDT 2008
Author: manik.surtani at jboss.com
Date: 2008-07-23 10:23:32 -0400 (Wed, 23 Jul 2008)
New Revision: 6377
Added:
core/trunk/src/main/java/org/jboss/cache/util/ImmutableListCopy.java
core/trunk/src/main/java/org/jboss/cache/util/ImmutableMapCopy.java
core/trunk/src/main/java/org/jboss/cache/util/ImmutableSetCopy.java
Modified:
core/trunk/src/main/java/org/jboss/cache/Fqn.java
core/trunk/src/main/java/org/jboss/cache/UnversionedNode.java
core/trunk/src/main/java/org/jboss/cache/buddyreplication/BuddyGroup.java
core/trunk/src/main/java/org/jboss/cache/commands/read/GetDataMapCommand.java
core/trunk/src/main/java/org/jboss/cache/invocation/AbstractInvocationContext.java
core/trunk/src/main/java/org/jboss/cache/invocation/CacheInvocationDelegate.java
core/trunk/src/main/java/org/jboss/cache/loader/AbstractCacheLoader.java
core/trunk/src/main/java/org/jboss/cache/loader/AsyncCacheLoader.java
core/trunk/src/main/java/org/jboss/cache/notifications/NotifierImpl.java
core/trunk/src/main/java/org/jboss/cache/transaction/PessimisticTransactionContext.java
core/trunk/src/main/java/org/jboss/cache/util/MapCopy.java
Log:
Implemented efficient custom collections in place of immutable and defensively copied collections
Modified: core/trunk/src/main/java/org/jboss/cache/Fqn.java
===================================================================
--- core/trunk/src/main/java/org/jboss/cache/Fqn.java 2008-07-23 13:46:30 UTC (rev 6376)
+++ core/trunk/src/main/java/org/jboss/cache/Fqn.java 2008-07-23 14:23:32 UTC (rev 6377)
@@ -8,6 +8,7 @@
import net.jcip.annotations.Immutable;
+import org.jboss.cache.util.ImmutableListCopy;
import java.io.Externalizable;
import java.io.IOException;
@@ -112,13 +113,9 @@
{
if (names != null)
{
+ assertNoWhiteSpace(names);
// if not safe make a defensive copy
- elements = safe ? names : new ArrayList<Object>(names);
- if (elements.size() > 0)
- {
- if (SEPARATOR.equals(elements.get(0))) elements.remove(0);
- if ("".equals(elements.get(0))) elements.remove(0);
- }
+ elements = safe ? names : new ImmutableListCopy<Object>(names);
size = elements.size();
}
else
@@ -128,12 +125,15 @@
}
}
+ private void assertNoWhiteSpace(List<Object> l)
+ {
+ if (l.contains("") || l.contains(SEPARATOR))
+ throw new IllegalArgumentException("Fqn list cannot contain whitespace or the [" + SEPARATOR + "] character!");
+ }
+
protected Fqn(Fqn base, List<Object> relative)
{
- List<Object> elements = new ArrayList<Object>(base.elements.size() + relative.size());
- elements.addAll(base.elements);
- elements.addAll(relative);
- this.elements = elements;
+ elements = new ImmutableListCopy<Object>(base.elements, relative);
size = elements.size();
}
@@ -235,12 +235,12 @@
@SuppressWarnings("unchecked")
public static Fqn fromString(String stringRepresentation)
{
- if (stringRepresentation == null || stringRepresentation.equals(SEPARATOR))
- {
+ if (stringRepresentation == null || stringRepresentation.equals(SEPARATOR) || stringRepresentation.equals(""))
return root();
- }
- List elements = Arrays.asList(stringRepresentation.split("/"));
- return new Fqn(elements, false);
+
+ String toMatch = stringRepresentation.startsWith(SEPARATOR) ? stringRepresentation.substring(1) : stringRepresentation;
+ Object[] el = toMatch.split("/");
+ return new Fqn(new ImmutableListCopy(el), true);
}
/**
@@ -434,7 +434,7 @@
*/
public boolean isDirectChildOf(Fqn parentFqn)
{
- return size == parentFqn.size() - 1 && isChildOf(parentFqn);
+ return size == parentFqn.size() + 1 && isChildOf(parentFqn);
}
/**
Modified: core/trunk/src/main/java/org/jboss/cache/UnversionedNode.java
===================================================================
--- core/trunk/src/main/java/org/jboss/cache/UnversionedNode.java 2008-07-23 13:46:30 UTC (rev 6376)
+++ core/trunk/src/main/java/org/jboss/cache/UnversionedNode.java 2008-07-23 14:23:32 UTC (rev 6377)
@@ -16,8 +16,8 @@
import org.jboss.cache.marshall.MarshalledValue;
import org.jboss.cache.optimistic.DataVersion;
import org.jboss.cache.transaction.GlobalTransaction;
+import org.jboss.cache.util.ImmutableSetCopy;
-import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
@@ -417,7 +417,7 @@
{
return Collections.emptySet();
}
- return Collections.unmodifiableSet(new HashSet<K>(data.keySet()));
+ return new ImmutableSetCopy<K>(data.keySet());
}
public boolean removeChild(Object childName)
@@ -567,7 +567,7 @@
{
if (children != null && !children.isEmpty())
{
- return Collections.unmodifiableSet(new HashSet<NodeSPI<K, V>>((Collection) children.values()));
+ return new ImmutableSetCopy(children.values());
}
else
{
Modified: core/trunk/src/main/java/org/jboss/cache/buddyreplication/BuddyGroup.java
===================================================================
--- core/trunk/src/main/java/org/jboss/cache/buddyreplication/BuddyGroup.java 2008-07-23 13:46:30 UTC (rev 6376)
+++ core/trunk/src/main/java/org/jboss/cache/buddyreplication/BuddyGroup.java 2008-07-23 14:23:32 UTC (rev 6377)
@@ -7,12 +7,11 @@
package org.jboss.cache.buddyreplication;
import net.jcip.annotations.ThreadSafe;
+import org.jboss.cache.util.ImmutableListCopy;
import org.jgroups.Address;
import java.io.Serializable;
-import java.util.ArrayList;
import java.util.Collection;
-import java.util.Collections;
import java.util.Date;
import java.util.List;
import java.util.Vector;
@@ -66,7 +65,7 @@
public List<Address> getBuddies()
{
// defensive copy and immutable.
- return Collections.unmodifiableList(new ArrayList<Address>(buddies));
+ return new ImmutableListCopy<Address>(buddies);
}
protected void addBuddies(Collection<Address> buddies)
Modified: core/trunk/src/main/java/org/jboss/cache/commands/read/GetDataMapCommand.java
===================================================================
--- core/trunk/src/main/java/org/jboss/cache/commands/read/GetDataMapCommand.java 2008-07-23 13:46:30 UTC (rev 6376)
+++ core/trunk/src/main/java/org/jboss/cache/commands/read/GetDataMapCommand.java 2008-07-23 14:23:32 UTC (rev 6377)
@@ -4,7 +4,7 @@
import org.jboss.cache.NodeSPI;
import org.jboss.cache.commands.Visitor;
import org.jboss.cache.invocation.InvocationContext;
-import org.jboss.cache.util.MapCopy;
+import org.jboss.cache.util.ImmutableMapCopy;
/**
* Implements functionality defined by {@link org.jboss.cache.Cache#getData(org.jboss.cache.Fqn)}
@@ -37,7 +37,7 @@
{
NodeSPI n = ctx.lookUpNode(fqn);
if (n == null || n.isDeleted()) return null;
- return new MapCopy(n.getDataDirect());
+ return new ImmutableMapCopy(n.getDataDirect());
}
public Object acceptVisitor(InvocationContext ctx, Visitor visitor) throws Throwable
Modified: core/trunk/src/main/java/org/jboss/cache/invocation/AbstractInvocationContext.java
===================================================================
--- core/trunk/src/main/java/org/jboss/cache/invocation/AbstractInvocationContext.java 2008-07-23 13:46:30 UTC (rev 6376)
+++ core/trunk/src/main/java/org/jboss/cache/invocation/AbstractInvocationContext.java 2008-07-23 14:23:32 UTC (rev 6377)
@@ -14,9 +14,9 @@
import org.jboss.cache.transaction.GlobalTransaction;
import org.jboss.cache.transaction.TransactionContext;
import org.jboss.cache.transaction.TransactionTable;
+import org.jboss.cache.util.ImmutableListCopy;
import javax.transaction.Transaction;
-import java.util.ArrayList;
import java.util.Collections;
import java.util.LinkedHashSet;
import java.util.List;
@@ -118,7 +118,7 @@
{
// first check transactional scope
if (transactionContext != null) return transactionContext.getLocks();
- return invocationLocks == null || invocationLocks.isEmpty() ? Collections.emptyList() : Collections.unmodifiableList(new ArrayList(invocationLocks));
+ return invocationLocks == null || invocationLocks.isEmpty() ? Collections.emptyList() : new ImmutableListCopy(invocationLocks);
}
@SuppressWarnings("unchecked")
Modified: core/trunk/src/main/java/org/jboss/cache/invocation/CacheInvocationDelegate.java
===================================================================
--- core/trunk/src/main/java/org/jboss/cache/invocation/CacheInvocationDelegate.java 2008-07-23 13:46:30 UTC (rev 6376)
+++ core/trunk/src/main/java/org/jboss/cache/invocation/CacheInvocationDelegate.java 2008-07-23 14:23:32 UTC (rev 6377)
@@ -40,12 +40,12 @@
import org.jboss.cache.statetransfer.StateTransferManager;
import org.jboss.cache.transaction.GlobalTransaction;
import org.jboss.cache.transaction.TransactionTable;
+import org.jboss.cache.util.ImmutableSetCopy;
import org.jgroups.Address;
import javax.transaction.Transaction;
import javax.transaction.TransactionManager;
import java.util.Collections;
-import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
@@ -543,7 +543,7 @@
GetChildrenNamesCommand command = commandsFactory.buildGetChildrenNamesCommand(fqn);
Set<Object> retval = (Set<Object>) invoker.invoke(ctx, command);
if (retval != null)
- retval = Collections.unmodifiableSet(new HashSet<Object>(retval));
+ retval = new ImmutableSetCopy<Object>(retval);
else
retval = Collections.emptySet();
return retval;
Modified: core/trunk/src/main/java/org/jboss/cache/loader/AbstractCacheLoader.java
===================================================================
--- core/trunk/src/main/java/org/jboss/cache/loader/AbstractCacheLoader.java 2008-07-23 13:46:30 UTC (rev 6376)
+++ core/trunk/src/main/java/org/jboss/cache/loader/AbstractCacheLoader.java 2008-07-23 14:23:32 UTC (rev 6377)
@@ -20,7 +20,7 @@
import org.jboss.cache.marshall.NodeData;
import org.jboss.cache.marshall.NodeDataExceptionMarker;
import org.jboss.cache.marshall.NodeDataMarker;
-import org.jboss.cache.util.MapCopy;
+import org.jboss.cache.util.ImmutableMapCopy;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
@@ -64,7 +64,7 @@
}
// JBCACHE-769 -- make a defensive copy
- Map<Object, Object> attrs = (attributes == null ? null : new MapCopy<Object, Object>(attributes));
+ Map<Object, Object> attrs = (attributes == null ? null : new ImmutableMapCopy<Object, Object>(attributes));
put(fqn, attrs);
}
Modified: core/trunk/src/main/java/org/jboss/cache/loader/AsyncCacheLoader.java
===================================================================
--- core/trunk/src/main/java/org/jboss/cache/loader/AsyncCacheLoader.java 2008-07-23 13:46:30 UTC (rev 6376)
+++ core/trunk/src/main/java/org/jboss/cache/loader/AsyncCacheLoader.java 2008-07-23 14:23:32 UTC (rev 6377)
@@ -9,7 +9,7 @@
import org.jboss.cache.Fqn;
import org.jboss.cache.Modification;
import org.jboss.cache.config.CacheLoaderConfig.IndividualCacheLoaderConfig;
-import org.jboss.cache.util.MapCopy;
+import org.jboss.cache.util.ImmutableMapCopy;
import java.io.IOException;
import java.util.ArrayList;
@@ -182,7 +182,7 @@
if (config.getUseAsyncPut())
{
// JBCACHE-769 -- make a defensive copy
- Map attrs = (attributes == null ? null : new MapCopy(attributes));
+ Map attrs = (attributes == null ? null : new ImmutableMapCopy(attributes));
Modification mod = new Modification(Modification.ModificationType.PUT_DATA, name, attrs);
enqueue(mod);
}
Modified: core/trunk/src/main/java/org/jboss/cache/notifications/NotifierImpl.java
===================================================================
--- core/trunk/src/main/java/org/jboss/cache/notifications/NotifierImpl.java 2008-07-23 13:46:30 UTC (rev 6376)
+++ core/trunk/src/main/java/org/jboss/cache/notifications/NotifierImpl.java 2008-07-23 14:23:32 UTC (rev 6377)
@@ -24,7 +24,7 @@
import org.jboss.cache.notifications.annotation.*;
import org.jboss.cache.notifications.event.*;
import static org.jboss.cache.notifications.event.Event.Type.*;
-import org.jboss.cache.util.MapCopy;
+import org.jboss.cache.util.ImmutableMapCopy;
import org.jgroups.View;
import javax.transaction.Transaction;
@@ -539,7 +539,7 @@
if (data == null) return null;
if (data.isEmpty()) return Collections.emptyMap();
if (safe(data)) return useMarshalledValueMaps ? new MarshalledValueMap(data) : data;
- Map defensivelyCopiedData = new MapCopy(data);
+ Map defensivelyCopiedData = new ImmutableMapCopy(data);
return useMarshalledValueMaps ? new MarshalledValueMap(defensivelyCopiedData) : defensivelyCopiedData;
}
@@ -566,7 +566,7 @@
* A map is deemed 'safe' to be passed as-is to a listener, if either of the following are true:
* <ul>
* <li>It is null</li>
- * <li>It is an instance of {@link org.jboss.cache.util.MapCopy}, which is immutable</li>
+ * <li>It is an instance of {@link org.jboss.cache.util.ImmutableMapCopy}, which is immutable</li>
* <li>It is an instance of {@link java.util.Collections#emptyMap()}, which is also immutable</li>
* <li>It is an instance of {@link java.util.Collections#singletonMap(Object,Object)}, which is also immutable</li>
* </ul>
@@ -576,7 +576,7 @@
*/
private static boolean safe(Map map)
{
- return map == null || map instanceof MapCopy || map.getClass().equals(emptyMap) || map.getClass().equals(singletonMap);
+ return map == null || map instanceof ImmutableMapCopy || map.getClass().equals(emptyMap) || map.getClass().equals(singletonMap);
}
/**
Modified: core/trunk/src/main/java/org/jboss/cache/transaction/PessimisticTransactionContext.java
===================================================================
--- core/trunk/src/main/java/org/jboss/cache/transaction/PessimisticTransactionContext.java 2008-07-23 13:46:30 UTC (rev 6376)
+++ core/trunk/src/main/java/org/jboss/cache/transaction/PessimisticTransactionContext.java 2008-07-23 14:23:32 UTC (rev 6377)
@@ -13,6 +13,7 @@
import org.jboss.cache.commands.WriteCommand;
import org.jboss.cache.config.Option;
import org.jboss.cache.interceptors.OrderedSynchronizationHandler;
+import org.jboss.cache.util.ImmutableListCopy;
import javax.transaction.RollbackException;
import javax.transaction.SystemException;
@@ -170,7 +171,7 @@
@SuppressWarnings("unchecked")
public List getLocks()
{
- return transactionLocks == null || transactionLocks.isEmpty() ? Collections.emptyList() : Collections.unmodifiableList(new ArrayList(transactionLocks));
+ return transactionLocks == null || transactionLocks.isEmpty() ? Collections.emptyList() : new ImmutableListCopy(transactionLocks);
}
Added: core/trunk/src/main/java/org/jboss/cache/util/ImmutableListCopy.java
===================================================================
--- core/trunk/src/main/java/org/jboss/cache/util/ImmutableListCopy.java (rev 0)
+++ core/trunk/src/main/java/org/jboss/cache/util/ImmutableListCopy.java 2008-07-23 14:23:32 UTC (rev 6377)
@@ -0,0 +1,428 @@
+package org.jboss.cache.util;
+
+import net.jcip.annotations.Immutable;
+
+import java.lang.reflect.Array;
+import java.util.AbstractList;
+import java.util.Collection;
+import java.util.Iterator;
+import java.util.List;
+import java.util.ListIterator;
+import java.util.NoSuchElementException;
+
+/**
+ * A lightweight, read-only copy of a List. Typically used in place of the common idiom:
+ * <code>
+ * return Collections.unmodifiableList(new ArrayList( myInternalList ));
+ * </code>
+ * <p/>
+ * a it is far more efficient than making a defensive copy and then wrapping the defensive copy in a read-only wrapper.
+ * <p/>
+ * Also used whenever a read-only reference List is needed (such as in Fqns).
+ * <p/>
+ *
+ * @author Manik Surtani (<a href="mailto:manik at jboss.org">manik at jboss.org</a>)
+ * @since 3.0
+ */
+ at Immutable
+public class ImmutableListCopy<E> extends AbstractList<E>
+{
+ private final E[] elements;
+ private final int size;
+
+ /**
+ * Only one copy constructor since the list is immutable.
+ *
+ * @param c collection to copy from
+ */
+ @SuppressWarnings("unchecked")
+ public ImmutableListCopy(Collection<? extends E> c)
+ {
+ size = c.size();
+ Object[] el = new Object[size]; // no room for growth;
+ el = c.toArray(el);
+ elements = (E[]) el;
+ }
+
+ /**
+ * Assumes that the array passed in is "safe", i.e., is not referenced from elsewhere. Use with care!
+ *
+ * @param array to reference
+ */
+ public ImmutableListCopy(E[] array)
+ {
+ size = array.length;
+ elements = array;
+ }
+
+ /**
+ * Utility constructors to allow combining collections
+ *
+ * @param collection1 collection to copy from
+ * @param collection2 collection to copy from
+ */
+ @SuppressWarnings("unchecked")
+ public ImmutableListCopy(Collection<? extends E> collection1, Collection<? extends E> collection2)
+ {
+ size = collection1.size() + collection2.size();
+ elements = (E[]) new Object[size]; // no room for growth;
+ Object[] c1 = new Object[collection1.size()];
+ Object[] c2 = new Object[collection2.size()];
+ c1 = collection1.toArray(c1);
+ c2 = collection2.toArray(c2);
+ System.arraycopy(c1, 0, elements, 0, c1.length);
+ System.arraycopy(c2, 0, elements, c1.length, c2.length);
+ }
+
+ @Override
+ public final int size()
+ {
+ return size;
+ }
+
+ @Override
+ public final boolean isEmpty()
+ {
+ return size == 0;
+ }
+
+ @Override
+ public final boolean contains(Object o)
+ {
+ return indexOf(o) >= 0;
+ }
+
+ @Override
+ public final Iterator<E> iterator()
+ {
+ return new ImmutableIterator();
+ }
+
+ @Override
+ public final Object[] toArray()
+ {
+ Object[] result = new Object[size];
+ System.arraycopy(elements, 0, result, 0, size);
+ return result;
+ }
+
+ @Override
+ @SuppressWarnings("unchecked")
+ public final <T> T[] toArray(T[] a)
+ {
+ if (a.length < size)
+ {
+ a = (T[]) Array.newInstance(a.getClass().getComponentType(), size);
+ }
+ System.arraycopy(elements, 0, a, 0, size);
+ if (a.length > size) a[size] = null;
+ return a;
+ }
+
+ @Override
+ public final boolean add(E o)
+ {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public final boolean remove(Object o)
+ {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public final boolean addAll(Collection<? extends E> c)
+ {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public final boolean addAll(int index, Collection<? extends E> c)
+ {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public final boolean removeAll(Collection<?> c)
+ {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public final boolean retainAll(Collection<?> c)
+ {
+ throw new UnsupportedOperationException();
+ }
+
+ public final E get(int index)
+ {
+ assertIndexInRange(index);
+ return elements[index];
+ }
+
+ @Override
+ public final int indexOf(Object o)
+ {
+ if (o == null)
+ {
+ for (int i = 0; i < size; i++)
+ {
+ if (elements[i] == null) return i;
+ }
+ }
+ else
+ {
+ for (int i = 0; i < size; i++)
+ {
+ if (o.equals(elements[i])) return i;
+ }
+ }
+ return -1;
+ }
+
+ @Override
+ public final int lastIndexOf(Object o)
+ {
+ if (o == null)
+ {
+ for (int i = size - 1; i >= 0; i--)
+ {
+ if (elements[i] == null) return i;
+ }
+ }
+ else
+ {
+ for (int i = size - 1; i >= 0; i--)
+ {
+ if (o.equals(elements[i])) return i;
+ }
+ }
+ return -1;
+ }
+
+ @Override
+ public final ListIterator<E> listIterator()
+ {
+ return listIterator(0);
+ }
+
+ @Override
+ public final ListIterator<E> listIterator(int index)
+ {
+ assertIndexInRange(index);
+ return new ImmutableIterator(index);
+ }
+
+ @Override
+ public final List<E> subList(int fromIndex, int toIndex)
+ {
+ return new ImmutableSubList<E>(fromIndex, toIndex);
+ }
+
+ private void assertIndexInRange(int index)
+ {
+ if (index >= size || index < 0) throw new IndexOutOfBoundsException("Index: " + index + ", Size: " + size);
+ }
+
+ private class ImmutableIterator implements ListIterator<E>
+ {
+ int cursor = 0;
+
+ ImmutableIterator(int index)
+ {
+ cursor = index;
+ }
+
+ ImmutableIterator()
+ {
+
+ }
+
+ public boolean hasNext()
+ {
+ return cursor != size;
+ }
+
+ public E next()
+ {
+ try
+ {
+ return get(cursor++);
+ }
+ catch (IndexOutOfBoundsException e)
+ {
+ throw new NoSuchElementException();
+ }
+ }
+
+ public void remove()
+ {
+ throw new UnsupportedOperationException();
+ }
+
+ public boolean hasPrevious()
+ {
+ return cursor != 0;
+ }
+
+ public E previous()
+ {
+ try
+ {
+ return get(--cursor);
+ }
+ catch (IndexOutOfBoundsException e)
+ {
+ throw new NoSuchElementException();
+ }
+ }
+
+ public int nextIndex()
+ {
+ return cursor;
+ }
+
+ public int previousIndex()
+ {
+ return cursor - 1;
+ }
+
+ public void set(E o)
+ {
+ throw new UnsupportedOperationException();
+ }
+
+ public void add(E o)
+ {
+ throw new UnsupportedOperationException();
+ }
+ }
+
+ private class ImmutableSubList<E> extends AbstractList<E>
+ {
+ private int offset;
+ private int size;
+
+ ImmutableSubList(int fromIndex, int toIndex)
+ {
+ assertIndexInRange(fromIndex);
+ assertIndexInRange(toIndex - 1);
+ if (fromIndex > toIndex)
+ throw new IllegalArgumentException("fromIndex(" + fromIndex + ") > toIndex(" + toIndex + ")");
+ offset = fromIndex;
+ size = toIndex - fromIndex;
+ }
+
+ @SuppressWarnings("unchecked")
+ public final E get(int index)
+ {
+ rangeCheck(index);
+ return (E) ImmutableListCopy.this.get(index + offset);
+ }
+
+ private void rangeCheck(int index)
+ {
+ if (index < 0 || index >= size) throw new IndexOutOfBoundsException("Index: " + index + ",Size: " + size);
+ }
+
+ public final int size()
+ {
+ return size;
+ }
+
+ @Override
+ protected final void removeRange(int fromIndex, int toIndex)
+ {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public final boolean addAll(Collection<? extends E> c)
+ {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public final boolean addAll(int index, Collection<? extends E> c)
+ {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public final Iterator<E> iterator()
+ {
+ return listIterator();
+ }
+
+ @Override
+ public final ListIterator<E> listIterator(final int index)
+ {
+ rangeCheck(index);
+
+ return new ListIterator<E>()
+ {
+ private ListIterator i = ImmutableListCopy.this.listIterator(index + offset);
+
+ public boolean hasNext()
+ {
+ return nextIndex() < size;
+ }
+
+ @SuppressWarnings("unchecked")
+ public E next()
+ {
+ if (hasNext())
+ return (E) i.next();
+ else
+ throw new NoSuchElementException();
+ }
+
+ public boolean hasPrevious()
+ {
+ return previousIndex() >= 0;
+ }
+
+ @SuppressWarnings("unchecked")
+ public E previous()
+ {
+ if (hasPrevious())
+ return (E) i.previous();
+ else
+ throw new NoSuchElementException();
+ }
+
+ public int nextIndex()
+ {
+ return i.nextIndex() - offset;
+ }
+
+ public int previousIndex()
+ {
+ return i.previousIndex() - offset;
+ }
+
+ public void remove()
+ {
+ throw new UnsupportedOperationException();
+ }
+
+ public void set(E o)
+ {
+ throw new UnsupportedOperationException();
+ }
+
+ public void add(E o)
+ {
+ throw new UnsupportedOperationException();
+ }
+ };
+ }
+
+ @Override
+ public final List<E> subList(int fromIndex, int toIndex)
+ {
+ return new ImmutableSubList<E>(offset + fromIndex, offset + toIndex);
+ }
+ }
+}
Added: core/trunk/src/main/java/org/jboss/cache/util/ImmutableMapCopy.java
===================================================================
--- core/trunk/src/main/java/org/jboss/cache/util/ImmutableMapCopy.java (rev 0)
+++ core/trunk/src/main/java/org/jboss/cache/util/ImmutableMapCopy.java 2008-07-23 14:23:32 UTC (rev 6377)
@@ -0,0 +1,95 @@
+package org.jboss.cache.util;
+
+import net.jcip.annotations.Immutable;
+
+import java.util.AbstractMap;
+import java.util.Map;
+import java.util.Set;
+
+/**
+ * Along the lines of ImmutableListCopy and ImmutableSetCopy. This lightweight wrapper primarily meant for iteration.
+ * performance of get() and containsKey() are not as efficient as that of a {@link java.util.HashMap}, but iteration is
+ * fast since the entry table is a fixed size immutable array.
+ * <p/>
+ * Typically used in place of the common idiom:
+ * <code>
+ * return Collections.unmodifiableMap(new HashMap( myInternalMap ));
+ * </code>
+ *
+ * @author Manik Surtani (<a href="mailto:manik at jboss.org">manik at jboss.org</a>)
+ * @since 3.0
+ */
+ at Immutable
+public class ImmutableMapCopy<K, V> extends AbstractMap<K, V>
+{
+ private final Entry<K, V>[] table;
+ private final int size;
+
+ @SuppressWarnings("unchecked")
+ public ImmutableMapCopy(Map<K, V> map)
+ {
+ size = map.size();
+ table = new ImmutableEntry[size];
+ int i = 0;
+ for (Map.Entry<K, V> me : map.entrySet())
+ {
+ table[i++] = new ImmutableEntry<K, V>(me);
+ }
+ }
+
+ @Override
+ public int size()
+ {
+ return size;
+ }
+
+ @Override
+ public final V remove(Object key)
+ {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public final void putAll(Map<? extends K, ? extends V> t)
+ {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public final void clear()
+ {
+ throw new UnsupportedOperationException();
+ }
+
+ public final Set<Entry<K, V>> entrySet()
+ {
+ return new ImmutableSetCopy<Map.Entry<K, V>>(table);
+ }
+
+ private class ImmutableEntry<K, V> implements Map.Entry<K, V>
+ {
+ K k;
+ V v;
+
+ private ImmutableEntry(Map.Entry<K, V> entry)
+ {
+ k = entry.getKey();
+ v = entry.getValue();
+ }
+
+ public K getKey()
+ {
+ return k;
+ }
+
+ public V getValue()
+ {
+ return v;
+ }
+
+ public V setValue(V value)
+ {
+ throw new UnsupportedOperationException();
+ }
+ }
+}
Added: core/trunk/src/main/java/org/jboss/cache/util/ImmutableSetCopy.java
===================================================================
--- core/trunk/src/main/java/org/jboss/cache/util/ImmutableSetCopy.java (rev 0)
+++ core/trunk/src/main/java/org/jboss/cache/util/ImmutableSetCopy.java 2008-07-23 14:23:32 UTC (rev 6377)
@@ -0,0 +1,109 @@
+package org.jboss.cache.util;
+
+import net.jcip.annotations.Immutable;
+
+import java.util.AbstractSet;
+import java.util.Collection;
+import java.util.Iterator;
+import java.util.NoSuchElementException;
+
+/**
+ * This is based on an ImmutableListCopy, with the assumption that the set passed in would ensure uniqueness of elements.
+ * <p/>
+ * The constructor takes in a collection so the onus is on the caller to ensure that the collection passed in adheres to
+ * Set semantics.
+ * <p/>
+ * Typically used in place of the common idiom:
+ * <code>
+ * return Collections.unmodifiableSet(new HashSet( myInternalSet ));
+ * </code>
+ *
+ * @author Manik Surtani (<a href="mailto:manik at jboss.org">manik at jboss.org</a>)
+ * @see org.jboss.cache.util.ImmutableListCopy
+ * @since 3.0
+ */
+ at Immutable
+public class ImmutableSetCopy<E> extends AbstractSet<E>
+{
+ private final E[] elements;
+ private final int size;
+
+ @SuppressWarnings("unchecked")
+ public ImmutableSetCopy(Collection<E> set)
+ {
+ size = set.size();
+ E[] tempElements = (E[]) new Object[size]; // no room for growth
+ elements = set.toArray(tempElements);
+ }
+
+ /**
+ * Assumes that the array passed in is "safe", i.e., is not referenced from elsewhere. Also assumes the array contains
+ * elements such that the uniqueness required by a set is adhered to. Use with care!
+ *
+ * @param array to reference
+ */
+ public ImmutableSetCopy(E[] array)
+ {
+ elements = array;
+ size = elements.length;
+ }
+
+ @Override
+ public boolean remove(Object o)
+ {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public boolean addAll(Collection<? extends E> c)
+ {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public boolean retainAll(Collection<?> c)
+ {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public boolean removeAll(Collection<?> c)
+ {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public void clear()
+ {
+ throw new UnsupportedOperationException();
+ }
+
+ public Iterator<E> iterator()
+ {
+ return new Iterator<E>()
+ {
+ int cursor = 0;
+
+ public boolean hasNext()
+ {
+ return cursor < size;
+ }
+
+ public E next()
+ {
+ if (cursor >= size) throw new NoSuchElementException();
+ return elements[cursor++];
+ }
+
+ public void remove()
+ {
+ throw new UnsupportedOperationException();
+ }
+ };
+ }
+
+ public int size()
+ {
+ return size;
+ }
+}
Modified: core/trunk/src/main/java/org/jboss/cache/util/MapCopy.java
===================================================================
--- core/trunk/src/main/java/org/jboss/cache/util/MapCopy.java 2008-07-23 13:46:30 UTC (rev 6376)
+++ core/trunk/src/main/java/org/jboss/cache/util/MapCopy.java 2008-07-23 14:23:32 UTC (rev 6377)
@@ -7,7 +7,7 @@
import java.util.AbstractMap;
import java.util.AbstractSet;
import java.util.ArrayList;
-import java.util.HashMap;
+import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
@@ -21,8 +21,10 @@
* {@link UnsupportedOperationException}s.
*
* @author Elias Ross
+ * @deprecated see ImmutableMapCopy instead.
*/
@Immutable
+ at Deprecated
public class MapCopy<K, V> extends AbstractMap<K, V> implements Serializable
{
@@ -51,7 +53,7 @@
public MapCopy()
{
- this(new HashMap<K, V>(0));
+ this((Map<K, V>) Collections.emptyMap());
}
/**
More information about the jbosscache-commits
mailing list