[[dev@xxxxxxxxxxx]] [2] First release on a public SCM. |
[ Thread Index |
Date Index
| More arakhne.org/dev Archives
]
Revision: 2
Author: galland
Date: 2008-09-12 17:59:03 +0200 (Fri, 12 Sep 2008)
Log Message:
-----------
First release on a public SCM.
Added Paths:
-----------
trunk/pom.xml
trunk/src/
trunk/src/main/
trunk/src/main/java/
trunk/src/main/java/org/
trunk/src/main/java/org/arakhne/
trunk/src/main/java/org/arakhne/util/
trunk/src/main/java/org/arakhne/util/ref/
trunk/src/main/java/org/arakhne/util/ref/ComparableSoftReference.java
trunk/src/main/java/org/arakhne/util/ref/ComparableWeakReference.java
trunk/src/main/java/org/arakhne/util/ref/SoftValueMap.java
trunk/src/main/java/org/arakhne/util/ref/WeakArrayList.java
trunk/src/main/java/org/arakhne/util/ref/WeakValueMap.java
trunk/src/main/resources/
trunk/src/main/resources/AUTHORS
trunk/src/main/resources/COPYING
trunk/src/main/resources/Changelog
trunk/src/main/resources/VERSION
trunk/src/test/
trunk/src/test/java/
Added: trunk/pom.xml
===================================================================
--- trunk/pom.xml (rev 0)
+++ trunk/pom.xml 2008-09-12 15:59:03 UTC (rev 2)
@@ -0,0 +1,106 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+ <modelVersion>4.0.0</modelVersion>
+ <groupId>org.arakhne</groupId>
+ <artifactId>arakhneRefs</artifactId>
+ <packaging>jar</packaging>
+ <version>3.0-SNAPSHOT</version>
+ <name>arakhneRefs</name>
+ <url>http://www.arakhne.org/arakhneRefs/</url>
+ <description>Java library that provides additional tools for managing weak and soft references</description>
+
+ <!-- ======================================= -->
+ <!-- ==== Project Information === -->
+ <!-- ======================================= -->
+
+ <licenses>
+ <license>
+ <name>GNU Lesser General Public License v2.0</name>
+ <url>http://www.gnu.org/licenses/lgpl.html</url>
+ <distribution>manual</distribution>
+ </license>
+ </licenses>
+
+ <mailingLists>
+ <mailingList>
+ <name>dev@xxxxxxxxxxx</name>
+ <subscribe>mailto:dev-request@xxxxxxxxxxx</subscribe>
+ <unsubscribe>mailto:dev-request@xxxxxxxxxxx</unsubscribe>
+ <post>mailto:dev@xxxxxxxxxxx</post>
+ </mailingList>
+ </mailingLists>
+
+ <!-- ======================================= -->
+ <!-- ==== Organization Information === -->
+ <!-- ======================================= -->
+
+ <organization>
+ <name>Arakhnê.org Project</name>
+ <url>http://www.arakhne.org</url>
+ </organization>
+
+ <developers>
+ <developer>
+ <id>sgalland</id>
+ <name>Stephane Galland</name>
+ <email>galland@xxxxxxxxxxx</email>
+ <url/>
+ <organization>
+ Arakhnê.org
+ </organization>
+ <organizationUrl>http://www.arakhne.org</organizationUrl>
+ <roles>
+ <role>Architect</role>
+ <role>Developer</role>
+ </roles>
+ <timezone />
+ <properties />
+ </developer>
+ </developers>
+
+ <!-- ======================================= -->
+ <!-- ==== Devel Configuration === -->
+ <!-- ======================================= -->
+
+ <scm>
+ <connection>scm:svn:svn+ssh://svn.tuxfamily.org/svnroot/arakhne/arakhneRefs</connection>
+ <developerConnection>scm:svn:svn+ssh://username@xxxxxxxxxxxxxxxxx/svnroot/arakhne/arakhneRefs</developerConnection>
+ <url>http://www.arakhne.org/websvn.php?project=arakhnerefs</url>
+ </scm>
+
+ <build>
+ <plugins>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-compiler-plugin</artifactId>
+ <version>2.0.2</version>
+ <configuration>
+ <source>1.6</source>
+ <target>1.6</target>
+ </configuration>
+ </plugin>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-scm-plugin</artifactId>
+ <version>1.0</version>
+ <configuration>
+ <goals>install</goals>
+ </configuration>
+ </plugin>
+ </plugins>
+ </build>
+
+ <!-- ======================================= -->
+ <!-- ==== Dependencies === -->
+ <!-- ======================================= -->
+
+ <dependencies>
+ <dependency>
+ <groupId>junit</groupId>
+ <artifactId>junit</artifactId>
+ <version>3.8.1</version>
+ <scope>test</scope>
+ </dependency>
+ </dependencies>
+
+</project>
Added: trunk/src/main/java/org/arakhne/util/ref/ComparableSoftReference.java
===================================================================
--- trunk/src/main/java/org/arakhne/util/ref/ComparableSoftReference.java (rev 0)
+++ trunk/src/main/java/org/arakhne/util/ref/ComparableSoftReference.java 2008-09-12 15:59:03 UTC (rev 2)
@@ -0,0 +1,172 @@
+/*
+ * $Id: ComparableSoftReference.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.lang.ref.SoftReference;
+
+/**
+ * This class is a WeakReference that allows to be
+ * compared on its pointed value.
+ *
+ * @param <T> is the type of the referenced object.
+ * @author Stéphane GALLAND <galland@xxxxxxxxxxx>
+ * @version $Name: $ $Revision: 1.1 $ $Date: 2007-02-20 08:52:37 $
+ */
+public class ComparableSoftReference<T> extends SoftReference<T> implements Comparable<Object> {
+
+ /**
+ * @param referent is the referenced object.
+ */
+ public ComparableSoftReference(T referent) {
+ super(referent);
+ }
+
+ /**
+ * @param referent is the referenced object.
+ * @param queue is the object that will be notified of the memory released for the referenced object.
+ */
+ public ComparableSoftReference(T referent, ReferenceQueue<? super T> queue) {
+ super(referent,queue);
+ }
+
+ /** {@inheritDoc}
+ *
+ * @param o {@inheritDoc}
+ * @return {@inheritDoc}
+ */
+ @SuppressWarnings("unchecked")
+ @Override
+ public boolean equals(Object o) {
+ if (super.equals(o)) return true;
+
+ try {
+ if (o instanceof Reference)
+ return (compareToRef((Reference)o)==0);
+
+ return compareToObject((T)o)==0;
+ }
+ catch(Exception _) {
+ return false;
+ }
+ }
+
+ /** Compare this reference to the specified object
+ * based on the {@link Object#hashCode()} if the
+ * references are not equals.
+ *
+ * @param o {@inheritDoc}
+ * @return {@inheritDoc}
+ */
+ @SuppressWarnings("unchecked")
+ public int compareTo(Object o) {
+ try {
+ if (o instanceof Reference)
+ return compareToRef((Reference)o);
+
+ return compareToObject((T)o);
+ }
+ catch(Exception _) {
+ int a = hashCode();
+ int b = o.hashCode();
+ return a - b;
+ }
+ }
+
+ /** Compare this reference to the specified object
+ * based on the {@link Object#hashCode()} if the
+ * references are not equals.
+ *
+ * @param o the object to be compared.
+ * @return a negative integer, zero, or a positive integer as this object
+ * is less than, equal to, or greater than the specified object.
+ */
+ @SuppressWarnings("unchecked")
+ public int compareToRef(Reference<T> o) {
+ T obj = o.get();
+ T cur = get();
+
+ if (((cur==null)&&(obj==null))||(cur==obj)) return 0;
+ if (cur==null) return -1;
+ if (obj==null) return 1;
+
+ if (cur instanceof Comparable) {
+ Comparable cmp = (Comparable<?>)cur;
+ return cmp.compareTo(obj);
+ }
+
+ if ((cur==obj)||(cur.equals(obj))) return 0;
+
+ int a = cur.hashCode();
+ int b = obj.hashCode();
+
+ return a - b;
+ }
+
+ /** Compare this reference to the specified object
+ * based on the {@link Object#hashCode()} if the
+ * references are not equals.
+ *
+ * @param o the object to be compared.
+ * @return a negative integer, zero, or a positive integer as this object
+ * is less than, equal to, or greater than the specified object.
+ */
+ @SuppressWarnings("unchecked")
+ public int compareToObject(T o) {
+ if (super.equals(o)) return 0;
+
+ T cur = get();
+
+ if ((cur==null)&&(o==null)) return 0;
+ if (cur==null) return -1;
+ if (o==null) return 1;
+
+ if (cur instanceof Comparable) {
+ Comparable cmp = (Comparable)cur;
+ return cmp.compareTo(o);
+ }
+
+ if ((cur==o)||(cur.equals(o))) return 0;
+
+ int a = cur.hashCode();
+ int b = o.hashCode();
+
+ return a - b;
+ }
+
+ /** {@inheritDoc}
+ *
+ * @return {@inheritDoc}
+ */
+ @Override
+ public String toString() {
+ StringBuffer buffer = new StringBuffer();
+ buffer.append('{');
+ T obj = get();
+ if (obj==null) buffer.append("#null#"); //$NON-NLS-1$
+ else buffer.append(obj.toString());
+ buffer.append('}');
+ return buffer.toString();
+ }
+
+}
Added: trunk/src/main/java/org/arakhne/util/ref/ComparableWeakReference.java
===================================================================
--- trunk/src/main/java/org/arakhne/util/ref/ComparableWeakReference.java (rev 0)
+++ trunk/src/main/java/org/arakhne/util/ref/ComparableWeakReference.java 2008-09-12 15:59:03 UTC (rev 2)
@@ -0,0 +1,172 @@
+/*
+ * $Id: ComparableWeakReference.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.lang.ref.WeakReference;
+
+/**
+ * This class is a WeakReference that allows to be
+ * compared on its pointed value.
+ *
+ * @param <T> is the type of the referenced object.
+ * @author Stéphane GALLAND <galland@xxxxxxxxxxx>
+ * @version $Name: $ $Revision: 1.1 $ $Date: 2007-02-20 08:52:37 $
+ */
+public class ComparableWeakReference<T> extends WeakReference<T> implements Comparable<Object> {
+
+ /**
+ * @param referent is the referenced object.
+ */
+ public ComparableWeakReference(T referent) {
+ super(referent);
+ }
+
+ /**
+ * @param referent is the referenced object.
+ * @param queue is the object that will be notified of the memory released for the referenced object.
+ */
+ public ComparableWeakReference(T referent, ReferenceQueue<? super T> queue) {
+ super(referent,queue);
+ }
+
+ /** {@inheritDoc}
+ *
+ * @param o {@inheritDoc}
+ * @return {@inheritDoc}
+ */
+ @SuppressWarnings("unchecked")
+ @Override
+ public boolean equals(Object o) {
+ if (super.equals(o)) return true;
+
+ try {
+ if (o instanceof Reference)
+ return (compareToRef((Reference)o)==0);
+
+ return compareToObject((T)o)==0;
+ }
+ catch(Exception _) {
+ return false;
+ }
+ }
+
+ /** Compare this reference to the specified object
+ * based on the {@link Object#hashCode()} if the
+ * references are not equals.
+ *
+ * @param o {@inheritDoc}
+ * @return {@inheritDoc}
+ */
+ @SuppressWarnings("unchecked")
+ public int compareTo(Object o) {
+ try {
+ if (o instanceof Reference)
+ return compareToRef((Reference)o);
+
+ return compareToObject((T)o);
+ }
+ catch(Exception _) {
+ int a = hashCode();
+ int b = o.hashCode();
+ return a - b;
+ }
+ }
+
+ /** Compare this reference to the specified object
+ * based on the {@link Object#hashCode()} if the
+ * references are not equals.
+ *
+ * @param o the object to be compared.
+ * @return a negative integer, zero, or a positive integer as this object
+ * is less than, equal to, or greater than the specified object.
+ */
+ @SuppressWarnings("unchecked")
+ public int compareToObject(T o) {
+ if (super.equals(o)) return 0;
+
+ T cur = get();
+
+ if ((cur==null)&&(o==null)) return 0;
+ if (cur==null) return -1;
+ if (o==null) return 1;
+
+ if (cur instanceof Comparable) {
+ Comparable cmp = (Comparable)cur;
+ return cmp.compareTo(o);
+ }
+
+ if ((cur==o)||(cur.equals(o))) return 0;
+
+ int a = cur.hashCode();
+ int b = o.hashCode();
+
+ return a - b;
+ }
+
+ /** Compare this reference to the specified object
+ * based on the {@link Object#hashCode()} if the
+ * references are not equals.
+ *
+ * @param o the object to be compared.
+ * @return a negative integer, zero, or a positive integer as this object
+ * is less than, equal to, or greater than the specified object.
+ */
+ @SuppressWarnings("unchecked")
+ public int compareToRef(Reference<T> o) {
+ Object obj = o.get();
+ Object cur = get();
+
+ if (((cur==null)&&(obj==null))||(obj==cur)) return 0;
+ if (cur==null) return -1;
+ if (obj==null) return 1;
+
+ if (cur instanceof Comparable) {
+ Comparable cmp = (Comparable)cur;
+ return cmp.compareTo(obj);
+ }
+
+ if ((cur==obj)||(cur.equals(obj))) return 0;
+
+ int a = cur.hashCode();
+ int b = obj.hashCode();
+
+ return a - b;
+ }
+
+ /** {@inheritDoc}
+ *
+ * @return {@inheritDoc}
+ */
+ @Override
+ public String toString() {
+ StringBuffer buffer = new StringBuffer();
+ buffer.append('{');
+ T obj = get();
+ if (obj==null) buffer.append("#null#"); //$NON-NLS-1$
+ else buffer.append(obj.toString());
+ buffer.append('}');
+ return buffer.toString();
+ }
+
+}
Added: trunk/src/main/java/org/arakhne/util/ref/SoftValueMap.java
===================================================================
--- trunk/src/main/java/org/arakhne/util/ref/SoftValueMap.java (rev 0)
+++ trunk/src/main/java/org/arakhne/util/ref/SoftValueMap.java 2008-09-12 15:59:03 UTC (rev 2)
@@ -0,0 +1,448 @@
+/*
+ * $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.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
+ * <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}.
+ * <p>
+ * This class has a special flag which permits to control the
+ * way how the released references are expurged: {@link #isDeeplyExpurge()},
+ * {@link #setDeeplyExpurge(boolean)}. If this flag is <code>true</code>,
+ * all the released references will be immediately removed from the map even
+ * if they are not enqueued by the virtual machine (see {@link #expurge()}.
+ * If this flag is <code>false</code>,
+ * only the enqueued references will be removed from the map
+ * (see {@link #expurgeQueuedReferences()}.
+ * <p>
+ * If this map does not use a "deep expurge" of the released references,
+ * it could contains <code>null</code> values that corresponds to
+ * values that are released by the garbage collector. If a "deep expurge"
+ * is used, all the values released by the garbage collector will be
+ * removed from the map.
+ * <p>
+ * "Deep expurge" consumes much more time that "No deep expurge". This is the
+ * reason why this feature is not activated by default.
+ * <p>
+ * The "deep expurge" feature was added to fix the uncoherent behavior
+ * of the garbage collector which seems to not always enqueued the
+ * released values (sometimes the queue is empty even if a value was released).
+ *
+ * @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 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)
+ */
+ @SuppressWarnings("unchecked")
+ 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.
+ *
+ * @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 SoftValueMap(int initialCapacity, float loadFactor) {
+ this.map = new HashMap<K,Value<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 SoftValueMap(int initialCapacity) {
+ this.map = new HashMap<K,Value<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 SoftValueMap() {
+ this.map = new HashMap<K,Value<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 SoftValueMap(Map<? extends K, ? extends V> m) {
+ this.map = new HashMap<K,Value<K,V>>();
+ this.entrySet = new EntrySet();
+ putAll(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 Entry) {
+ this.map.remove(((Entry<K,V>)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 Entry) {
+ this.map.remove(((Entry<K,V>)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 Value<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 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.
+ */
+ Value(K k, V v, ReferenceQueue<V> queue) {
+ super(maskNull(v), queue);
+ this.k = k;
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @return {@inheritDoc}
+ */
+ @Override
+ public String toString() {
+ StringBuffer buffer = new StringBuffer();
+ buffer.append('{');
+ K key = getKey();
+ buffer.append(key==null ? null : key.toString());
+ buffer.append('=');
+ if (isEnqueued()) {
+ buffer.append("Q#"); //$NON-NLS-1$
+ }
+ else {
+ buffer.append("P#"); //$NON-NLS-1$
+ }
+ V v = getValue();
+ buffer.append((v==null ? null : v.toString()));
+ buffer.append('}');
+ return buffer.toString();
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @return {@inheritDoc}
+ */
+ public K getKey() {
+ return this.k;
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @return {@inheritDoc}
+ */
+ public V getValue() {
+ return unmaskNull(get());
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @param o {@inheritDoc}
+ * @return {@inheritDoc}
+ */
+ public V setValue(V o) {
+ throw new UnsupportedOperationException();
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @return {@inheritDoc}
+ */
+ @Override
+ public int hashCode() {
+ Object val = getValue();
+ return (getKey()==null ? 0 : getKey().hashCode()) ^
+ (val==null ? 0 : val.hashCode());
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @param o {@inheritDoc}
+ * @return {@inheritDoc}
+ */
+ @SuppressWarnings("unchecked")
+ @Override
+ public boolean equals(Object o) {
+ if (o instanceof Entry) {
+ Entry<K,V> e = (Entry<K,V>)o;
+ Object e1val = getValue();
+ Object e2val = e.getValue();
+ return (getKey()==null ?
+ e.getKey()==null : getKey().equals(e.getKey())) &&
+ (e1val==null ? e2val==null : e1val.equals(e2val));
+ }
+ return false;
+ }
+
+ }
+
+}
Added: trunk/src/main/java/org/arakhne/util/ref/WeakArrayList.java
===================================================================
--- trunk/src/main/java/org/arakhne/util/ref/WeakArrayList.java (rev 0)
+++ trunk/src/main/java/org/arakhne/util/ref/WeakArrayList.java 2008-09-12 15:59:03 UTC (rev 2)
@@ -0,0 +1,400 @@
+/*
+ * $Id: WeakArrayList.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.lang.ref.WeakReference;
+import java.util.AbstractList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.List;
+
+/**
+ * A array-based <tt>List</tt> implementation with <em>weak keys</em>.
+ * An entry in a <tt>WeakArrayList</tt> will automatically be removed when
+ * it is no longer in ordinary use.
+ *
+ * <p> The behavior of the <tt>WeakArrayList</tt> class depends in part upon
+ * the actions of the garbage collector, so several familiar (though not
+ * required) <tt>List</tt> invariants do not hold for this class. Because
+ * the garbage collector may discard values at any time, a
+ * <tt>WeakArrayList</tt> may behave as though an unknown thread is silently
+ * removing entries. In particular, even if you synchronize on a
+ * <tt>WeakArrayList</tt> instance and invoke none of its mutator methods, it
+ * is possible for the <tt>size</tt> method to return smaller values over
+ * time, for the <tt>isEmpty</tt> method to return <tt>false</tt> and
+ * then <tt>true</tt>, for the <tt>contains</tt> method to return
+ * <tt>true</tt> and later <tt>false</tt> for a given value, for the
+ * <tt>get</tt> method to return a value for a given key but later return
+ * <tt>null</tt>, for the <tt>add</tt> method to return
+ * <tt>null</tt> and the <tt>remove</tt> method to return
+ * <tt>false</tt> for a value that previously appeared to be in the list.
+ * <p>
+ * This class has a special flag which permits to control the
+ * way how the released references are expurged: {@link #isDeeplyExpurge()},
+ * {@link #setDeeplyExpurge(boolean)}. If this flag is <code>true</code>,
+ * all the released references will be immediately removed from the map even
+ * if they are not enqueued by the virtual machine (see {@link #expurge()}.
+ * If this flag is <code>false</code>,
+ * only the enqueued references will be removed from the map
+ * (see {@link #expurgeQueuedReferences()}.
+ * <p>
+ * If this map does not use a "deep expurge" of the released references,
+ * it could contains <code>null</code> values that corresponds to
+ * values that are released by the garbage collector. If a "deep expurge"
+ * is used, all the values released by the garbage collector will be
+ * removed from the map.
+ * <p>
+ * "Deep expurge" consumes much more time that "No deep expurge". This is the
+ * reason why this feature is not activated by default.
+ * <p>
+ * The "deep expurge" feature was added to fix the uncoherent behavior
+ * of the garbage collector which seems to not always enqueued the
+ * released values (sometimes the queue is empty even if a value was released).
+ *
+ * @param <T> is the type of the array's elements.
+ * @author Stéphane GALLAND <galland@xxxxxxxxxxx>
+ * @version $Name: $ $Revision: 1.1 $ $Date: 2007-02-20 08:52:37 $
+ */
+public class WeakArrayList<T> extends AbstractList<T> implements List<T> {
+
+ private static final long serialVersionUID = 2601162363164961860L;
+
+ /** This value represents a null value given by the user.
+ */
+ private static final Object NULL_VALUE = new Object();
+
+ /** Replies the null value given by the user by the corresponding null object.
+ */
+ @SuppressWarnings("unchecked")
+ private T maskNull(T value) {
+ return (value==null) ? (T)NULL_VALUE : value;
+ }
+
+ /** Replies the value given by the user.
+ */
+ private T unmaskNull(T value) {
+ return (value==NULL_VALUE) ? null : value;
+ }
+
+ private final transient ReferenceQueue<T> queue = new ReferenceQueue<T>();
+
+ private Object[] data;
+
+ private int size;
+
+ private boolean autoExpurge = false;
+
+ /**
+ * Constructs an empty list with the specified initial capacity.
+ *
+ * @param initialCapacity the initial capacity of the list
+ * @exception IllegalArgumentException if the specified initial capacity
+ * is negative
+ */
+ public WeakArrayList(int initialCapacity) {
+ if (initialCapacity < 0)
+ throw new IllegalArgumentException("Illegal Capacity: "+initialCapacity); //$NON-NLS-1$
+ this.data = new Object[initialCapacity];
+ this.size = 0;
+ }
+
+ /**
+ * Constructs an empty list with an initial capacity of ten.
+ */
+ public WeakArrayList() {
+ this(10);
+ }
+
+ /**
+ * Constructs a list containing the elements of the specified
+ * collection, in the order they are returned by the collection's
+ * iterator.
+ *
+ * @param c the collection whose elements are to be placed into this list
+ * @throws NullPointerException if the specified collection is null
+ */
+ public WeakArrayList(Collection<? extends T> c) {
+ this.data = new Object[c.size()];
+ this.size = this.data.length;
+ int i=0;
+ for (T t : c) {
+ this.data[i] = createRef(t);
+ i++;
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @return {@inheritDoc}
+ */
+ @Override
+ @SuppressWarnings("unchecked")
+ public String toString() {
+ StringBuffer buffer = new StringBuffer();
+ Reference<T> ref;
+ T obj;
+ for(int i=0; i<this.size; i++) {
+ ref = (Reference<T>)this.data[i];
+ obj = ref.get();
+ buffer.append('{');
+ buffer.append(obj==null ? null : obj.toString());
+ buffer.append('}');
+ }
+ return buffer.toString();
+ }
+
+ /** Create and replies the reference for the specified object.
+ *
+ * @param obj is the object on which a weak reference must be attached.
+ * @return the weak reference.
+ */
+ private Reference<T> createRef(T obj) {
+ return new WeakReference<T>(maskNull(obj), this.queue);
+ }
+
+ /**
+ * Increases the capacity of this <tt>WeakArrayList</tt> instance, if
+ * necessary, to ensure that it can hold at least the number of elements
+ * specified by the minimum capacity argument.
+ *
+ * @param minCapacity the desired minimum capacity
+ */
+ public void ensureCapacity(int minCapacity) {
+ this.modCount++;
+ int oldCapacity = this.data.length;
+ if (minCapacity > oldCapacity) {
+ Object[] oldData = this.data;
+ int newCapacity = (oldCapacity * 3)/2 + 1;
+ if (newCapacity < minCapacity)
+ newCapacity = minCapacity;
+ // minCapacity is usually close to size, so this is a win:
+ this.data = Arrays.copyOf(oldData, newCapacity);
+ }
+ }
+
+ /**
+ * Trims the capacity of this <tt>WeakArrayList</tt> instance to be the
+ * list's current size. An application can use this operation to minimize
+ * the storage of an <tt>WeakArrayList</tt> instance.
+ */
+ public void trimToSize() {
+ this.modCount++;
+ int oldCapacity = this.data.length;
+ if (this.size < oldCapacity) {
+ this.data = Arrays.copyOf(this.data, this.size);
+ }
+ }
+
+ /** Clean the references that was marked as released inside
+ * the queue.
+ *
+ * @return the count of expurged elements.
+ */
+ protected int expurgeNow() {
+ if (this.autoExpurge)
+ return expurge();
+ return 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 array list deeply expurge the
+ * released elements, 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.
+ *
+ * @return the size
+ */
+ public int expurgeQueuedReferences() {
+ synchronized (this.queue) {
+ // Expurge the array only if a referenced
+ // object was marked as releasable
+ Reference<? extends T> ref = this.queue.poll();
+ if (ref!=null) {
+ return expurge();
+ }
+ return this.size;
+ }
+ }
+
+ /** Clean the references that was released.
+ *
+ * @return the size
+ */
+ @SuppressWarnings("unchecked")
+ public int expurge() {
+ synchronized(this.queue) {
+ Reference<? extends T> ref = this.queue.poll();
+ while (ref!=null) {
+ ref.clear();
+ ref = this.queue.poll();
+ }
+
+ // Clear the table
+ for(int i=this.size-1; i>=0; i--) {
+ ref = (Reference<T>)this.data[i];
+ assert(ref!=null);
+ if ((ref.isEnqueued())||(ref.get()==null)) {
+ ref.enqueue();
+ ref.clear();
+ System.arraycopy(
+ this.data, i+1,
+ this.data, i,
+ this.size - i - 1);
+ this.size --;
+ }
+ }
+
+ ref = this.queue.poll();
+ while (ref!=null) {
+ ref.clear();
+ ref = this.queue.poll();
+ }
+ return this.size;
+ }
+ }
+
+ /** Verify if the specified index is inside the array.
+ *
+ * @param index is the index totest
+ * @param allowLast indicates if the last elements is assumed to be valid or not.
+ */
+ protected void assertRange(int index, boolean allowLast) {
+ int size = expurgeNow();
+ if (index<0)
+ throw new IndexOutOfBoundsException("invalid negative value: "+Integer.toString(index)); //$NON-NLS-1$
+ if ((allowLast)&&(index>size))
+ throw new IndexOutOfBoundsException("index>"+size+": "+Integer.toString(index)); //$NON-NLS-1$ //$NON-NLS-2$
+ if ((!allowLast)&&(index>=size))
+ throw new IndexOutOfBoundsException("index>="+size+": "+Integer.toString(index)); //$NON-NLS-1$ //$NON-NLS-2$
+ }
+
+ /** {@inheritDoc}
+ */
+ @Override
+ public int size() {
+ synchronized(this.queue) {
+ return expurgeNow();
+ }
+ }
+
+ /** {@inheritDoc}
+ */
+ @SuppressWarnings("unchecked")
+ @Override
+ public T get(int index) {
+ synchronized(this.queue) {
+ T value;
+ do {
+ assertRange(index,false);
+ value = ((Reference<T>)this.data[index]).get();
+ }
+ while (value==null);
+ return unmaskNull(value);
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @SuppressWarnings("unchecked")
+ @Override
+ public T set(int index, T element) {
+ synchronized(this.queue) {
+ T oldValue;
+ Reference<T> ref;
+ do {
+ assertRange(index, false);
+ ref = (Reference<T>)this.data[index];
+ oldValue = ref.get();
+ }
+ while (oldValue==null);
+ ref.clear();
+ this.data[index] = createRef(element);
+ this.modCount++;
+ return unmaskNull(oldValue);
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void add(int index, T element) {
+ synchronized(this.queue) {
+ assertRange(index,true);
+ ensureCapacity(this.size+1);
+ System.arraycopy(this.data, index, this.data, index+1, this.size-index);
+ this.data[index] = createRef(element);
+ this.size++;
+ this.modCount++;
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @SuppressWarnings("unchecked")
+ @Override
+ public T remove(int index) {
+ synchronized(this.queue) {
+ T oldValue;
+ Reference<T> ref;
+ do {
+ assertRange(index, false);
+ ref = (Reference<T>)this.data[index];
+ oldValue = ref.get();
+ }
+ while (oldValue==null);
+ ref.clear();
+ System.arraycopy(this.data, index+1, this.data, index, this.size-index-1);
+ this.data[this.size-1] = null;
+ this.size--;
+ this.modCount++;
+ return unmaskNull(oldValue);
+ }
+ }
+
+}
Added: trunk/src/main/java/org/arakhne/util/ref/WeakValueMap.java
===================================================================
--- trunk/src/main/java/org/arakhne/util/ref/WeakValueMap.java (rev 0)
+++ trunk/src/main/java/org/arakhne/util/ref/WeakValueMap.java 2008-09-12 15:59:03 UTC (rev 2)
@@ -0,0 +1,450 @@
+/*
+ * $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.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;
+
+/**
+ * A <tt>Map</tt> implementation with <em>weak values</em>. An entry in a
+ * <tt>WeakValueMap</tt> will automatically be removed when its value is no
+ * longer in ordinary use or null.
+ * <p>
+ * This class was inspirated from {@link WeakHashMap}
+ * <p>
+ * This class has a special flag which permits to control the
+ * way how the released references are expurged: {@link #isDeeplyExpurge()},
+ * {@link #setDeeplyExpurge(boolean)}. If this flag is <code>true</code>,
+ * all the released references will be immediately removed from the map even
+ * if they are not enqueued by the virtual machine (see {@link #expurge()}.
+ * If this flag is <code>false</code>,
+ * only the enqueued references will be removed from the map
+ * (see {@link #expurgeQueuedReferences()}.
+ * <p>
+ * If this map does not use a "deep expurge" of the released references,
+ * it could contains <code>null</code> values that corresponds to
+ * values that are released by the garbage collector. If a "deep expurge"
+ * is used, all the values released by the garbage collector will be
+ * removed from the map.
+ * <p>
+ * "Deep expurge" consumes much more time that "No deep expurge". This is the
+ * reason why this feature is not activated by default.
+ * <p>
+ * The "deep expurge" feature was added to fix the uncoherent behavior
+ * of the garbage collector which seems to not always enqueued the
+ * released values (sometimes the queue is empty even if a value was released).
+ *
+ * @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 class WeakValueMap<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)
+ */
+ @SuppressWarnings("unchecked")
+ 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.
+ *
+ * @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 WeakValueMap(int initialCapacity, float loadFactor) {
+ this.map = new HashMap<K,Value<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 WeakValueMap(int initialCapacity) {
+ this.map = new HashMap<K,Value<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 WeakValueMap() {
+ this.map = new HashMap<K,Value<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 WeakValueMap(Map<? extends K, ? extends V> m) {
+ this.map = new HashMap<K,Value<K,V>>();
+ this.entrySet = new EntrySet();
+ putAll(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 Entry) {
+ this.map.remove(((Entry<K,V>)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 Entry) {
+ this.map.remove(((Entry<K,V>)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 Value<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 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;
+
+ /**
+ * @param k is the key.
+ * @param v is the value.
+ * @param queue is the memory-release listener.
+ */
+ Value(K k, V v, ReferenceQueue<V> queue) {
+ super(maskNull(v), queue);
+ this.k = k;
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @return {@inheritDoc}
+ */
+ @Override
+ public String toString() {
+ StringBuffer buffer = new StringBuffer();
+ buffer.append('{');
+ K key = getKey();
+ buffer.append(key==null ? null : key.toString());
+ buffer.append('=');
+ if (isEnqueued()) {
+ buffer.append("Q#"); //$NON-NLS-1$
+ }
+ else {
+ buffer.append("P#"); //$NON-NLS-1$
+ }
+ V v = getValue();
+ buffer.append((v==null ? null : v.toString()));
+ buffer.append('}');
+ return buffer.toString();
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @return {@inheritDoc}
+ */
+ public K getKey() {
+ return this.k;
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @return {@inheritDoc}
+ */
+ public V getValue() {
+ return unmaskNull(get());
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @param o {@inheritDoc}
+ * @return {@inheritDoc}
+ */
+ public V setValue(V o) {
+ throw new UnsupportedOperationException();
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @return {@inheritDoc}
+ */
+ @Override
+ public int hashCode() {
+ Object val = getValue();
+ return (getKey()==null ? 0 : getKey().hashCode()) ^
+ (val==null ? 0 : val.hashCode());
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @param o {@inheritDoc}
+ * @return {@inheritDoc}
+ */
+ @SuppressWarnings("unchecked")
+ @Override
+ public boolean equals(Object o) {
+ if (o instanceof Entry) {
+ Entry<K,V> e = (Entry<K,V>)o;
+ Object e1val = getValue();
+ Object e2val = e.getValue();
+ return (getKey()==null ?
+ e.getKey()==null : getKey().equals(e.getKey())) &&
+ (e1val==null ? e2val==null : e1val.equals(e2val));
+ }
+ return false;
+ }
+
+ }
+
+}
Added: trunk/src/main/resources/AUTHORS
===================================================================
--- trunk/src/main/resources/AUTHORS (rev 0)
+++ trunk/src/main/resources/AUTHORS 2008-09-12 15:59:03 UTC (rev 2)
@@ -0,0 +1 @@
+Stephane GALLAND <galland@xxxxxxxxxxx>
Added: trunk/src/main/resources/COPYING
===================================================================
--- trunk/src/main/resources/COPYING (rev 0)
+++ trunk/src/main/resources/COPYING 2008-09-12 15:59:03 UTC (rev 2)
@@ -0,0 +1,165 @@
+ GNU LESSER GENERAL PUBLIC LICENSE
+ Version 3, 29 June 2007
+
+ Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+
+ This version of the GNU Lesser General Public License incorporates
+the terms and conditions of version 3 of the GNU General Public
+License, supplemented by the additional permissions listed below.
+
+ 0. Additional Definitions.
+
+ As used herein, "this License" refers to version 3 of the GNU Lesser
+General Public License, and the "GNU GPL" refers to version 3 of the GNU
+General Public License.
+
+ "The Library" refers to a covered work governed by this License,
+other than an Application or a Combined Work as defined below.
+
+ An "Application" is any work that makes use of an interface provided
+by the Library, but which is not otherwise based on the Library.
+Defining a subclass of a class defined by the Library is deemed a mode
+of using an interface provided by the Library.
+
+ A "Combined Work" is a work produced by combining or linking an
+Application with the Library. The particular version of the Library
+with which the Combined Work was made is also called the "Linked
+Version".
+
+ The "Minimal Corresponding Source" for a Combined Work means the
+Corresponding Source for the Combined Work, excluding any source code
+for portions of the Combined Work that, considered in isolation, are
+based on the Application, and not on the Linked Version.
+
+ The "Corresponding Application Code" for a Combined Work means the
+object code and/or source code for the Application, including any data
+and utility programs needed for reproducing the Combined Work from the
+Application, but excluding the System Libraries of the Combined Work.
+
+ 1. Exception to Section 3 of the GNU GPL.
+
+ You may convey a covered work under sections 3 and 4 of this License
+without being bound by section 3 of the GNU GPL.
+
+ 2. Conveying Modified Versions.
+
+ If you modify a copy of the Library, and, in your modifications, a
+facility refers to a function or data to be supplied by an Application
+that uses the facility (other than as an argument passed when the
+facility is invoked), then you may convey a copy of the modified
+version:
+
+ a) under this License, provided that you make a good faith effort to
+ ensure that, in the event an Application does not supply the
+ function or data, the facility still operates, and performs
+ whatever part of its purpose remains meaningful, or
+
+ b) under the GNU GPL, with none of the additional permissions of
+ this License applicable to that copy.
+
+ 3. Object Code Incorporating Material from Library Header Files.
+
+ The object code form of an Application may incorporate material from
+a header file that is part of the Library. You may convey such object
+code under terms of your choice, provided that, if the incorporated
+material is not limited to numerical parameters, data structure
+layouts and accessors, or small macros, inline functions and templates
+(ten or fewer lines in length), you do both of the following:
+
+ a) Give prominent notice with each copy of the object code that the
+ Library is used in it and that the Library and its use are
+ covered by this License.
+
+ b) Accompany the object code with a copy of the GNU GPL and this license
+ document.
+
+ 4. Combined Works.
+
+ You may convey a Combined Work under terms of your choice that,
+taken together, effectively do not restrict modification of the
+portions of the Library contained in the Combined Work and reverse
+engineering for debugging such modifications, if you also do each of
+the following:
+
+ a) Give prominent notice with each copy of the Combined Work that
+ the Library is used in it and that the Library and its use are
+ covered by this License.
+
+ b) Accompany the Combined Work with a copy of the GNU GPL and this license
+ document.
+
+ c) For a Combined Work that displays copyright notices during
+ execution, include the copyright notice for the Library among
+ these notices, as well as a reference directing the user to the
+ copies of the GNU GPL and this license document.
+
+ d) Do one of the following:
+
+ 0) Convey the Minimal Corresponding Source under the terms of this
+ License, and the Corresponding Application Code in a form
+ suitable for, and under terms that permit, the user to
+ recombine or relink the Application with a modified version of
+ the Linked Version to produce a modified Combined Work, in the
+ manner specified by section 6 of the GNU GPL for conveying
+ Corresponding Source.
+
+ 1) Use a suitable shared library mechanism for linking with the
+ Library. A suitable mechanism is one that (a) uses at run time
+ a copy of the Library already present on the user's computer
+ system, and (b) will operate properly with a modified version
+ of the Library that is interface-compatible with the Linked
+ Version.
+
+ e) Provide Installation Information, but only if you would otherwise
+ be required to provide such information under section 6 of the
+ GNU GPL, and only to the extent that such information is
+ necessary to install and execute a modified version of the
+ Combined Work produced by recombining or relinking the
+ Application with a modified version of the Linked Version. (If
+ you use option 4d0, the Installation Information must accompany
+ the Minimal Corresponding Source and Corresponding Application
+ Code. If you use option 4d1, you must provide the Installation
+ Information in the manner specified by section 6 of the GNU GPL
+ for conveying Corresponding Source.)
+
+ 5. Combined Libraries.
+
+ You may place library facilities that are a work based on the
+Library side by side in a single library together with other library
+facilities that are not Applications and are not covered by this
+License, and convey such a combined library under terms of your
+choice, if you do both of the following:
+
+ a) Accompany the combined library with a copy of the same work based
+ on the Library, uncombined with any other library facilities,
+ conveyed under the terms of this License.
+
+ b) Give prominent notice with the combined library that part of it
+ is a work based on the Library, and explaining where to find the
+ accompanying uncombined form of the same work.
+
+ 6. Revised Versions of the GNU Lesser General Public License.
+
+ The Free Software Foundation may publish revised and/or new versions
+of the GNU Lesser General Public License from time to time. Such new
+versions will be similar in spirit to the present version, but may
+differ in detail to address new problems or concerns.
+
+ Each version is given a distinguishing version number. If the
+Library as you received it specifies that a certain numbered version
+of the GNU Lesser General Public License "or any later version"
+applies to it, you have the option of following the terms and
+conditions either of that published version or of any later version
+published by the Free Software Foundation. If the Library as you
+received it does not specify a version number of the GNU Lesser
+General Public License, you may choose any version of the GNU Lesser
+General Public License ever published by the Free Software Foundation.
+
+ If the Library as you received it specifies that a proxy can decide
+whether future versions of the GNU Lesser General Public License shall
+apply, that proxy's public statement of acceptance of any version is
+permanent authorization for you to choose that version for the
+Library.
Added: trunk/src/main/resources/Changelog
===================================================================
--- trunk/src/main/resources/Changelog (rev 0)
+++ trunk/src/main/resources/Changelog 2008-09-12 15:59:03 UTC (rev 2)
@@ -0,0 +1,17 @@
+arakhneRefs-3.0
+
+ * Add the class SoftValueMap
+
+ -- Stephane GALLAND <galland@xxxxxxxxxxx> Mon, 18 Feb 2008 20:04:24 +0100
+
+arakhneRefs-2.0
+
+ * Bug fixes inside the weak data structures
+
+ -- Stephane GALLAND <galland@xxxxxxxxxxx> Mon, 31 Dec 2007 12:24:59 +0100
+
+arakhneRefs-1.0
+
+ * First public release.
+
+ -- Stephane GALLAND <galland@xxxxxxxxxxx>
Added: trunk/src/main/resources/VERSION
===================================================================
--- trunk/src/main/resources/VERSION (rev 0)
+++ trunk/src/main/resources/VERSION 2008-09-12 15:59:03 UTC (rev 2)
@@ -0,0 +1 @@
+arakhneRefs 3.0