Jim Janney said:
The ordering is defined by nextInsertionRank. Making that a member of
the map may not be the best choice. This is not a finished product,
only a sketch of an approach to the problem. Some interesting bugs have
been left as an exercise for the reader...
Here is a design I like better. It reduces the coupling between classes
and better reflects the underlying concepts:
/**
* Define an arbitrary ordering on a finite set of values.
* The ordering is determined by the order of calls to {@code register}.
*/
public class ArbitraryOrder<T> implements Comparator<T> {
private long nextInsertionRank = 0;
private final Map<T, Long> insertionRanks = new HashMap<T, Long>();
@Override
public int compare(T o1, T o2) {
Long rank1 = insertionRanks.get(o1);
if (rank1 == null) {
throw new IllegalArgumentException(o1 + " is not registered");
}
Long rank2 = insertionRanks.get(o2);
if (rank2 == null) {
throw new IllegalArgumentException(o2 + " is not registered");
}
return rank1.compareTo(rank2);
}
public void register(T value) {
insertionRanks.put(value, nextInsertionRank++);
}
public void remove(Object key) {
insertionRanks.remove(key);
}
}
public class InsertionOrderedMap<K,V> extends TreeMap<K,V> {
public InsertionOrderedMap() {
super(new ArbitraryOrder<K>());
}
@Override
public V put(K key, V value) {
((ArbitraryOrder<K>)comparator()).register(key);
return super.put(key, value);
};
@Override
public V remove(Object key) {
V result = super.remove(key);
((ArbitraryOrder<K>)comparator()).remove(key);
return result;
}
}