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>, </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