Annotation of java/classes/org/w3c/util/LookupTable.java, revision 1.5

1.1       bmahe       1: // LookupTable.java
1.5     ! ylafon      2: // $Id: LookupTable.java,v 1.4 2012/06/16 15:48:50 ylafon Exp $
1.1       bmahe       3: // (c) COPYRIGHT MIT, INRIA and Keio, 1999.
                      4: // Please first read the full copyright statement in file COPYRIGHT.html
                      5: package org.w3c.util;
                      6: 
                      7: import java.io.Serializable;
1.5     ! ylafon      8: import java.util.Arrays;
1.1       bmahe       9: import java.util.Enumeration;
                     10: 
                     11: /**
                     12:  * A kind of hashtable (maps keys to values), useful for a limited number
                     13:  * of elements.
1.5     ! ylafon     14:  *
        !            15:  * @author BenoοΏ½t MahοΏ½ (bmahe@w3.org)
        !            16:  * @version $Revision: 1.4 $
1.1       bmahe      17:  */
1.5     ! ylafon     18: public class LookupTable<K, V> implements Cloneable, Serializable {
1.1       bmahe      19:     /**
                     20:      * The default capacity.
                     21:      */
                     22:     public static final int DEFAULT_CAPACITY = 10;
1.5     ! ylafon     23:     private static final long serialVersionUID = 3075731106415136080L;
        !            24:     private V elements[] = null;
        !            25:     private K keys[] = null;
        !            26:     private int count = 0;
        !            27:     private int capacity = 0;
1.1       bmahe      28: 
1.5     ! ylafon     29:     /**
        !            30:      * Constructor.
        !            31:      *
        !            32:      * @param capacity the initial capacity
        !            33:      */
        !            34:     @SuppressWarnings({"unchecked"})
        !            35:     public LookupTable(int capacity) {
        !            36:         this.count = 0;
        !            37:         this.capacity = capacity;
        !            38:         this.elements = (V[]) new Object[capacity];
        !            39:         this.keys = (K[]) new Object[capacity];
        !            40:     }
1.1       bmahe      41: 
1.5     ! ylafon     42:     /**
        !            43:      * Constructor, build a LookupTable with a initial capacity set to
        !            44:      * DEFAULT_CAPACITY.
        !            45:      */
        !            46:     public LookupTable() {
        !            47:         this(DEFAULT_CAPACITY);
        !            48:     }
1.1       bmahe      49: 
                     50:     /**
                     51:      * Returns the number of keys in this lookuptable.
                     52:      *
1.5     ! ylafon     53:      * @return the number of keys in this lookuptable.
1.1       bmahe      54:      */
                     55:     public int size() {
1.5     ! ylafon     56:         return count;
1.1       bmahe      57:     }
                     58: 
                     59:     /**
                     60:      * Tests if this lookuptable maps no keys to values.
1.5     ! ylafon     61:      *
        !            62:      * @return <code>true</code> if this lookuptable maps no keys to values;
        !            63:      *         <code>false</code> otherwise.
1.1       bmahe      64:      */
                     65:     public boolean isEmpty() {
1.5     ! ylafon     66:         return count == 0;
1.1       bmahe      67:     }
                     68: 
                     69:     /**
                     70:      * Returns an enumeration of the keys in this lookuptable.
                     71:      *
1.5     ! ylafon     72:      * @return an enumeration of the keys in this lookuptable.
        !            73:      * @see java.util.Enumeration
        !            74:      * @see #elements()
1.1       bmahe      75:      */
1.5     ! ylafon     76:     public synchronized Enumeration<K> keys() {
        !            77:         return new ArrayEnumeration<K>(keys, count);
1.1       bmahe      78:     }
                     79: 
                     80:     /**
                     81:      * Returns an enumeration of the values in this lookuptable.
                     82:      * Use the Enumeration methods on the returned object to fetch the elements
                     83:      * sequentially.
                     84:      *
1.5     ! ylafon     85:      * @return an enumeration of the values in this lookuptable.
        !            86:      * @see java.util.Enumeration
        !            87:      * @see #keys()
1.1       bmahe      88:      */
1.5     ! ylafon     89:     public synchronized Enumeration<V> elements() {
        !            90:         return new ArrayEnumeration<V>(elements, count);
1.1       bmahe      91:     }
                     92: 
                     93:     /**
                     94:      * Tests if some key maps into the specified value in this lookuptable.
1.5     ! ylafon     95:      *
        !            96:      * @param value a value to search for.
        !            97:      * @return <code>true</code> if and only if some key maps to the
        !            98:      *         <code>value</code> argument in this lookuptable as
        !            99:      *         determined by the <tt>equals</tt> method;
        !           100:      *         <code>false</code> otherwise.
        !           101:      * @throws NullPointerException if the value is <code>null</code>.
        !           102:      * @see #containsKey(Object)
1.1       bmahe     103:      */
1.5     ! ylafon    104:     public synchronized boolean contains(V value) {
        !           105:         return (Arrays.binarySearch(elements, value) >= 0);
1.1       bmahe     106:     }
                    107: 
                    108:     /**
                    109:      * Tests if the specified object is a key in this lookuptable.
1.5     ! ylafon    110:      *
        !           111:      * @param key possible key.
        !           112:      * @return <code>true</code> if and only if the specified object
        !           113:      *         is a key in this lookuptable, as determined by the
        !           114:      *         <tt>equals</tt> method; <code>false</code> otherwise.
        !           115:      * @see #contains(Object)
1.1       bmahe     116:      */
1.5     ! ylafon    117:     public synchronized boolean containsKey(K key) {
        !           118:         return (contains(keys, count, key) != -1);
1.1       bmahe     119:     }
                    120: 
1.5     ! ylafon    121:     private int contains(K array[], int size, K value) {
        !           122:         if (value == null) {
        !           123:             throw new NullPointerException();
        !           124:         }
        !           125:         int res = Arrays.binarySearch(array, value);
        !           126:         if (res >= 0) {
        !           127:             return res;
        !           128:         }
        !           129:         return -1;
1.1       bmahe     130:     }
                    131: 
                    132:     /**
1.5     ! ylafon    133:      * Returns the value to which the specified key is mapped in this
1.1       bmahe     134:      * lookuptable.
1.5     ! ylafon    135:      *
        !           136:      * @param key a key in the lookuptable.
        !           137:      * @return the value to which the key is mapped in this lookuptable;
        !           138:      *         <code>null</code> if the key is not mapped to any value in
        !           139:      *         this lookuptable.
        !           140:      * @see #put(Object, Object)
        !           141:      */
        !           142:     public synchronized V get(K key) {
        !           143:         int idx = contains(keys, count, key);
        !           144:         if (idx != -1) {
        !           145:             return elements[idx];
        !           146:         }
        !           147:         return null;
1.1       bmahe     148:     }
                    149: 
                    150:     /**
1.5     ! ylafon    151:      * Maps the specified <code>key</code> to the specified
        !           152:      * <code>value</code> in this lookuptable. Neither the key nor the
1.1       bmahe     153:      * value can be <code>null</code>. <p>
1.5     ! ylafon    154:      * <p/>
        !           155:      * The value can be retrieved by calling the <code>get</code> method
        !           156:      * with a key that is equal to the original key.
1.1       bmahe     157:      *
1.5     ! ylafon    158:      * @param key   the lookuptable key.
        !           159:      * @param value the value.
        !           160:      * @return the previous value of the specified key in this lookuptable,
        !           161:      *         or <code>null</code> if it did not have one.
        !           162:      * @throws NullPointerException if the key or value is
        !           163:      *                              <code>null</code>.
        !           164:      * @see Object#equals(Object)
        !           165:      * @see #get(Object)
        !           166:      */
        !           167:     public synchronized V put(K key, V value) {
        !           168:         if (value == null) {
        !           169:             throw new NullPointerException();
        !           170:         }
        !           171:         int idx = contains(keys, count, key);
        !           172:         if (idx == -1) {
        !           173:             if (count >= capacity) {
        !           174:                 grow();
        !           175:             }
        !           176:             keys[count] = key;
        !           177:             elements[count] = value;
        !           178:             count++;
        !           179:             return null;
        !           180:         } else {
        !           181:             V previousValue = elements[idx];
        !           182:             elements[idx] = value;
        !           183:             return previousValue;
        !           184:         }
1.1       bmahe     185:     }
                    186: 
                    187:     /**
1.5     ! ylafon    188:      * Increases the capacity. This method is called automatically when the
1.1       bmahe     189:      * number of keys in the lookuptable exceeds this lookuptable's capacity.
1.5     ! ylafon    190:      */
        !           191:     @SuppressWarnings({"unchecked"})
1.1       bmahe     192:     protected void grow() {
1.5     ! ylafon    193:         int newCapacity = capacity * 2 + 1;
        !           194:         V newElements[] = (V[]) new Object[newCapacity];
        !           195:         K newKeys[] = (K[]) new Object[newCapacity];
        !           196:         System.arraycopy(elements, 0, newElements, 0, count);
        !           197:         System.arraycopy(keys, 0, newKeys, 0, count);
        !           198:         this.keys = newKeys;
        !           199:         this.elements = newElements;
        !           200:         this.capacity = newCapacity;
1.1       bmahe     201:     }
                    202: 
                    203:     /**
1.5     ! ylafon    204:      * Removes the key (and its corresponding value) from this
        !           205:      * lookuptable. This method does nothing if the key is not in the
1.1       bmahe     206:      * lookuptable.
                    207:      *
1.5     ! ylafon    208:      * @param key the key that needs to be removed.
        !           209:      * @return the value to which the key had been mapped in this lookuptable,
        !           210:      *         or <code>null</code> if the key did not have a mapping.
        !           211:      */
        !           212:     public synchronized V remove(K key) {
        !           213:         int idx = contains(keys, count, key);
        !           214:         if (idx != -1) {
        !           215:             //remove this one by moving the last one here.
        !           216:             V oldvalue = elements[idx];
        !           217:             count--;
        !           218:             keys[idx] = keys[count];
        !           219:             elements[idx] = elements[count];
        !           220:             keys[count] = null;
        !           221:             elements[count] = null;
        !           222:             return oldvalue;
        !           223:         }
        !           224:         return null;
1.1       bmahe     225:     }
                    226: 
                    227:     /**
1.5     ! ylafon    228:      * Clears this lookuptable so that it contains no keys.
1.1       bmahe     229:      */
1.5     ! ylafon    230:     @SuppressWarnings({"unchecked"})
1.1       bmahe     231:     public synchronized void clear() {
1.5     ! ylafon    232:         this.count = 0;
        !           233:         this.keys = (K[]) new Object[capacity];
        !           234:         this.elements = (V[]) new Object[capacity];
1.1       bmahe     235:     }
                    236: 
                    237:     /**
1.5     ! ylafon    238:      * Creates a shallow copy of this lookuptable. All the structure of the
        !           239:      * lookuptable itself is copied, but the keys and values are not cloned.
1.1       bmahe     240:      * This is a relatively expensive operation.
                    241:      *
1.5     ! ylafon    242:      * @return a clone of the lookuptable.
1.1       bmahe     243:      */
1.5     ! ylafon    244:     @SuppressWarnings({"unchecked"})
        !           245:     public synchronized Object clone()
        !           246:             throws CloneNotSupportedException {
        !           247:         try {
        !           248:             LookupTable<K,V> l = (LookupTable<K,V>) super.clone();
        !           249:             l.keys = (K[]) new Object[capacity];
        !           250:             l.elements = (V[]) new Object[capacity];
        !           251:             System.arraycopy(keys, 0, l.keys, 0, count);
        !           252:             System.arraycopy(elements, 0, l.elements, 0, count);
        !           253:             l.capacity = capacity;
        !           254:             l.count = count;
        !           255:             return l;
        !           256:         } catch (CloneNotSupportedException e) {
        !           257:             // this shouldn't happen, since we are Cloneable
        !           258:             throw new InternalError();
        !           259:         }
1.1       bmahe     260:     }
                    261: 
                    262:     /**
1.5     ! ylafon    263:      * Returns a string representation of this <tt>Lookuptable</tt> object
        !           264:      * in the form of a set of entries, enclosed in braces and separated
        !           265:      * by the ASCII characters "<tt>,&nbsp;</tt>" (comma and space). Each
        !           266:      * entry is rendered as the key, an equals sign <tt>=</tt>, and the
        !           267:      * associated element, where the <tt>toString</tt> method is used to
        !           268:      * convert the key and element to strings. <p>Overrides to
1.1       bmahe     269:      * <tt>toString</tt> method of <tt>Object</tt>.
                    270:      *
1.5     ! ylafon    271:      * @return a string representation of this lookuptable.
1.1       bmahe     272:      */
                    273:     public synchronized String toString() {
1.5     ! ylafon    274:         StringBuilder buffer = new StringBuilder();
        !           275:         for (int i = 0; i < count; i++) {
        !           276:             buffer.append('[').append(keys[i]).append(',').append(elements[i]).append(']');
        !           277:         }
        !           278:         return buffer.toString();
1.1       bmahe     279:     }
                    280: 
                    281: }

Webmaster