[Arakhnę-Dev] [27] Bug fix: avoid ConcurrentModificationException on WeakValueMap and SoftValueMap. |
[ Thread Index |
Date Index
| More arakhne.org/dev Archives
]
- To: dev@xxxxxxxxxxx
- Subject: [Arakhnę-Dev] [27] Bug fix: avoid ConcurrentModificationException on WeakValueMap and SoftValueMap.
- From: subversion@xxxxxxxxxxxxx
- Date: Mon, 02 Feb 2009 21:42:50 +0100
Revision: 27
Author: galland
Date: 2009-02-02 21:42:49 +0100 (Mon, 02 Feb 2009)
Log Message:
-----------
Bug fix: avoid ConcurrentModificationException on WeakValueMap and SoftValueMap.
Modified Paths:
--------------
trunk/arakhneRefs/pom.xml
trunk/arakhneRefs/src/main/java/org/arakhne/util/ref/SoftValueMap.java
trunk/arakhneRefs/src/main/java/org/arakhne/util/ref/WeakValueMap.java
trunk/pom.xml
Added Paths:
-----------
trunk/arakhneRefs/src/main/java/org/arakhne/util/ref/AbstractWeakSoftValueMap.java
Modified: trunk/arakhneRefs/pom.xml
===================================================================
--- trunk/arakhneRefs/pom.xml 2009-02-02 20:41:14 UTC (rev 26)
+++ trunk/arakhneRefs/pom.xml 2009-02-02 20:42:49 UTC (rev 27)
@@ -22,5 +22,13 @@
<scm>
<url>http://www.arakhne.org/websvn.php?project=afc&subproject=arakhneRefs</url>
</scm>
+
+ <dependencies>
+ <dependency>
+ <groupId>junit</groupId>
+ <artifactId>junit</artifactId>
+ <scope>test</scope>
+ </dependency>
+ </dependencies>
</project>
Added: trunk/arakhneRefs/src/main/java/org/arakhne/util/ref/AbstractWeakSoftValueMap.java
===================================================================
--- trunk/arakhneRefs/src/main/java/org/arakhne/util/ref/AbstractWeakSoftValueMap.java (rev 0)
+++ trunk/arakhneRefs/src/main/java/org/arakhne/util/ref/AbstractWeakSoftValueMap.java 2009-02-02 20:42:49 UTC (rev 27)
@@ -0,0 +1,413 @@
+/*
+ * $Id: WeakValueMap.java,v 1.1 2007-02-20 08:52:37 sgalland Exp $
+ *
+ * Copyright (C) 2005-2007 Stéphane GALLAND
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ * This program is free software; you can redistribute it and/or modify
+ */
+
+package org.arakhne.util.ref;
+
+import java.lang.ref.Reference;
+import java.lang.ref.ReferenceQueue;
+import java.util.AbstractMap;
+import java.util.AbstractSet;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.NoSuchElementException;
+import java.util.Set;
+
+/**
+ * A <tt>Map</tt> implementation with <em>weak/soft values</em>. An entry in a
+ * <tt>AbstractWeakSoftValueMap</tt> will automatically be removed when its value is no
+ * longer in ordinary use or null.
+ *
+ * @param <K> is the type of the keys.
+ * @param <V> is the type of the values.
+ * @author Stéphane GALLAND <galland@xxxxxxxxxxx>
+ * @version $Name: $ $Revision: 1.1 $ $Date: 2007-02-20 08:52:37 $
+ */
+public abstract class AbstractWeakSoftValueMap<K,V> extends AbstractMap<K,V> implements Map<K,V> {
+
+ /** Defines the NULL object inside a WeakValueMap.
+ *
+ * @see #maskNull(Object)
+ */
+ protected static final Object NULL_VALUE = new Object();
+
+ /** Mask the null values given by the used of this map.
+ * <p>
+ * This method replaces the <code>null</code> value by
+ * the internal representation {@link #NULL_VALUE}.
+ *
+ * @param <V> is the type of the value.
+ * @param value is the value given by the user of this map.
+ * @return the internal representation of the value.
+ * @see #unmaskNull(Object)
+ */
+ @SuppressWarnings("unchecked")
+ protected static <V> V maskNull(V value) {
+ return (value==null) ? (V)NULL_VALUE : value;
+ }
+
+ /** Unmask the null values given by the used of this map.
+ * <p>
+ * This method replaces the internal representation
+ * {@link #NULL_VALUE} of null values by its user representation
+ * <code>null</code>.
+ *
+ * @param <V> is the type of the value.
+ * @param value is the value given by the user of this map.
+ * @return the internal representation of the value.
+ * @see #maskNull(Object)
+ */
+ protected static <V> V unmaskNull(V value) {
+ return (value==NULL_VALUE) ? null : value;
+ }
+
+ private boolean autoExpurge = false;
+ private final HashMap<K,WeakSoftValue<K,V>> map;
+ private final ReferenceQueue<V> queue = new ReferenceQueue<V>();
+ private final EntrySet entrySet;
+
+ /**
+ * Constructs an empty <tt>HashMap</tt> with the specified initial
+ * capacity and load factor.
+ *
+ * @param initialCapacity the initial capacity
+ * @param loadFactor the load factor
+ * @throws IllegalArgumentException if the initial capacity is negative
+ * or the load factor is nonpositive
+ */
+ public AbstractWeakSoftValueMap(int initialCapacity, float loadFactor) {
+ this.map = new HashMap<K,WeakSoftValue<K,V>>(initialCapacity, loadFactor);
+ this.entrySet = new EntrySet();
+ }
+
+ /**
+ * Constructs an empty <tt>HashMap</tt> with the specified initial
+ * capacity and the default load factor (0.75).
+ *
+ * @param initialCapacity the initial capacity.
+ * @throws IllegalArgumentException if the initial capacity is negative.
+ */
+ public AbstractWeakSoftValueMap(int initialCapacity) {
+ this.map = new HashMap<K,WeakSoftValue<K,V>>(initialCapacity);
+ this.entrySet = new EntrySet();
+ }
+
+ /**
+ * Constructs an empty <tt>HashMap</tt> with the default initial capacity
+ * (16) and the default load factor (0.75).
+ */
+ public AbstractWeakSoftValueMap() {
+ this.map = new HashMap<K,WeakSoftValue<K,V>>();
+ this.entrySet = new EntrySet();
+ }
+
+ /**
+ * Constructs a new <tt>HashMap</tt> with the same mappings as the
+ * specified <tt>Map</tt>. The <tt>HashMap</tt> is created with
+ * default load factor (0.75) and an initial capacity sufficient to
+ * hold the mappings in the specified <tt>Map</tt>.
+ *
+ * @param m the map whose mappings are to be placed in this map
+ * @throws NullPointerException if the specified map is null
+ */
+ public AbstractWeakSoftValueMap(Map<? extends K, ? extends V> m) {
+ this.map = new HashMap<K,WeakSoftValue<K,V>>();
+ this.entrySet = new EntrySet();
+ putAll(m);
+ }
+
+ /** Clean the references that was marked as released inside
+ * the queue.
+ */
+ protected final void expurgeNow() {
+ if (this.autoExpurge)
+ expurge();
+ else
+ expurgeQueuedReferences();
+ }
+
+ /** Replies if this map expurge all the released references
+ * even if they are not enqueued by the virtual machine
+ *
+ * @return <code>true</code> is the values are deeply expurged when they
+ * are released from the moemory, otherwise <code>false</code>
+ */
+ public final boolean isDeeplyExpurge() {
+ return this.autoExpurge;
+ }
+
+ /** Set if this map expurge all the released references
+ * even if they are not enqueued by the virtual machine
+ *
+ * @param deeplyExpurge must be <code>true</code> to
+ * expurge all the released values, otherwise <code>false</code>
+ * to expurge only the enqueued values.
+ * @return the old value of this flag
+ */
+ public final boolean setDeeplyExpurge(boolean deeplyExpurge) {
+ boolean old = this.autoExpurge;
+ this.autoExpurge = deeplyExpurge;
+ return old;
+ }
+
+ /** Clean the references that was marked as released inside
+ * the queue.
+ */
+ public final void expurgeQueuedReferences() {
+ Reference<? extends V> o;
+ while((o = this.queue.poll()) != null) {
+ if (o instanceof WeakSoftValue) {
+ this.map.remove(((WeakSoftValue<?,?>)o).getKey());
+ }
+ o.clear();
+ }
+ }
+
+ /** Clean the references that was released.
+ */
+ public final void expurge() {
+ Reference<? extends V> o;
+
+ Iterator<Entry<K,WeakSoftValue<K,V>>> iter = this.map.entrySet().iterator();
+ Entry<K,WeakSoftValue<K,V>> entry;
+ WeakSoftValue<K,V> value;
+ while (iter.hasNext()) {
+ entry = iter.next();
+ if (entry!=null) {
+ value = entry.getValue();
+ if ((value!=null)&&
+ ((value.isEnqueued())||(value.get()==null))) {
+ value.enqueue();
+ value.clear();
+ }
+ }
+ }
+ entry = null;
+ value = null;
+
+ while((o = this.queue.poll()) != null) {
+ if (o instanceof WeakSoftValue) {
+ this.map.remove(((WeakSoftValue<?,?>)o).getKey());
+ }
+ o.clear();
+ }
+ }
+
+ /** Create a storage object that permits to put the specified
+ * elements inside this map.
+ *
+ * @param k is the key associated to the value
+ * @param v is the value
+ * @param queue is the reference queue to use
+ * @return the new storage object
+ */
+ protected abstract WeakSoftValue<K,V> makeValue(K k, V v, ReferenceQueue<V> queue);
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public final V put(K key, V value) {
+ expurgeNow();
+ WeakSoftValue<K,V> ret = this.map.put(key, makeValue(key, value, this.queue));
+ if(ret == null) return null;
+ return ret.getValue();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public final Set<Entry<K,V>> entrySet() {
+ expurgeNow();
+ return this.entrySet;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public final boolean equals(Object o) {
+ expurgeNow();
+ return super.equals(o);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public final int hashCode() {
+ expurgeNow();
+ return hashCode();
+ }
+
+ /**
+ * @author Stéphane GALLAND <galland@xxxxxxxxxxx>
+ * @version $Name: $ $Revision: 1.1 $ $Date: 2007-02-20 08:52:37 $
+ */
+ private class RealEntry implements Entry<K,V> {
+
+ private final K key;
+ private V value;
+
+ public RealEntry(K k, V v) {
+ this.key = k;
+ this.value = v;
+ }
+
+ @Override
+ public K getKey() {
+ return this.key;
+ }
+
+ @Override
+ public V getValue() {
+ return this.value;
+ }
+
+ @Override
+ public V setValue(V value) {
+ V oldValue = this.value;
+ this.value = value;
+ if (value==null)
+ remove(this.key);
+ else
+ put(this.key, value);
+ return oldValue;
+ }
+
+ }
+
+ /**
+ * @author Stéphane GALLAND <galland@xxxxxxxxxxx>
+ * @version $Name: $ $Revision: 1.1 $ $Date: 2007-02-20 08:52:37 $
+ */
+ private class EntrySetIterator implements Iterator<Entry<K,V>> {
+
+ private final Iterator<Entry<K,WeakSoftValue<K,V>>> iter;
+ private RealEntry next;
+
+ public EntrySetIterator(Iterator<Entry<K,WeakSoftValue<K,V>>> iter) {
+ this.iter = iter;
+ expurgeNow();
+ this.next = searchNext();
+ }
+
+ private RealEntry searchNext() {
+ Entry<K,WeakSoftValue<K,V>> entry;
+ WeakSoftValue<K,V> val;
+ V value;
+ while (this.iter.hasNext()) {
+ entry = this.iter.next();
+ if (entry==null) throw new NoSuchElementException();
+ val = entry.getValue();
+ if (val==null) throw new NoSuchElementException();
+ value = val.getValue();
+ if (value!=null) {
+ return new RealEntry(entry.getKey(), value);
+ }
+ }
+ return null;
+ }
+
+ public boolean hasNext() {
+ return (this.next!=null);
+ }
+
+ public Entry<K,V> next() {
+ RealEntry entry = this.next;
+ if (entry==null) throw new NoSuchElementException();
+ this.next = searchNext();
+ return entry;
+ }
+
+ public void remove() {
+ this.iter.remove();
+ }
+
+ }
+
+ /**
+ * @author Stéphane GALLAND <galland@xxxxxxxxxxx>
+ * @version $Name: $ $Revision: 1.1 $ $Date: 2007-02-20 08:52:37 $
+ */
+ private class EntrySet extends AbstractSet<Entry<K,V>> implements Set<Entry<K,V>> {
+
+ /**
+ *
+ */
+ public EntrySet() {
+ //
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @return {@inheritDoc}
+ */
+ @SuppressWarnings("synthetic-access")
+ @Override
+ public Iterator<Entry<K, V>> iterator() {
+ return new EntrySetIterator(AbstractWeakSoftValueMap.this.map.entrySet().iterator());
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @return {@inheritDoc}
+ */
+ @SuppressWarnings("synthetic-access")
+ @Override
+ public int size() {
+ expurgeNow();
+ return AbstractWeakSoftValueMap.this.map.size();
+ }
+
+ }
+
+ /**
+ * @author Stéphane GALLAND <galland@xxxxxxxxxxx>
+ * @version $Name: $ $Revision: 1.1 $ $Date: 2007-02-20 08:52:37 $
+ */
+ protected interface WeakSoftValue<K,V> extends Entry<K,V> {
+
+ /**
+ * @return if the value is enqueued into a reference queue.
+ */
+ public boolean isEnqueued();
+
+ /**
+ * @return the weak/soft reference.
+ */
+ public V get();
+
+ /**
+ * @return if the value was enqueued
+ */
+ public boolean enqueue();
+
+ /**
+ */
+ public void clear();
+
+ }
+
+}
Modified: trunk/arakhneRefs/src/main/java/org/arakhne/util/ref/SoftValueMap.java
===================================================================
--- trunk/arakhneRefs/src/main/java/org/arakhne/util/ref/SoftValueMap.java 2009-02-02 20:41:14 UTC (rev 26)
+++ trunk/arakhneRefs/src/main/java/org/arakhne/util/ref/SoftValueMap.java 2009-02-02 20:42:49 UTC (rev 27)
@@ -1,7 +1,7 @@
/*
- * $Id$
+ * $Id: SoftValueMap.java,v 1.1 2007-02-20 08:52:37 sgalland Exp $
*
- * Copyright (C) 2005-2008 Stéphane GALLAND
+ * Copyright (C) 2005-2007 Stéphane GALLAND
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
@@ -21,23 +21,16 @@
package org.arakhne.util.ref;
-import java.lang.ref.Reference;
import java.lang.ref.ReferenceQueue;
import java.lang.ref.SoftReference;
-import java.util.AbstractMap;
-import java.util.AbstractSet;
-import java.util.ConcurrentModificationException;
-import java.util.HashMap;
-import java.util.Iterator;
import java.util.Map;
-import java.util.Set;
/**
- * A <tt>Map</tt> implementation with <em>soft-referenced values</em>. An entry in a
+ * A <tt>Map</tt> implementation with <em>soft values</em>. An entry in a
* <tt>SoftValueMap</tt> will automatically be removed when its value is no
* longer in ordinary use or null.
* <p>
- * This class was inspirated from {@link WeakValueMap}.
+ * This class was inspirated from <code>WeakHashMap</code>
* <p>
* This class has a special flag which permits to control the
* way how the released references are expurged: {@link #isDeeplyExpurge()},
@@ -66,48 +59,8 @@
* @author Stéphane GALLAND <galland@xxxxxxxxxxx>
* @version $Name: $ $Revision: 1.1 $ $Date: 2007-02-20 08:52:37 $
*/
-public class SoftValueMap<K,V> extends AbstractMap<K,V> implements Map<K,V> {
-
- /** Constant that represent a NULL value inside a SoftValueMap.
- * @see #maskNull(Object)
- */
- protected static final Object NULL_VALUE = new Object();
-
- /** Mask the null values given by the used of this map.
- * <p>
- * This method replaces the <code>null</code> value by
- * the internal representation {@link #NULL_VALUE}.
- *
- * @param <V> is the type of the value
- * @param value is the value given by the user of this map.
- * @return the internal representation of the value.
- * @see #unmaskNull(Object)
- */
- @SuppressWarnings("unchecked")
- protected static <V> V maskNull(V value) {
- return (value==null) ? (V)NULL_VALUE : value;
- }
-
- /** Unmask the null values given by the used of this map.
- * <p>
- * This method replaces the internal representation
- * {@link #NULL_VALUE} of null values by its user representation
- * <code>null</code>.
- *
- * @param <V> is the type of the value
- * @param value is the value given by the user of this map.
- * @return the internal representation of the value.
- * @see #maskNull(Object)
- */
- protected static <V> V unmaskNull(V value) {
- return (value==NULL_VALUE) ? null : value;
- }
-
- private boolean autoExpurge = false;
- private final HashMap<K,Value<K,V>> map;
- private final ReferenceQueue<V> queue = new ReferenceQueue<V>();
- private final EntrySet entrySet;
-
+public class SoftValueMap<K,V> extends AbstractWeakSoftValueMap<K,V> {
+
/**
* Constructs an empty <tt>HashMap</tt> with the specified initial
* capacity and load factor.
@@ -118,8 +71,7 @@
* or the load factor is nonpositive
*/
public SoftValueMap(int initialCapacity, float loadFactor) {
- this.map = new HashMap<K,Value<K,V>>(initialCapacity, loadFactor);
- this.entrySet = new EntrySet();
+ super(initialCapacity, loadFactor);
}
/**
@@ -130,8 +82,7 @@
* @throws IllegalArgumentException if the initial capacity is negative.
*/
public SoftValueMap(int initialCapacity) {
- this.map = new HashMap<K,Value<K,V>>(initialCapacity);
- this.entrySet = new EntrySet();
+ super(initialCapacity);
}
/**
@@ -139,8 +90,7 @@
* (16) and the default load factor (0.75).
*/
public SoftValueMap() {
- this.map = new HashMap<K,Value<K,V>>();
- this.entrySet = new EntrySet();
+ super();
}
/**
@@ -153,89 +103,9 @@
* @throws NullPointerException if the specified map is null
*/
public SoftValueMap(Map<? extends K, ? extends V> m) {
- this.map = new HashMap<K,Value<K,V>>();
- this.entrySet = new EntrySet();
- putAll(m);
+ super(m);
}
- /** Clean the references that was marked as released inside
- * the queue.
- */
- protected void expurgeNow() {
- if (this.autoExpurge)
- expurge();
- else
- expurgeQueuedReferences();
- }
-
- /** Replies if this map expurge all the released references
- * even if they are not enqueued by the virtual machine
- *
- * @return <code>true</code> if this map deeply expurge its content,
- * otherwise <code>false</code>
- */
- public boolean isDeeplyExpurge() {
- return this.autoExpurge;
- }
-
- /** Set if this map expurge all the released references
- * even if they are not enqueued by the virtual machine
- *
- * @param deeplyExpurge must be <code>true</code> to
- * expurge all the released values, otherwise <code>false</code>
- * to expurge only the enqueued values.
- * @return the old value of this flag
- */
- public boolean setDeeplyExpurge(boolean deeplyExpurge) {
- boolean old = this.autoExpurge;
- this.autoExpurge = deeplyExpurge;
- return old;
- }
-
- /** Clean the references that was marked as released inside
- * the queue.
- */
- public void expurgeQueuedReferences() {
- Reference<? extends V> o;
- while((o = this.queue.poll()) != null) {
- if (o instanceof Value) {
-
- this.map.remove(((Value<?,?>)o).getKey());
- }
- o.clear();
- }
- }
-
- /** Clean the references that was released.
- */
- public void expurge() {
- Reference<? extends V> o;
-
- Iterator<Entry<K,Value<K,V>>> iter = this.map.entrySet().iterator();
- Entry<K,Value<K,V>> entry;
- Value<K,V> value;
- while (iter.hasNext()) {
- entry = iter.next();
- if (entry!=null) {
- value = entry.getValue();
- if ((value!=null)&&
- ((value.isEnqueued())||(value.get()==null))) {
- value.enqueue();
- value.clear();
- }
- }
- }
- entry = null;
- value = null;
-
- while((o = this.queue.poll()) != null) {
- if (o instanceof Value) {
- this.map.remove(((Value<?,?>)o).getKey());
- }
- o.clear();
- }
- }
-
/** Create a storage object that permits to put the specified
* elements inside this map.
*
@@ -244,115 +114,23 @@
* @param queue is the reference queue to use
* @return the new storage object
*/
- protected Value<K,V> makeValue(K k, V v, ReferenceQueue<V> queue) {
+ @Override
+ protected WeakSoftValue<K,V> makeValue(K k, V v, ReferenceQueue<V> queue) {
return new Value<K,V>(k, v, queue);
}
/**
- * {@inheritDoc}
- */
- @Override
- public V put(K key, V value) {
- expurgeNow();
- Value<K,V> ret = this.map.put(key, makeValue(key, value, this.queue));
- if(ret == null) return null;
- return ret.getValue();
- }
-
- /**
- * {@inheritDoc}
- */
- @Override
- public Set<Entry<K,V>> entrySet() {
- expurgeNow();
- return this.entrySet;
- }
-
- /**
- * {@inheritDoc}
- */
- @Override
- public boolean equals(Object o) {
- expurgeNow();
- return super.equals(o);
- }
-
- /**
- * {@inheritDoc}
- */
- @Override
- public int hashCode() {
- expurgeNow();
- return hashCode();
- }
-
- /**
* @author Stéphane GALLAND <galland@xxxxxxxxxxx>
* @version $Name: $ $Revision: 1.1 $ $Date: 2007-02-20 08:52:37 $
*/
- private class EntrySet extends AbstractSet<Entry<K,V>> implements Set<Entry<K,V>> {
+ private static class Value<K,V> extends SoftReference<V> implements WeakSoftValue<K,V> {
- private final Set<Entry<K,Value<K,V>>> baseSet;
-
- /**
- *
- */
- @SuppressWarnings("synthetic-access")
- public EntrySet() {
- this.baseSet = SoftValueMap.this.map.entrySet();
- }
-
- /**
- * {@inheritDoc}
- *
- * @return {@inheritDoc}
- */
- @Override
- public Iterator<Entry<K, V>> iterator() {
- final Iterator<Entry<K,Value<K,V>>> iter = this.baseSet.iterator();
- return new Iterator<Entry<K,V>>() {
- public boolean hasNext() {
- expurgeNow();
- return iter.hasNext();
- }
- public Entry<K,V> next() {
- Entry<K, Value<K,V>> entry = iter.next();
- if (entry==null) throw new ConcurrentModificationException();
- Value<K,V> value = entry.getValue();
- if (value==null) throw new ConcurrentModificationException();
- return value;
- }
- public void remove() {
- iter.remove();
- }
- };
- }
-
- /**
- * {@inheritDoc}
- *
- * @return {@inheritDoc}
- */
- @Override
- public int size() {
- expurgeNow();
- return this.baseSet.size();
- }
-
- }
-
- /**
- * @author Stéphane GALLAND <galland@xxxxxxxxxxx>
- * @version $Name: $ $Revision: 1.1 $ $Date: 2007-02-20 08:52:37 $
- */
- private static class Value<K,V> extends SoftReference<V> implements Entry<K,V> {
-
private final K k;
/**
* @param k is the key.
* @param v is the value.
- * @param queue is the memory release listener.
+ * @param queue is the memory-release listener.
*/
Value(K k, V v, ReferenceQueue<V> queue) {
super(maskNull(v), queue);
@@ -382,7 +160,7 @@
buffer.append('}');
return buffer.toString();
}
-
+
/**
* {@inheritDoc}
*
@@ -400,7 +178,7 @@
public V getValue() {
return unmaskNull(get());
}
-
+
/**
* {@inheritDoc}
*
Modified: trunk/arakhneRefs/src/main/java/org/arakhne/util/ref/WeakValueMap.java
===================================================================
--- trunk/arakhneRefs/src/main/java/org/arakhne/util/ref/WeakValueMap.java 2009-02-02 20:41:14 UTC (rev 26)
+++ trunk/arakhneRefs/src/main/java/org/arakhne/util/ref/WeakValueMap.java 2009-02-02 20:42:49 UTC (rev 27)
@@ -21,16 +21,9 @@
package org.arakhne.util.ref;
-import java.lang.ref.Reference;
import java.lang.ref.ReferenceQueue;
import java.lang.ref.WeakReference;
-import java.util.AbstractMap;
-import java.util.AbstractSet;
-import java.util.ConcurrentModificationException;
-import java.util.HashMap;
-import java.util.Iterator;
import java.util.Map;
-import java.util.Set;
import java.util.WeakHashMap;
/**
@@ -67,49 +60,8 @@
* @author Stéphane GALLAND <galland@xxxxxxxxxxx>
* @version $Name: $ $Revision: 1.1 $ $Date: 2007-02-20 08:52:37 $
*/
-public class WeakValueMap<K,V> extends AbstractMap<K,V> implements Map<K,V> {
+public class WeakValueMap<K,V> extends AbstractWeakSoftValueMap<K,V> {
- /** Defines the NULL object inside a WeakValueMap.
- *
- * @see #maskNull(Object)
- */
- protected static final Object NULL_VALUE = new Object();
-
- /** Mask the null values given by the used of this map.
- * <p>
- * This method replaces the <code>null</code> value by
- * the internal representation {@link #NULL_VALUE}.
- *
- * @param <V> is the type of the value.
- * @param value is the value given by the user of this map.
- * @return the internal representation of the value.
- * @see #unmaskNull(Object)
- */
- @SuppressWarnings("unchecked")
- protected static <V> V maskNull(V value) {
- return (value==null) ? (V)NULL_VALUE : value;
- }
-
- /** Unmask the null values given by the used of this map.
- * <p>
- * This method replaces the internal representation
- * {@link #NULL_VALUE} of null values by its user representation
- * <code>null</code>.
- *
- * @param <V> is the type of the value.
- * @param value is the value given by the user of this map.
- * @return the internal representation of the value.
- * @see #maskNull(Object)
- */
- protected static <V> V unmaskNull(V value) {
- return (value==NULL_VALUE) ? null : value;
- }
-
- private boolean autoExpurge = false;
- private final HashMap<K,Value<K,V>> map;
- private final ReferenceQueue<V> queue = new ReferenceQueue<V>();
- private final EntrySet entrySet;
-
/**
* Constructs an empty <tt>HashMap</tt> with the specified initial
* capacity and load factor.
@@ -120,8 +72,7 @@
* or the load factor is nonpositive
*/
public WeakValueMap(int initialCapacity, float loadFactor) {
- this.map = new HashMap<K,Value<K,V>>(initialCapacity, loadFactor);
- this.entrySet = new EntrySet();
+ super(initialCapacity, loadFactor);
}
/**
@@ -132,8 +83,7 @@
* @throws IllegalArgumentException if the initial capacity is negative.
*/
public WeakValueMap(int initialCapacity) {
- this.map = new HashMap<K,Value<K,V>>(initialCapacity);
- this.entrySet = new EntrySet();
+ super(initialCapacity);
}
/**
@@ -141,8 +91,7 @@
* (16) and the default load factor (0.75).
*/
public WeakValueMap() {
- this.map = new HashMap<K,Value<K,V>>();
- this.entrySet = new EntrySet();
+ super();
}
/**
@@ -155,88 +104,9 @@
* @throws NullPointerException if the specified map is null
*/
public WeakValueMap(Map<? extends K, ? extends V> m) {
- this.map = new HashMap<K,Value<K,V>>();
- this.entrySet = new EntrySet();
- putAll(m);
+ super(m);
}
- /** Clean the references that was marked as released inside
- * the queue.
- */
- protected void expurgeNow() {
- if (this.autoExpurge)
- expurge();
- else
- expurgeQueuedReferences();
- }
-
- /** Replies if this map expurge all the released references
- * even if they are not enqueued by the virtual machine
- *
- * @return <code>true</code> is the values are deeply expurged when they
- * are released from the moemory, otherwise <code>false</code>
- */
- public boolean isDeeplyExpurge() {
- return this.autoExpurge;
- }
-
- /** Set if this map expurge all the released references
- * even if they are not enqueued by the virtual machine
- *
- * @param deeplyExpurge must be <code>true</code> to
- * expurge all the released values, otherwise <code>false</code>
- * to expurge only the enqueued values.
- * @return the old value of this flag
- */
- public boolean setDeeplyExpurge(boolean deeplyExpurge) {
- boolean old = this.autoExpurge;
- this.autoExpurge = deeplyExpurge;
- return old;
- }
-
- /** Clean the references that was marked as released inside
- * the queue.
- */
- public void expurgeQueuedReferences() {
- Reference<? extends V> o;
- while((o = this.queue.poll()) != null) {
- if (o instanceof Value) {
- this.map.remove(((Value<?,?>)o).getKey());
- }
- o.clear();
- }
- }
-
- /** Clean the references that was released.
- */
- public void expurge() {
- Reference<? extends V> o;
-
- Iterator<Entry<K,Value<K,V>>> iter = this.map.entrySet().iterator();
- Entry<K,Value<K,V>> entry;
- Value<K,V> value;
- while (iter.hasNext()) {
- entry = iter.next();
- if (entry!=null) {
- value = entry.getValue();
- if ((value!=null)&&
- ((value.isEnqueued())||(value.get()==null))) {
- value.enqueue();
- value.clear();
- }
- }
- }
- entry = null;
- value = null;
-
- while((o = this.queue.poll()) != null) {
- if (o instanceof Value) {
- this.map.remove(((Value<?,?>)o).getKey());
- }
- o.clear();
- }
- }
-
/** Create a storage object that permits to put the specified
* elements inside this map.
*
@@ -245,109 +115,17 @@
* @param queue is the reference queue to use
* @return the new storage object
*/
- protected Value<K,V> makeValue(K k, V v, ReferenceQueue<V> queue) {
+ @Override
+ protected WeakSoftValue<K,V> makeValue(K k, V v, ReferenceQueue<V> queue) {
return new Value<K,V>(k, v, queue);
}
/**
- * {@inheritDoc}
- */
- @Override
- public V put(K key, V value) {
- expurgeNow();
- Value<K,V> ret = this.map.put(key, makeValue(key, value, this.queue));
- if(ret == null) return null;
- return ret.getValue();
- }
-
- /**
- * {@inheritDoc}
- */
- @Override
- public Set<Entry<K,V>> entrySet() {
- expurgeNow();
- return this.entrySet;
- }
-
- /**
- * {@inheritDoc}
- */
- @Override
- public boolean equals(Object o) {
- expurgeNow();
- return super.equals(o);
- }
-
- /**
- * {@inheritDoc}
- */
- @Override
- public int hashCode() {
- expurgeNow();
- return hashCode();
- }
-
- /**
* @author Stéphane GALLAND <galland@xxxxxxxxxxx>
* @version $Name: $ $Revision: 1.1 $ $Date: 2007-02-20 08:52:37 $
*/
- private class EntrySet extends AbstractSet<Entry<K,V>> implements Set<Entry<K,V>> {
+ private static class Value<K,V> extends WeakReference<V> implements WeakSoftValue<K,V> {
- private final Set<Entry<K,Value<K,V>>> baseSet;
-
- /**
- *
- */
- @SuppressWarnings("synthetic-access")
- public EntrySet() {
- this.baseSet = WeakValueMap.this.map.entrySet();
- }
-
- /**
- * {@inheritDoc}
- *
- * @return {@inheritDoc}
- */
- @Override
- public Iterator<Entry<K, V>> iterator() {
- final Iterator<Entry<K,Value<K,V>>> iter = this.baseSet.iterator();
- return new Iterator<Entry<K,V>>() {
- public boolean hasNext() {
- expurgeNow();
- return iter.hasNext();
- }
- public Entry<K,V> next() {
- Entry<K, Value<K,V>> entry = iter.next();
- if (entry==null) throw new ConcurrentModificationException();
- Value<K,V> value = entry.getValue();
- if (value==null) throw new ConcurrentModificationException();
- return value;
- }
- public void remove() {
- iter.remove();
- }
- };
- }
-
- /**
- * {@inheritDoc}
- *
- * @return {@inheritDoc}
- */
- @Override
- public int size() {
- expurgeNow();
- return this.baseSet.size();
- }
-
- }
-
- /**
- * @author Stéphane GALLAND <galland@xxxxxxxxxxx>
- * @version $Name: $ $Revision: 1.1 $ $Date: 2007-02-20 08:52:37 $
- */
- private static class Value<K,V> extends WeakReference<V> implements Entry<K,V> {
-
private final K k;
/**
Modified: trunk/pom.xml
===================================================================
--- trunk/pom.xml 2009-02-02 20:41:14 UTC (rev 26)
+++ trunk/pom.xml 2009-02-02 20:42:49 UTC (rev 27)
@@ -18,7 +18,7 @@
<properties>
<version_myjdk>1.6</version_myjdk>
<version_arakhnelogger>1.1-SNAPSHOT</version_arakhnelogger>
- <version_arakhnerefs>3.0-SNAPSHOT</version_arakhnerefs>
+ <version_arakhnerefs>4.0-SNAPSHOT</version_arakhnerefs>
<version_arakhnevmutils>2.1-SNAPSHOT</version_arakhnevmutils>
</properties>
@@ -34,6 +34,11 @@
<artifactId>maven-enforcer-plugin</artifactId>
<version>1.0-alpha-4</version>
</dependency>
+ <dependency>
+ <groupId>junit</groupId>
+ <artifactId>junit</artifactId>
+ <version>[3.8,4.0)</version>
+ </dependency>
</dependencies>
</dependencyManagement>
@@ -133,7 +138,6 @@
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
- <version>2.0.2</version>
<configuration>
<source>${version_myjdk}</source>
<target>${version_myjdk}</target>
@@ -142,7 +146,6 @@
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-scm-plugin</artifactId>
- <version>1.0</version>
<configuration>
<goals>install</goals>
</configuration>
@@ -150,12 +153,10 @@
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-site-plugin</artifactId>
- <version>2.0-beta-7</version>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-deploy-plugin</artifactId>
- <version>2.3</version>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>