Merging from -r468106:814127 of collections_jdk5_branch - namely where this code was generified; mostly in r738956.
Also see the following revisions: ------------------------------------------------------------------------ r751871 | mbenson | 2009-03-09 15:13:34 -0700 (Mon, 09 Mar 2009) | 1 line Add OrderedMap to our SortedMap implementations ------------------------------------------------------------------------ git-svn-id: https://svn.apache.org/repos/asf/commons/proper/collections/trunk@815025 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
parent
87bd27bed1
commit
fd10e94049
|
@ -55,90 +55,103 @@ import org.apache.commons.collections.map.AbstractSortedMapDecorator;
|
|||
* @author Matthew Hawthorne
|
||||
* @author Stephen Colebourne
|
||||
*/
|
||||
public class DualTreeBidiMap
|
||||
extends AbstractDualBidiMap implements SortedBidiMap, Serializable {
|
||||
public class DualTreeBidiMap<K, V> extends AbstractDualBidiMap<K, V> implements
|
||||
SortedBidiMap<K, V>, Serializable {
|
||||
|
||||
/** Ensure serialization compatibility */
|
||||
private static final long serialVersionUID = 721969328361809L;
|
||||
/** The comparator to use */
|
||||
protected final Comparator comparator;
|
||||
|
||||
/** The key comparator to use */
|
||||
protected final Comparator<? super K> comparator;
|
||||
|
||||
/** The value comparator to use */
|
||||
protected final Comparator<? super V> valueComparator;
|
||||
|
||||
/**
|
||||
* Creates an empty <code>DualTreeBidiMap</code>
|
||||
*/
|
||||
public DualTreeBidiMap() {
|
||||
super(new TreeMap(), new TreeMap());
|
||||
super(new TreeMap<K, V>(), new TreeMap<V, K>());
|
||||
this.comparator = null;
|
||||
this.valueComparator = null;
|
||||
}
|
||||
|
||||
/**
|
||||
/**
|
||||
* Constructs a <code>DualTreeBidiMap</code> and copies the mappings from
|
||||
* specified <code>Map</code>.
|
||||
* specified <code>Map</code>.
|
||||
*
|
||||
* @param map the map whose mappings are to be placed in this map
|
||||
*/
|
||||
public DualTreeBidiMap(Map map) {
|
||||
super(new TreeMap(), new TreeMap());
|
||||
public DualTreeBidiMap(Map<K, V> map) {
|
||||
super(new TreeMap<K, V>(), new TreeMap<V, K>());
|
||||
putAll(map);
|
||||
this.comparator = null;
|
||||
this.valueComparator = null;
|
||||
}
|
||||
|
||||
/**
|
||||
/**
|
||||
* Constructs a <code>DualTreeBidiMap</code> using the specified Comparator.
|
||||
*
|
||||
* @param comparator the Comparator
|
||||
* @param keyComparator the Comparator
|
||||
*/
|
||||
public DualTreeBidiMap(Comparator comparator) {
|
||||
super(new TreeMap(comparator), new TreeMap(comparator));
|
||||
this.comparator = comparator;
|
||||
public DualTreeBidiMap(Comparator<? super K> keyComparator, Comparator<? super V> valueComparator) {
|
||||
super(new TreeMap<K, V>(keyComparator), new TreeMap<V, K>(valueComparator));
|
||||
this.comparator = keyComparator;
|
||||
this.valueComparator = valueComparator;
|
||||
}
|
||||
|
||||
/**
|
||||
/**
|
||||
* Constructs a <code>DualTreeBidiMap</code> that decorates the specified maps.
|
||||
*
|
||||
* @param normalMap the normal direction map
|
||||
* @param reverseMap the reverse direction map
|
||||
* @param inverseBidiMap the inverse BidiMap
|
||||
*/
|
||||
protected DualTreeBidiMap(Map normalMap, Map reverseMap, BidiMap inverseBidiMap) {
|
||||
protected DualTreeBidiMap(Map<K, V> normalMap, Map<V, K> reverseMap, BidiMap<V, K> inverseBidiMap) {
|
||||
super(normalMap, reverseMap, inverseBidiMap);
|
||||
this.comparator = ((SortedMap) normalMap).comparator();
|
||||
this.comparator = ((SortedMap<K, V>) normalMap).comparator();
|
||||
this.valueComparator = ((SortedMap<V, K>) reverseMap).comparator();
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new instance of this object.
|
||||
*
|
||||
*
|
||||
* @param normalMap the normal direction map
|
||||
* @param reverseMap the reverse direction map
|
||||
* @param inverseMap the inverse BidiMap
|
||||
* @return new bidi map
|
||||
*/
|
||||
protected BidiMap createBidiMap(Map normalMap, Map reverseMap, BidiMap inverseMap) {
|
||||
return new DualTreeBidiMap(normalMap, reverseMap, inverseMap);
|
||||
protected DualTreeBidiMap<V, K> createBidiMap(Map<V, K> normalMap, Map<K, V> reverseMap, BidiMap<K, V> inverseMap) {
|
||||
return new DualTreeBidiMap<V, K>(normalMap, reverseMap, inverseMap);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
public Comparator comparator() {
|
||||
return ((SortedMap) maps[0]).comparator();
|
||||
public Comparator<? super K> comparator() {
|
||||
return ((SortedMap<K, V>) normalMap).comparator();
|
||||
}
|
||||
|
||||
public Object firstKey() {
|
||||
return ((SortedMap) maps[0]).firstKey();
|
||||
public Comparator<? super V> valueComparator() {
|
||||
return ((SortedMap<V, K>) reverseMap).comparator();
|
||||
|
||||
}
|
||||
|
||||
public Object lastKey() {
|
||||
return ((SortedMap) maps[0]).lastKey();
|
||||
public K firstKey() {
|
||||
return ((SortedMap<K, V>) normalMap).firstKey();
|
||||
}
|
||||
|
||||
public Object nextKey(Object key) {
|
||||
public K lastKey() {
|
||||
return ((SortedMap<K, V>) normalMap).lastKey();
|
||||
}
|
||||
|
||||
public K nextKey(K key) {
|
||||
if (isEmpty()) {
|
||||
return null;
|
||||
}
|
||||
if (maps[0] instanceof OrderedMap) {
|
||||
return ((OrderedMap) maps[0]).nextKey(key);
|
||||
if (normalMap instanceof OrderedMap) {
|
||||
return ((OrderedMap<K, ?>) normalMap).nextKey(key);
|
||||
}
|
||||
SortedMap sm = (SortedMap) maps[0];
|
||||
Iterator it = sm.tailMap(key).keySet().iterator();
|
||||
SortedMap<K, V> sm = (SortedMap<K, V>) normalMap;
|
||||
Iterator<K> it = sm.tailMap(key).keySet().iterator();
|
||||
it.next();
|
||||
if (it.hasNext()) {
|
||||
return it.next();
|
||||
|
@ -146,15 +159,15 @@ public class DualTreeBidiMap
|
|||
return null;
|
||||
}
|
||||
|
||||
public Object previousKey(Object key) {
|
||||
public K previousKey(K key) {
|
||||
if (isEmpty()) {
|
||||
return null;
|
||||
}
|
||||
if (maps[0] instanceof OrderedMap) {
|
||||
return ((OrderedMap) maps[0]).previousKey(key);
|
||||
if (normalMap instanceof OrderedMap) {
|
||||
return ((OrderedMap<K, V>) normalMap).previousKey(key);
|
||||
}
|
||||
SortedMap sm = (SortedMap) maps[0];
|
||||
SortedMap hm = sm.headMap(key);
|
||||
SortedMap<K, V> sm = (SortedMap<K, V>) normalMap;
|
||||
SortedMap<K, V> hm = sm.headMap(key);
|
||||
if (hm.isEmpty()) {
|
||||
return null;
|
||||
}
|
||||
|
@ -167,181 +180,204 @@ public class DualTreeBidiMap
|
|||
* <p>
|
||||
* This implementation copies the elements to an ArrayList in order to
|
||||
* provide the forward/backward behaviour.
|
||||
*
|
||||
*
|
||||
* @return a new ordered map iterator
|
||||
*/
|
||||
public OrderedMapIterator orderedMapIterator() {
|
||||
return new BidiOrderedMapIterator(this);
|
||||
public OrderedMapIterator<K, V> mapIterator() {
|
||||
return new BidiOrderedMapIterator<K, V>(this);
|
||||
}
|
||||
|
||||
public SortedBidiMap inverseSortedBidiMap() {
|
||||
return (SortedBidiMap) inverseBidiMap();
|
||||
public SortedBidiMap<V, K> inverseSortedBidiMap() {
|
||||
return (SortedBidiMap<V, K>) inverseBidiMap();
|
||||
}
|
||||
|
||||
public OrderedBidiMap inverseOrderedBidiMap() {
|
||||
return (OrderedBidiMap) inverseBidiMap();
|
||||
public OrderedBidiMap<V, K> inverseOrderedBidiMap() {
|
||||
return (OrderedBidiMap<V, K>) inverseBidiMap();
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
public SortedMap headMap(Object toKey) {
|
||||
SortedMap sub = ((SortedMap) maps[0]).headMap(toKey);
|
||||
return new ViewMap(this, sub);
|
||||
public SortedMap<K, V> headMap(K toKey) {
|
||||
SortedMap<K, V> sub = ((SortedMap<K, V>) normalMap).headMap(toKey);
|
||||
return new ViewMap<K, V>(this, sub);
|
||||
}
|
||||
|
||||
public SortedMap tailMap(Object fromKey) {
|
||||
SortedMap sub = ((SortedMap) maps[0]).tailMap(fromKey);
|
||||
return new ViewMap(this, sub);
|
||||
public SortedMap<K, V> tailMap(K fromKey) {
|
||||
SortedMap<K, V> sub = ((SortedMap<K, V>) normalMap).tailMap(fromKey);
|
||||
return new ViewMap<K, V>(this, sub);
|
||||
}
|
||||
|
||||
public SortedMap subMap(Object fromKey, Object toKey) {
|
||||
SortedMap sub = ((SortedMap) maps[0]).subMap(fromKey, toKey);
|
||||
return new ViewMap(this, sub);
|
||||
public SortedMap<K, V> subMap(K fromKey, K toKey) {
|
||||
SortedMap<K, V> sub = ((SortedMap<K, V>) normalMap).subMap(fromKey, toKey);
|
||||
return new ViewMap<K, V>(this, sub);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
public SortedBidiMap<V, K> inverseBidiMap() {
|
||||
return (SortedBidiMap<V, K>) super.inverseBidiMap();
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
/**
|
||||
* Internal sorted map view.
|
||||
*/
|
||||
protected static class ViewMap extends AbstractSortedMapDecorator {
|
||||
protected static class ViewMap<K, V> extends AbstractSortedMapDecorator<K, V> {
|
||||
/** The parent bidi map. */
|
||||
final DualTreeBidiMap bidi;
|
||||
|
||||
final DualTreeBidiMap<K, V> bidi;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
* @param bidi the parent bidi map
|
||||
* @param sm the subMap sorted map
|
||||
*/
|
||||
protected ViewMap(DualTreeBidiMap bidi, SortedMap sm) {
|
||||
protected ViewMap(DualTreeBidiMap<K, V> bidi, SortedMap<K, V> sm) {
|
||||
// the implementation is not great here...
|
||||
// use the maps[0] as the filtered map, but maps[1] as the full map
|
||||
// use the normalMap as the filtered map, but reverseMap as the full map
|
||||
// this forces containsValue and clear to be overridden
|
||||
super((SortedMap) bidi.createBidiMap(sm, bidi.maps[1], bidi.inverseBidiMap));
|
||||
this.bidi = (DualTreeBidiMap) map;
|
||||
super(new DualTreeBidiMap<K, V>(sm, bidi.reverseMap, bidi.inverseBidiMap));
|
||||
this.bidi = (DualTreeBidiMap<K, V>) decorated();
|
||||
}
|
||||
|
||||
|
||||
public boolean containsValue(Object value) {
|
||||
// override as default implementation jumps to [1]
|
||||
return bidi.maps[0].containsValue(value);
|
||||
// override as default implementation uses reverseMap
|
||||
return decorated().normalMap.containsValue(value);
|
||||
}
|
||||
|
||||
|
||||
public void clear() {
|
||||
// override as default implementation jumps to [1]
|
||||
for (Iterator it = keySet().iterator(); it.hasNext();) {
|
||||
// override as default implementation uses reverseMap
|
||||
for (Iterator<K> it = keySet().iterator(); it.hasNext();) {
|
||||
it.next();
|
||||
it.remove();
|
||||
}
|
||||
}
|
||||
|
||||
public SortedMap headMap(Object toKey) {
|
||||
return new ViewMap(bidi, super.headMap(toKey));
|
||||
|
||||
public SortedMap<K, V> headMap(K toKey) {
|
||||
return new ViewMap<K, V>(decorated(), super.headMap(toKey));
|
||||
}
|
||||
|
||||
public SortedMap tailMap(Object fromKey) {
|
||||
return new ViewMap(bidi, super.tailMap(fromKey));
|
||||
public SortedMap<K, V> tailMap(K fromKey) {
|
||||
return new ViewMap<K, V>(decorated(), super.tailMap(fromKey));
|
||||
}
|
||||
|
||||
public SortedMap subMap(Object fromKey, Object toKey) {
|
||||
return new ViewMap(bidi, super.subMap(fromKey, toKey));
|
||||
public SortedMap<K, V> subMap(K fromKey, K toKey) {
|
||||
return new ViewMap<K, V>(decorated(), super.subMap(fromKey, toKey));
|
||||
}
|
||||
|
||||
@Override
|
||||
protected DualTreeBidiMap<K, V> decorated() {
|
||||
return (DualTreeBidiMap<K, V>) super.decorated();
|
||||
}
|
||||
|
||||
public K previousKey(K key) {
|
||||
return decorated().previousKey(key);
|
||||
};
|
||||
|
||||
public K nextKey(K key) {
|
||||
return decorated().nextKey(key);
|
||||
};
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
/**
|
||||
* Inner class MapIterator.
|
||||
*/
|
||||
protected static class BidiOrderedMapIterator implements OrderedMapIterator, ResettableIterator {
|
||||
|
||||
protected static class BidiOrderedMapIterator<K, V> implements OrderedMapIterator<K, V>, ResettableIterator<K> {
|
||||
|
||||
/** The parent map */
|
||||
protected final AbstractDualBidiMap parent;
|
||||
protected final AbstractDualBidiMap<K, V> parent;
|
||||
|
||||
/** The iterator being decorated */
|
||||
protected ListIterator iterator;
|
||||
protected ListIterator<Map.Entry<K, V>> iterator;
|
||||
|
||||
/** The last returned entry */
|
||||
private Map.Entry last = null;
|
||||
|
||||
private Map.Entry<K, V> last = null;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
* @param parent the parent map
|
||||
*/
|
||||
protected BidiOrderedMapIterator(AbstractDualBidiMap parent) {
|
||||
protected BidiOrderedMapIterator(AbstractDualBidiMap<K, V> parent) {
|
||||
super();
|
||||
this.parent = parent;
|
||||
iterator = new ArrayList(parent.entrySet()).listIterator();
|
||||
iterator = new ArrayList<Map.Entry<K, V>>(parent.entrySet()).listIterator();
|
||||
}
|
||||
|
||||
|
||||
public boolean hasNext() {
|
||||
return iterator.hasNext();
|
||||
}
|
||||
|
||||
public Object next() {
|
||||
last = (Map.Entry) iterator.next();
|
||||
|
||||
public K next() {
|
||||
last = iterator.next();
|
||||
return last.getKey();
|
||||
}
|
||||
|
||||
|
||||
public boolean hasPrevious() {
|
||||
return iterator.hasPrevious();
|
||||
}
|
||||
|
||||
public Object previous() {
|
||||
last = (Map.Entry) iterator.previous();
|
||||
|
||||
public K previous() {
|
||||
last = iterator.previous();
|
||||
return last.getKey();
|
||||
}
|
||||
|
||||
|
||||
public void remove() {
|
||||
iterator.remove();
|
||||
parent.remove(last.getKey());
|
||||
last = null;
|
||||
}
|
||||
|
||||
public Object getKey() {
|
||||
|
||||
public K getKey() {
|
||||
if (last == null) {
|
||||
throw new IllegalStateException("Iterator getKey() can only be called after next() and before remove()");
|
||||
}
|
||||
return last.getKey();
|
||||
}
|
||||
|
||||
public Object getValue() {
|
||||
public V getValue() {
|
||||
if (last == null) {
|
||||
throw new IllegalStateException("Iterator getValue() can only be called after next() and before remove()");
|
||||
}
|
||||
return last.getValue();
|
||||
}
|
||||
|
||||
public Object setValue(Object value) {
|
||||
|
||||
public V setValue(V value) {
|
||||
if (last == null) {
|
||||
throw new IllegalStateException("Iterator setValue() can only be called after next() and before remove()");
|
||||
}
|
||||
if (parent.maps[1].containsKey(value) &&
|
||||
parent.maps[1].get(value) != last.getKey()) {
|
||||
if (parent.reverseMap.containsKey(value) &&
|
||||
parent.reverseMap.get(value) != last.getKey()) {
|
||||
throw new IllegalArgumentException("Cannot use setValue() when the object being set is already in the map");
|
||||
}
|
||||
return parent.put(last.getKey(), value);
|
||||
}
|
||||
|
||||
|
||||
public void reset() {
|
||||
iterator = new ArrayList(parent.entrySet()).listIterator();
|
||||
iterator = new ArrayList<Map.Entry<K, V>>(parent.entrySet()).listIterator();
|
||||
last = null;
|
||||
}
|
||||
|
||||
|
||||
public String toString() {
|
||||
if (last != null) {
|
||||
return "MapIterator[" + getKey() + "=" + getValue() + "]";
|
||||
} else {
|
||||
return "MapIterator[]";
|
||||
}
|
||||
return "MapIterator[]";
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Serialization
|
||||
//-----------------------------------------------------------------------
|
||||
private void writeObject(ObjectOutputStream out) throws IOException {
|
||||
out.defaultWriteObject();
|
||||
out.writeObject(maps[0]);
|
||||
out.writeObject(normalMap);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
|
||||
in.defaultReadObject();
|
||||
maps[0] = new TreeMap(comparator);
|
||||
maps[1] = new TreeMap(comparator);
|
||||
normalMap = new TreeMap(comparator);
|
||||
reverseMap = new TreeMap(comparator);
|
||||
Map map = (Map) in.readObject();
|
||||
putAll(map);
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue