151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski/*
251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * Copyright (c) 1998, 2006, Oracle and/or its affiliates. All rights reserved.
351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski *
551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * This code is free software; you can redistribute it and/or modify it
651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * under the terms of the GNU General Public License version 2 only, as
751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * published by the Free Software Foundation.  Oracle designates this
851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * particular file as subject to the "Classpath" exception as provided
951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * by Oracle in the LICENSE file that accompanied this code.
1051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski *
1151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * This code is distributed in the hope that it will be useful, but WITHOUT
1251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
1351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
1451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * version 2 for more details (a copy is included in the LICENSE file that
1551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * accompanied this code).
1651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski *
1751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * You should have received a copy of the GNU General Public License version
1851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * 2 along with this work; if not, write to the Free Software Foundation,
1951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
2051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski *
2151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
2251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * or visit www.oracle.com if you need additional information or have any
2351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * questions.
2451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski */
2551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
2651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebskipackage sun.misc;
2751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
2851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebskiimport java.lang.ref.SoftReference;
2951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebskiimport java.lang.ref.ReferenceQueue;
3051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
3151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebskiimport java.util.Iterator;
3251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebskiimport java.util.Map;
3351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebskiimport java.util.AbstractMap;
3451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebskiimport java.util.HashMap;
3551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebskiimport java.util.Set;
3651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebskiimport java.util.AbstractSet;
3751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebskiimport java.util.NoSuchElementException;
3851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
3951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
4051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski/**
4151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * A memory-sensitive implementation of the <code>Map</code> interface.
4251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski *
4351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * <p> A <code>SoftCache</code> object uses {@link java.lang.ref.SoftReference
4451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * soft references} to implement a memory-sensitive hash map.  If the garbage
4551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * collector determines at a certain point in time that a value object in a
4651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * <code>SoftCache</code> entry is no longer strongly reachable, then it may
4751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * remove that entry in order to release the memory occupied by the value
4851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * object.  All <code>SoftCache</code> objects are guaranteed to be completely
4951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * cleared before the virtual machine will throw an
5051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * <code>OutOfMemoryError</code>.  Because of this automatic clearing feature,
5151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * the behavior of this class is somewhat different from that of other
5251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * <code>Map</code> implementations.
5351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski *
5451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * <p> Both null values and the null key are supported.  This class has the
5551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * same performance characteristics as the <code>HashMap</code> class, and has
5651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * the same efficiency parameters of <em>initial capacity</em> and <em>load
5751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * factor</em>.
5851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski *
5951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * <p> Like most collection classes, this class is not synchronized.  A
6051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * synchronized <code>SoftCache</code> may be constructed using the
6151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * <code>Collections.synchronizedMap</code> method.
6251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski *
6351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * <p> In typical usage this class will be subclassed and the <code>fill</code>
6451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * method will be overridden.  When the <code>get</code> method is invoked on a
6551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * key for which there is no mapping in the cache, it will in turn invoke the
6651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * <code>fill</code> method on that key in an attempt to construct a
6751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * corresponding value.  If the <code>fill</code> method returns such a value
6851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * then the cache will be updated and the new value will be returned.  Thus,
6951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * for example, a simple URL-content cache can be constructed as follows:
7051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski *
7151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * <pre>
7251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski *     public class URLCache extends SoftCache {
7351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski *         protected Object fill(Object key) {
7451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski *             return ((URL)key).getContent();
7551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski *         }
7651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski *     }
7751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * </pre>
7851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski *
7951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * <p> The behavior of the <code>SoftCache</code> class depends in part upon
8051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * the actions of the garbage collector, so several familiar (though not
8151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * required) <code>Map</code> invariants do not hold for this class.  <p>
8251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * Because entries are removed from a <code>SoftCache</code> in response to
8351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * dynamic advice from the garbage collector, a <code>SoftCache</code> may
8451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * behave as though an unknown thread is silently removing entries.  In
8551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * particular, even if you synchronize on a <code>SoftCache</code> instance and
8651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * invoke none of its mutator methods, it is possible for the <code>size</code>
8751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * method to return smaller values over time, for the <code>isEmpty</code>
8851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * method to return <code>false</code> and then <code>true</code>, for the
8951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * <code>containsKey</code> method to return <code>true</code> and later
9051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * <code>false</code> for a given key, for the <code>get</code> method to
9151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * return a value for a given key but later return <code>null</code>, for the
9251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * <code>put</code> method to return <code>null</code> and the
9351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * <code>remove</code> method to return <code>false</code> for a key that
9451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * previously appeared to be in the map, and for successive examinations of the
9551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * key set, the value set, and the entry set to yield successively smaller
9651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * numbers of elements.
9751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski *
9851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * @author      Mark Reinhold
9951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * @since       1.2
10051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * @see         java.util.HashMap
10151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * @see         java.lang.ref.SoftReference
10251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski */
10351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
10451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
10551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebskipublic class SoftCache extends AbstractMap implements Map {
10651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
10751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    /* The basic idea of this implementation is to maintain an internal HashMap
10851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski       that maps keys to soft references whose referents are the keys' values;
10951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski       the various accessor methods dereference these soft references before
11051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski       returning values.  Because we don't have access to the innards of the
11151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski       HashMap, each soft reference must contain the key that maps to it so
11251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski       that the processQueue method can remove keys whose values have been
11351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski       discarded.  Thus the HashMap actually maps keys to instances of the
11451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski       ValueCell class, which is a simple extension of the SoftReference class.
11551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     */
11651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
11751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
11851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    static private class ValueCell extends SoftReference {
11951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        static private Object INVALID_KEY = new Object();
12051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        static private int dropped = 0;
12151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        private Object key;
12251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
12351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        private ValueCell(Object key, Object value, ReferenceQueue queue) {
12451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            super(value, queue);
12551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            this.key = key;
12651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        }
12751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
12851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        private static ValueCell create(Object key, Object value,
12951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                                        ReferenceQueue queue)
13051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        {
13151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            if (value == null) return null;
13251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            return new ValueCell(key, value, queue);
13351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        }
13451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
13551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        private static Object strip(Object val, boolean drop) {
13651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            if (val == null) return null;
13751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            ValueCell vc = (ValueCell)val;
13851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            Object o = vc.get();
13951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            if (drop) vc.drop();
14051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            return o;
14151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        }
14251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
14351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        private boolean isValid() {
14451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            return (key != INVALID_KEY);
14551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        }
14651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
14751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        private void drop() {
14851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            super.clear();
14951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            key = INVALID_KEY;
15051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            dropped++;
15151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        }
15251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
15351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    }
15451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
15551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
15651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    /* Hash table mapping keys to ValueCells */
15751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    private Map hash;
15851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
15951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    /* Reference queue for cleared ValueCells */
16051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    private ReferenceQueue queue = new ReferenceQueue();
16151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
16251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
16351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    /* Process any ValueCells that have been cleared and enqueued by the
16451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski       garbage collector.  This method should be invoked once by each public
16551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski       mutator in this class.  We don't invoke this method in public accessors
16651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski       because that can lead to surprising ConcurrentModificationExceptions.
16751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     */
16851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    private void processQueue() {
16951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        ValueCell vc;
17051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        while ((vc = (ValueCell)queue.poll()) != null) {
17151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            if (vc.isValid()) hash.remove(vc.key);
17251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            else ValueCell.dropped--;
17351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        }
17451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    }
17551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
17651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
17751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    /* -- Constructors -- */
17851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
17951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    /**
18051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * Construct a new, empty <code>SoftCache</code> with the given
18151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * initial capacity and the given load factor.
18251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     *
18351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * @param  initialCapacity  The initial capacity of the cache
18451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     *
18551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * @param  loadFactor       A number between 0.0 and 1.0
18651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     *
18751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * @throws IllegalArgumentException  If the initial capacity is less than
18851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     *                                   or equal to zero, or if the load
18951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     *                                   factor is less than zero
19051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     */
19151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    public SoftCache(int initialCapacity, float loadFactor) {
19251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        hash = new HashMap(initialCapacity, loadFactor);
19351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    }
19451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
19551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    /**
19651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * Construct a new, empty <code>SoftCache</code> with the given
19751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * initial capacity and the default load factor.
19851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     *
19951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * @param  initialCapacity  The initial capacity of the cache
20051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     *
20151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * @throws IllegalArgumentException  If the initial capacity is less than
20251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     *                                   or equal to zero
20351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     */
20451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    public SoftCache(int initialCapacity) {
20551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        hash = new HashMap(initialCapacity);
20651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    }
20751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
20851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    /**
20951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * Construct a new, empty <code>SoftCache</code> with the default
21051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * capacity and the default load factor.
21151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     */
21251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    public SoftCache() {
21351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        hash = new HashMap();
21451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    }
21551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
21651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
21751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    /* -- Simple queries -- */
21851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
21951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    /**
22051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * Return the number of key-value mappings in this cache.  The time
22151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * required by this operation is linear in the size of the map.
22251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     */
22351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    public int size() {
22451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        return entrySet().size();
22551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    }
22651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
22751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    /**
22851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * Return <code>true</code> if this cache contains no key-value mappings.
22951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     */
23051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    public boolean isEmpty() {
23151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        return entrySet().isEmpty();
23251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    }
23351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
23451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    /**
23551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * Return <code>true</code> if this cache contains a mapping for the
23651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * specified key.  If there is no mapping for the key, this method will not
23751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * attempt to construct one by invoking the <code>fill</code> method.
23851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     *
23951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * @param   key   The key whose presence in the cache is to be tested
24051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     */
24151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    public boolean containsKey(Object key) {
24251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        return ValueCell.strip(hash.get(key), false) != null;
24351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    }
24451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
24551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
24651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    /* -- Lookup and modification operations -- */
24751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
24851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    /**
24951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * Create a value object for the given <code>key</code>.  This method is
25051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * invoked by the <code>get</code> method when there is no entry for
25151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * <code>key</code>.  If this method returns a non-<code>null</code> value,
25251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * then the cache will be updated to map <code>key</code> to that value,
25351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * and that value will be returned by the <code>get</code> method.
25451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     *
25551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * <p> The default implementation of this method simply returns
25651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * <code>null</code> for every <code>key</code> value.  A subclass may
25751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * override this method to provide more useful behavior.
25851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     *
25951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * @param  key  The key for which a value is to be computed
26051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     *
26151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * @return      A value for <code>key</code>, or <code>null</code> if one
26251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     *              could not be computed
26351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * @see #get
26451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     */
26551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    protected Object fill(Object key) {
26651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        return null;
26751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    }
26851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
26951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    /**
27051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * Return the value to which this cache maps the specified
27151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * <code>key</code>.  If the cache does not presently contain a value for
27251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * this key, then invoke the <code>fill</code> method in an attempt to
27351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * compute such a value.  If that method returns a non-<code>null</code>
27451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * value, then update the cache and return the new value.  Otherwise,
27551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * return <code>null</code>.
27651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     *
27751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * <p> Note that because this method may update the cache, it is considered
27851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * a mutator and may cause <code>ConcurrentModificationException</code>s to
27951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * be thrown if invoked while an iterator is in use.
28051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     *
28151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * @param  key  The key whose associated value, if any, is to be returned
28251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     *
28351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * @see #fill
28451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     */
28551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    public Object get(Object key) {
28651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        processQueue();
28751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        Object v = hash.get(key);
28851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        if (v == null) {
28951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            v = fill(key);
29051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            if (v != null) {
29151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                hash.put(key, ValueCell.create(key, v, queue));
29251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                return v;
29351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            }
29451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        }
29551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        return ValueCell.strip(v, false);
29651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    }
29751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
29851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    /**
29951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * Update this cache so that the given <code>key</code> maps to the given
30051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * <code>value</code>.  If the cache previously contained a mapping for
30151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * <code>key</code> then that mapping is replaced and the old value is
30251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * returned.
30351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     *
30451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * @param  key    The key that is to be mapped to the given
30551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     *                <code>value</code>
30651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * @param  value  The value to which the given <code>key</code> is to be
30751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     *                mapped
30851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     *
30951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * @return  The previous value to which this key was mapped, or
31051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     *          <code>null</code> if if there was no mapping for the key
31151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     */
31251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    public Object put(Object key, Object value) {
31351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        processQueue();
31451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        ValueCell vc = ValueCell.create(key, value, queue);
31551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        return ValueCell.strip(hash.put(key, vc), true);
31651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    }
31751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
31851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    /**
31951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * Remove the mapping for the given <code>key</code> from this cache, if
32051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * present.
32151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     *
32251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * @param  key  The key whose mapping is to be removed
32351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     *
32451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * @return  The value to which this key was mapped, or <code>null</code> if
32551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     *          there was no mapping for the key
32651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     */
32751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    public Object remove(Object key) {
32851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        processQueue();
32951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        return ValueCell.strip(hash.remove(key), true);
33051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    }
33151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
33251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    /**
33351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * Remove all mappings from this cache.
33451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     */
33551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    public void clear() {
33651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        processQueue();
33751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        hash.clear();
33851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    }
33951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
34051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
34151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    /* -- Views -- */
34251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
34351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    private static boolean valEquals(Object o1, Object o2) {
34451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        return (o1 == null) ? (o2 == null) : o1.equals(o2);
34551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    }
34651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
34751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
34851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    /* Internal class for entries.
34951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski       Because it uses SoftCache.this.queue, this class cannot be static.
35051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     */
35151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    private class Entry implements Map.Entry {
35251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        private Map.Entry ent;
35351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        private Object value;   /* Strong reference to value, to prevent the GC
35451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                                   from flushing the value while this Entry
35551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                                   exists */
35651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
35751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        Entry(Map.Entry ent, Object value) {
35851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            this.ent = ent;
35951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            this.value = value;
36051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        }
36151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
36251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        public Object getKey() {
36351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            return ent.getKey();
36451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        }
36551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
36651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        public Object getValue() {
36751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            return value;
36851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        }
36951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
37051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        public Object setValue(Object value) {
37151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            return ent.setValue(ValueCell.create(ent.getKey(), value, queue));
37251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        }
37351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
37451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        public boolean equals(Object o) {
37551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            if (! (o instanceof Map.Entry)) return false;
37651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            Map.Entry e = (Map.Entry)o;
37751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            return (valEquals(ent.getKey(), e.getKey())
37851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                    && valEquals(value, e.getValue()));
37951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        }
38051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
38151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        public int hashCode() {
38251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            Object k;
38351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            return ((((k = getKey()) == null) ? 0 : k.hashCode())
38451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                    ^ ((value == null) ? 0 : value.hashCode()));
38551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        }
38651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
38751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    }
38851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
38951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
39051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    /* Internal class for entry sets */
39151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    private class EntrySet extends AbstractSet {
39251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        Set hashEntries = hash.entrySet();
39351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
39451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        public Iterator iterator() {
39551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
39651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            return new Iterator() {
39751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                Iterator hashIterator = hashEntries.iterator();
39851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                Entry next = null;
39951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
40051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                public boolean hasNext() {
40151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                    while (hashIterator.hasNext()) {
40251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                        Map.Entry ent = (Map.Entry)hashIterator.next();
40351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                        ValueCell vc = (ValueCell)ent.getValue();
40451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                        Object v = null;
40551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                        if ((vc != null) && ((v = vc.get()) == null)) {
40651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                            /* Value has been flushed by GC */
40751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                            continue;
40851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                        }
40951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                        next = new Entry(ent, v);
41051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                        return true;
41151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                    }
41251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                    return false;
41351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                }
41451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
41551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                public Object next() {
41651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                    if ((next == null) && !hasNext())
41751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                        throw new NoSuchElementException();
41851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                    Entry e = next;
41951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                    next = null;
42051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                    return e;
42151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                }
42251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
42351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                public void remove() {
42451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                    hashIterator.remove();
42551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                }
42651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
42751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            };
42851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        }
42951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
43051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        public boolean isEmpty() {
43151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            return !(iterator().hasNext());
43251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        }
43351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
43451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        public int size() {
43551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            int j = 0;
43651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            for (Iterator i = iterator(); i.hasNext(); i.next()) j++;
43751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            return j;
43851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        }
43951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
44051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        public boolean remove(Object o) {
44151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            processQueue();
44251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            if (o instanceof Entry) return hashEntries.remove(((Entry)o).ent);
44351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            else return false;
44451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        }
44551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
44651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    }
44751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
44851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
44951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    private Set entrySet = null;
45051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
45151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    /**
45251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * Return a <code>Set</code> view of the mappings in this cache.
45351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     */
45451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    public Set entrySet() {
45551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        if (entrySet == null) entrySet = new EntrySet();
45651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        return entrySet;
45751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    }
45851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
45951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski}
460