169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal/*
269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * Javassist, a Java-bytecode translator toolkit.
369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * Copyright (C) 1999-2007 Shigeru Chiba. All Rights Reserved.
469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal *
569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * The contents of this file are subject to the Mozilla Public License Version
669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * 1.1 (the "License"); you may not use this file except in compliance with
769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * the License.  Alternatively, the contents of this file may be used under
869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * the terms of the GNU Lesser General Public License Version 2.1 or later.
969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal *
1069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * Software distributed under the License is distributed on an "AS IS" basis,
1169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
1269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * for the specific language governing rights and limitations under the
1369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * License.
1469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal */
1569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
1669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigalpackage javassist.scopedpool;
1769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
1869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigalimport java.lang.ref.ReferenceQueue;
1969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigalimport java.lang.ref.SoftReference;
2069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigalimport java.util.AbstractMap;
2169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigalimport java.util.HashMap;
2269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigalimport java.util.Map;
2369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigalimport java.util.Set;
2469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
2569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal/**
2669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * This Map will remove entries when the value in the map has been cleaned from
2769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * garbage collection
2869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal *
2969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * @version <tt>$Revision: 1.4 $</tt>
3069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * @author <a href="mailto:bill@jboss.org">Bill Burke</a>
3169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal */
3269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigalpublic class SoftValueHashMap extends AbstractMap implements Map {
3369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    private static class SoftValueRef extends SoftReference {
3469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        public Object key;
3569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
3669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        private SoftValueRef(Object key, Object val, ReferenceQueue q) {
3769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            super(val, q);
3869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            this.key = key;
3969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        }
4069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
4169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        private static SoftValueRef create(Object key, Object val,
4269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal                ReferenceQueue q) {
4369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            if (val == null)
4469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal                return null;
4569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            else
4669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal                return new SoftValueRef(key, val, q);
4769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        }
4869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
4969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    }
5069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
5169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    /**
5269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * Returns a set of the mappings contained in this hash table.
5369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     */
5469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    public Set entrySet() {
5569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        processQueue();
5669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        return hash.entrySet();
5769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    }
5869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
5969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    /* Hash table mapping WeakKeys to values */
6069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    private Map hash;
6169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
6269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    /* Reference queue for cleared WeakKeys */
6369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    private ReferenceQueue queue = new ReferenceQueue();
6469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
6569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    /*
6669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * Remove all invalidated entries from the map, that is, remove all entries
6769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * whose values have been discarded.
6869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     */
6969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    private void processQueue() {
7069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        SoftValueRef ref;
7169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        while ((ref = (SoftValueRef)queue.poll()) != null) {
7269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            if (ref == (SoftValueRef)hash.get(ref.key)) {
7369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal                // only remove if it is the *exact* same WeakValueRef
7469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal                //
7569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal                hash.remove(ref.key);
7669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            }
7769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        }
7869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    }
7969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
8069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    /* -- Constructors -- */
8169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
8269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    /**
8369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * Constructs a new, empty <code>WeakHashMap</code> with the given initial
8469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * capacity and the given load factor.
8569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     *
8669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * @param initialCapacity
8769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     *            The initial capacity of the <code>WeakHashMap</code>
8869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     *
8969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * @param loadFactor
9069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     *            The load factor of the <code>WeakHashMap</code>
9169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     *
9269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * @throws IllegalArgumentException
9369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     *             If the initial capacity is less than zero, or if the load
9469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     *             factor is nonpositive
9569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     */
9669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    public SoftValueHashMap(int initialCapacity, float loadFactor) {
9769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        hash = new HashMap(initialCapacity, loadFactor);
9869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    }
9969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
10069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    /**
10169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * Constructs a new, empty <code>WeakHashMap</code> with the given initial
10269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * capacity and the default load factor, which is <code>0.75</code>.
10369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     *
10469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * @param initialCapacity
10569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     *            The initial capacity of the <code>WeakHashMap</code>
10669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     *
10769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * @throws IllegalArgumentException
10869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     *             If the initial capacity is less than zero
10969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     */
11069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    public SoftValueHashMap(int initialCapacity) {
11169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        hash = new HashMap(initialCapacity);
11269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    }
11369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
11469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    /**
11569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * Constructs a new, empty <code>WeakHashMap</code> with the default
11669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * initial capacity and the default load factor, which is <code>0.75</code>.
11769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     */
11869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    public SoftValueHashMap() {
11969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        hash = new HashMap();
12069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    }
12169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
12269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    /**
12369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * Constructs a new <code>WeakHashMap</code> with the same mappings as the
12469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * specified <tt>Map</tt>. The <code>WeakHashMap</code> is created with
12569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * an initial capacity of twice the number of mappings in the specified map
12669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * or 11 (whichever is greater), and a default load factor, which is
12769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * <tt>0.75</tt>.
12869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     *
12969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * @param t     the map whose mappings are to be placed in this map.
13069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     */
13169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    public SoftValueHashMap(Map t) {
13269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        this(Math.max(2 * t.size(), 11), 0.75f);
13369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        putAll(t);
13469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    }
13569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
13669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    /* -- Simple queries -- */
13769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
13869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    /**
13969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * Returns the number of key-value mappings in this map. <strong>Note:</strong>
14069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * <em>In contrast with most implementations of the
14169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * <code>Map</code> interface, the time required by this operation is
14269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * linear in the size of the map.</em>
14369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     */
14469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    public int size() {
14569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        processQueue();
14669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        return hash.size();
14769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    }
14869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
14969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    /**
15069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * Returns <code>true</code> if this map contains no key-value mappings.
15169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     */
15269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    public boolean isEmpty() {
15369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        processQueue();
15469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        return hash.isEmpty();
15569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    }
15669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
15769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    /**
15869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * Returns <code>true</code> if this map contains a mapping for the
15969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * specified key.
16069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     *
16169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * @param key
16269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     *            The key whose presence in this map is to be tested.
16369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     */
16469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    public boolean containsKey(Object key) {
16569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        processQueue();
16669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        return hash.containsKey(key);
16769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    }
16869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
16969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    /* -- Lookup and modification operations -- */
17069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
17169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    /**
17269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * Returns the value to which this map maps the specified <code>key</code>.
17369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * If this map does not contain a value for this key, then return
17469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * <code>null</code>.
17569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     *
17669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * @param key
17769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     *            The key whose associated value, if any, is to be returned.
17869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     */
17969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    public Object get(Object key) {
18069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        processQueue();
18169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        SoftReference ref = (SoftReference)hash.get(key);
18269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        if (ref != null)
18369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            return ref.get();
18469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        return null;
18569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    }
18669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
18769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    /**
18869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * Updates this map so that the given <code>key</code> maps to the given
18969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * <code>value</code>. If the map previously contained a mapping for
19069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * <code>key</code> then that mapping is replaced and the previous value
19169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * is returned.
19269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     *
19369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * @param key
19469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     *            The key that is to be mapped to the given <code>value</code>
19569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * @param value
19669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     *            The value to which the given <code>key</code> is to be
19769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     *            mapped
19869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     *
19969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * @return The previous value to which this key was mapped, or
20069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     *         <code>null</code> if if there was no mapping for the key
20169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     */
20269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    public Object put(Object key, Object value) {
20369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        processQueue();
20469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        Object rtn = hash.put(key, SoftValueRef.create(key, value, queue));
20569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        if (rtn != null)
20669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            rtn = ((SoftReference)rtn).get();
20769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        return rtn;
20869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    }
20969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
21069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    /**
21169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * Removes the mapping for the given <code>key</code> from this map, if
21269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * present.
21369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     *
21469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * @param key
21569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     *            The key whose mapping is to be removed.
21669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     *
21769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * @return The value to which this key was mapped, or <code>null</code> if
21869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     *         there was no mapping for the key.
21969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     */
22069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    public Object remove(Object key) {
22169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        processQueue();
22269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        return hash.remove(key);
22369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    }
22469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
22569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    /**
22669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * Removes all mappings from this map.
22769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     */
22869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    public void clear() {
22969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        processQueue();
23069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        hash.clear();
23169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    }
23269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal}
233