package freenet.support; import java.util.Enumeration; import java.util.Hashtable; import java.util.Vector; /** * A hashtable that can store several values for each entry. * * @author oskar */ public class MultiValueTable { private Hashtable> table; private int ies; public MultiValueTable() { this(16, 3); } public MultiValueTable(int initialSize) { this(initialSize, 3); } public MultiValueTable(int initialSize, int initialEntrySize) { table = new Hashtable>(initialSize); ies = initialEntrySize; } public void put(K key, V value) { synchronized (table) { Vector v = table.get(key); if (v == null) { v = new Vector(ies); table.put(key, v); } v.addElement(value); } } /** * Returns the first element for this key. */ public V get(K key) { synchronized (table) { Vector v = table.get(key); return (v == null ? null : v.firstElement()); } } public boolean containsKey(K key) { synchronized (table) { return table.containsKey(key); } } public boolean containsElement(K key, V value) { synchronized (table) { Vector v = table.get(key); return (v != null) && v.contains(value); } } /** * Users will have to handle synchronizing. */ public Enumeration getAll(K key) { Vector v; synchronized (table) { v = table.get(key); } return (v == null ? new LimitedEnumeration(null) : v.elements()); } /** * To be used in for(x : y). */ public Iterable iterateAll(K key) { synchronized (table) { return(table.get(key)); } } public int countAll(K key) { Vector v; synchronized (table) { v = table.get(key); } if(v != null) return v.size(); else return 0; } public Object getSync(K key) { synchronized (table) { return table.get(key); } } public Object[] getArray(K key) { synchronized (table) { Vector v = table.get(key); if (v == null) return null; else { Object[] r = new Object[v.size()]; v.copyInto(r); return r; } } } public void remove(K key) { synchronized (table) { table.remove(key); } } public boolean isEmpty() { synchronized (table) { return table.isEmpty(); } } public void clear() { synchronized (table) { table.clear(); } } public boolean removeElement(K key, V value) { synchronized (table) { Vector v = table.get(key); if (v == null) return false; else { boolean b = v.removeElement(value); if (v.isEmpty()) table.remove(key); return b; } } } public Enumeration keys() { synchronized (table) { return table.keys(); } } public Enumeration elements() { synchronized (table) { if (table.isEmpty()) return new LimitedEnumeration(null); else return new MultiValueEnumeration(); } } private class MultiValueEnumeration implements Enumeration { private Enumeration current; private Enumeration< Vector> global; public MultiValueEnumeration() { synchronized (table) { global = table.elements(); } current = global.nextElement().elements(); step(); } public final void step() { while (!current.hasMoreElements() && global.hasMoreElements()) current = global.nextElement().elements(); } public final boolean hasMoreElements() { return global.hasMoreElements(); // || current.hasMoreElements(); } public final V nextElement() { V o = current.nextElement(); step(); return o; } } }