/* * This file is part of the Haven & Hearth game client. * Copyright (C) 2009 Fredrik Tolf <fredrik@dolda2000.com>, and * Björn Johannessen <johannessen.bjorn@gmail.com> * * Redistribution and/or modification of this file is subject to the * terms of the GNU Lesser General Public License, version 3, as * published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * Other parts of this source tree adhere to other copying * rights. Please see the file `COPYING' in the root directory of the * source tree for details. * * A copy the GNU Lesser General Public License is distributed along * with the source tree of which this file is a part in the file * `doc/LPGL-3'. If it is missing for any reason, please see the Free * Software Foundation's website at <http://www.fsf.org/>, or write * to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, * Boston, MA 02111-1307 USA */ package haven; import java.util.*; public class HashBMap<K, V> extends AbstractMap<K, V> implements BMap<K, V> { private final Map<K, V> fmap; private final Map<V, K> rmap; private final BMap<V, K> rev; private HashBMap(Map<K, V> f, Map<V, K> r, BMap<V, K> rev) { fmap = f; rmap = r; this.rev = rev; } public HashBMap() { fmap = new HashMap<K, V>(); rmap = new HashMap<V, K>(); rev = new HashBMap<V, K>(rmap, fmap, this); } public boolean containsKey(Object k) { return(fmap.containsKey(k)); } private Set<Entry<K, V>> entries = null; public Set<Entry<K, V>> entrySet() { if(entries == null) { entries = new AbstractSet<Entry<K, V>>() { public int size() { return(fmap.size()); } public Iterator<Entry<K, V>> iterator() { return(new Iterator<Entry<K, V>>() { private final Iterator<Entry<K, V>> iter = fmap.entrySet().iterator(); private Entry<K, V> next, last; class IteredEntry<K, V> implements Entry<K, V> { private final K k; private final V v; private IteredEntry(K k, V v) { this.k = k; this.v = v; } public K getKey() {return(k);} public V getValue() {return(v);} public boolean equals(Object o) { return((o instanceof IteredEntry) && (((IteredEntry)o).k == k) && (((IteredEntry)o).v == v)); } public int hashCode() { return(k.hashCode() ^ v.hashCode()); } public V setValue(V nv) {throw(new UnsupportedOperationException());} } public boolean hasNext() { if(next != null) return(true); if(!iter.hasNext()) return(false); Entry<K, V> e = iter.next(); next = new IteredEntry<K, V>(e.getKey(), e.getValue()); return(true); } public Entry<K, V> next() { if(!hasNext()) throw(new NoSuchElementException()); Entry<K, V> ret = last = next; next = null; return(ret); } public void remove() { iter.remove(); if(rmap.remove(last.getValue()) != last.getKey()) throw(new ConcurrentModificationException("reverse-map invariant broken")); } }); } public void clear() { fmap.clear(); rmap.clear(); } }; } return(entries); } public V get(Object k) { return(fmap.get(k)); } public V put(K k, V v) { if((k == null) || (v == null)) throw(new NullPointerException()); V old = fmap.put(k, v); rmap.put(v, k); return(old); } public V remove(Object k) { V old = fmap.remove(k); rmap.remove(old); return(old); } public BMap<V, K> reverse() { return(rev); } }