home *** CD-ROM | disk | FTP | other *** search
/ CD Actual 25 / CDROM25.iso / Share / prog / VJ11 / VJTRIAL.EXE / IE30Java.exe / classd.exe / sun / misc / Cache.java < prev    next >
Encoding:
Java Source  |  1997-01-27  |  9.6 KB  |  342 lines

  1. /*
  2.  * @(#)Cache.java    1.11 95/09/06
  3.  * 
  4.  * Copyright (c) 1994 Sun Microsystems, Inc. All Rights Reserved.
  5.  * 
  6.  * Permission to use, copy, modify, and distribute this software and its
  7.  * documentation for NON-COMMERCIAL purposes and without fee is hereby
  8.  * granted provided that this copyright notice appears in all copies. Please
  9.  * refer to the file "copyright.html" for further important copyright and
  10.  * licensing information.
  11.  * 
  12.  * SUN MAKES NO REPRESENTATIONS OR WARRANTIES ABOUT THE SUITABILITY OF THE
  13.  * SOFTWARE, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
  14.  * IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE,
  15.  * OR NON-INFRINGEMENT. SUN SHALL NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY
  16.  * LICENSEE AS A RESULT OF USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR
  17.  * ITS DERIVATIVES.
  18.  */
  19.  
  20. package sun.misc;
  21.  
  22. import java.util.Dictionary;
  23. import java.util.Enumeration;
  24. import java.util.NoSuchElementException;
  25.  
  26. /**
  27.  * Caches the collision list.
  28.  */
  29. class CacheEntry extends Ref {
  30.     int hash;
  31.     Object key;
  32.     CacheEntry next;
  33.     public Object reconstitute() {
  34.     return null;
  35.     }
  36. }
  37.  
  38. /**
  39.  * The Cache class. Maps keys to values. Any object can be used as
  40.  * a key and/or value.  This is very similar to the Hashtable
  41.  * class, except that after putting an object into the Cache,
  42.  * it is not guaranteed that a subsequent get will return it.
  43.  * The Cache will automatically remove entries if memory is
  44.  * getting tight and if the entry is not referenced from outside
  45.  * the Cache.<p>
  46.  *
  47.  * To sucessfully store and retrieve objects from a hash table the
  48.  * object used as the key must implement the hashCode() and equals()
  49.  * methods.<p>
  50.  *
  51.  * This example creates a Cache of numbers. It uses the names of
  52.  * the numbers as keys:
  53.  * <pre>
  54.  *    Cache numbers = new Cache();
  55.  *    numbers.put("one", new Integer(1));
  56.  *    numbers.put("two", new Integer(1));
  57.  *    numbers.put("three", new Integer(1));
  58.  * </pre>
  59.  * To retrieve a number use:
  60.  * <pre>
  61.  *    Integer n = (Integer)numbers.get("two");
  62.  *    if (n != null) {
  63.  *        System.out.println("two = " + n);
  64.  *    }
  65.  * </pre>
  66.  *
  67.  * @see java.lang.Object#hashCode
  68.  * @see java.lang.Object#equals
  69.  * @see sun.misc.Ref
  70.  * @version     1.11, 09/06/95
  71.  */
  72. public
  73. class Cache extends Dictionary {
  74.     /**
  75.      * The hash table data.
  76.      */
  77.     private CacheEntry table[];
  78.  
  79.     /**
  80.      * The total number of entries in the hash table.
  81.      */
  82.     private int count;
  83.  
  84.     /**
  85.      * Rehashes the table when count exceeds this threshold.
  86.      */
  87.     private int threshold;
  88.  
  89.     /**
  90.      * The load factor for the hashtable.
  91.      */
  92.     private float loadFactor;
  93.  
  94.     private void init(int initialCapacity, float loadFactor) {
  95.     if ((initialCapacity <= 0) || (loadFactor <= 0.0)) {
  96.         throw new IllegalArgumentException();
  97.     }
  98.     this.loadFactor = loadFactor;
  99.     table = new CacheEntry[initialCapacity];
  100.     threshold = (int) (initialCapacity * loadFactor);
  101.     }
  102.  
  103.     /**
  104.      * Constructs a new, empty Cache with the specified initial 
  105.      * capacity and the specified load factor.
  106.      * @param initialCapacity the initial number of buckets
  107.      * @param loadFactor a number between 0.0 and 1.0, it defines
  108.      *        the threshold for rehashing the Cache into
  109.      *        a bigger one.
  110.      * @exception IllegalArgumentException If the initial capacity
  111.      * is less than or equal to zero.
  112.      * @exception IllegalArgumentException If the load factor is
  113.      * less than or equal to zero.
  114.      */
  115.     public Cache (int initialCapacity, float loadFactor) {
  116.     init(initialCapacity, loadFactor);
  117.     }
  118.  
  119.     /**
  120.      * Constructs a new, empty Cache with the specified initial 
  121.      * capacity.
  122.      * @param initialCapacity the initial number of buckets
  123.      */
  124.     public Cache (int initialCapacity) {
  125.     init(initialCapacity, 0.75f);
  126.     }
  127.  
  128.     /**
  129.      * Constructs a new, empty Cache. A default capacity and load factor
  130.      * is used. Note that the Cache will automatically grow when it gets
  131.      * full.
  132.      */
  133.     public Cache () {
  134.     try {
  135.           init(101, 0.75f);
  136.     } catch (IllegalArgumentException ex) {
  137.         // This should never happen
  138.         throw new Error("panic");
  139.       }
  140.     }
  141.  
  142.     /**
  143.      * Returns the number of elements contained within the Cache. 
  144.      */
  145.     public int size() {
  146.     return count;
  147.     }
  148.  
  149.     /**
  150.      * Returns true if the Cache contains no elements.
  151.      */
  152.     public boolean isEmpty() {
  153.     return count == 0;
  154.     }
  155.  
  156.     /**
  157.      * Returns an enumeration of the Cache's keys.
  158.      * @see Cache#elements
  159.      * @see Enumeration
  160.      */
  161.     public synchronized Enumeration keys() {
  162.     return new CacheEnumerator(table, true);
  163.     }
  164.  
  165.     /**
  166.      * Returns an enumeration of the elements. Use the Enumeration methods 
  167.      * on the returned object to fetch the elements sequentially.
  168.      * @see Cache#keys
  169.      * @see Enumeration
  170.      */
  171.     public synchronized Enumeration elements() {
  172.     return new CacheEnumerator(table, false);
  173.     }
  174.  
  175.     /**
  176.      * Gets the object associated with the specified key in the Cache.
  177.      * @param key the key in the hash table
  178.      * @returns the element for the key or null if the key
  179.      *         is not defined in the hash table.
  180.      * @see Cache#put
  181.      */
  182.     public synchronized Object get(Object key) {
  183.     CacheEntry tab[] = table;
  184.     int hash = key.hashCode();
  185.     int index = (hash & 0x7FFFFFFF) % tab.length;
  186.     for (CacheEntry e = tab[index]; e != null; e = e.next) {
  187.         if ((e.hash == hash) && e.key.equals(key)) {
  188.         return e.check();
  189.         }
  190.     }
  191.     return null;
  192.     }
  193.  
  194.     /**
  195.      * Rehashes the contents of the table into a bigger table.
  196.      * This is method is called automatically when the Cache's
  197.      * size exceeds the threshold.
  198.      */
  199.     protected void rehash() {
  200.     int oldCapacity = table.length;
  201.     CacheEntry oldTable[] = table;
  202.  
  203.     int newCapacity = oldCapacity * 2 + 1;
  204.     CacheEntry newTable[] = new CacheEntry[newCapacity];
  205.  
  206.     threshold = (int) (newCapacity * loadFactor);
  207.     table = newTable;
  208.  
  209.     // System.out.println("rehash old=" + oldCapacity + ", new=" +
  210.     // newCapacity + ", thresh=" + threshold + ", count=" + count);
  211.  
  212.     for (int i = oldCapacity; i-- > 0;) {
  213.         for (CacheEntry old = oldTable[i]; old != null;) {
  214.         CacheEntry e = old;
  215.         old = old.next;
  216.         if (e.check() != null) {
  217.             int index = (e.hash & 0x7FFFFFFF) % newCapacity;
  218.             e.next = newTable[index];
  219.             newTable[index] = e;
  220.         } else
  221.             count--;    /* remove entries that have disappeared */
  222.         }
  223.     }
  224.     }
  225.  
  226.     /**
  227.      * Puts the specified element into the Cache, using the specified
  228.      * key.  The element may be retrieved by doing a get() with the same 
  229.      * key.  The key and the element cannot be null.
  230.      * @param key the specified hashtable key
  231.      * @param value the specified element 
  232.      * @return the old value of the key, or null if it did not have one.
  233.      * @exception NullPointerException If the value of the specified
  234.      * element is null.
  235.      * @see Cache#get
  236.      */
  237.     public synchronized Object put(Object key, Object value) {
  238.     // Make sure the value is not null
  239.     if (value == null) {
  240.         throw new NullPointerException();
  241.     }
  242.     // Makes sure the key is not already in the cache.
  243.     CacheEntry tab[] = table;
  244.     int hash = key.hashCode();
  245.     int index = (hash & 0x7FFFFFFF) % tab.length;
  246.     CacheEntry ne = null;
  247.     for (CacheEntry e = tab[index]; e != null; e = e.next) {
  248.         if ((e.hash == hash) && e.key.equals(key)) {
  249.         Object old = e.check();
  250.         e.setThing(value);
  251.         return old;
  252.         } else if (e.check() == null)
  253.         ne = e;        /* reuse old flushed value */
  254.     }
  255.  
  256.     if (count >= threshold) {
  257.         // Rehash the table if the threshold is exceeded
  258.         rehash();
  259.         return put(key, value);
  260.     }
  261.     // Creates the new entry.
  262.     if (ne == null) {
  263.         ne = new CacheEntry ();
  264.         ne.next = tab[index];
  265.         tab[index] = ne;
  266.         count++;
  267.     }
  268.     ne.hash = hash;
  269.     ne.key = key;
  270.     ne.setThing(value);
  271.     return null;
  272.     }
  273.  
  274.     /**
  275.      * Removes the element corresponding to the key. Does nothing if the
  276.      * key is not present.
  277.      * @param key the key that needs to be removed
  278.      * @return the value of key, or null if the key was not found.
  279.      */
  280.     public synchronized Object remove(Object key) {
  281.     CacheEntry tab[] = table;
  282.     int hash = key.hashCode();
  283.     int index = (hash & 0x7FFFFFFF) % tab.length;
  284.     for (CacheEntry e = tab[index], prev = null; e != null; prev = e, e = e.next) {
  285.         if ((e.hash == hash) && e.key.equals(key)) {
  286.         if (prev != null) {
  287.             prev.next = e.next;
  288.         } else {
  289.             tab[index] = e.next;
  290.         }
  291.         count--;
  292.         return e.check();
  293.         }
  294.     }
  295.     return null;
  296.     }
  297. }
  298.  
  299. /**
  300.  * A Cache enumerator class.  This class should remain opaque
  301.  * to the client. It will use the Enumeration interface.
  302.  */
  303. class CacheEnumerator implements Enumeration {
  304.     boolean keys;
  305.     int index;
  306.     CacheEntry table[];
  307.     CacheEntry entry;
  308.  
  309.     CacheEnumerator (CacheEntry table[], boolean keys) {
  310.     this.table = table;
  311.     this.keys = keys;
  312.     this.index = table.length;
  313.     }
  314.  
  315.     public boolean hasMoreElements() {
  316.     while (index >= 0) {
  317.         while (entry != null)
  318.         if (entry.check() != null)
  319.             return true;
  320.         else
  321.             entry = entry.next;
  322.         while (--index >= 0 && (entry = table[index]) != null) ;
  323.     }
  324.     return false;
  325.     }
  326.  
  327.     public Object nextElement() {
  328.     while (index >= 0) {
  329.         if (entry == null)
  330.         while (--index >= 0 && (entry = table[index]) == null) ;
  331.         if (entry != null) {
  332.         CacheEntry e = entry;
  333.         entry = e.next;
  334.         if (e.check() != null)
  335.             return keys ? e.key : e.check();
  336.         }
  337.     }
  338.     throw new NoSuchElementException("CacheEnumerator");
  339.     }
  340.  
  341. }
  342.