160 lines
4.3 KiB
Java
160 lines
4.3 KiB
Java
package tc.oc.commons.core.util;
|
|
|
|
import java.util.ArrayList;
|
|
import java.util.Collection;
|
|
import java.util.Collections;
|
|
import java.util.Comparator;
|
|
import java.util.HashSet;
|
|
import java.util.Iterator;
|
|
import java.util.List;
|
|
import java.util.Set;
|
|
|
|
import com.google.common.collect.ForwardingSet;
|
|
import gnu.trove.impl.Constants;
|
|
import gnu.trove.map.TObjectIntMap;
|
|
import gnu.trove.map.hash.TObjectIntHashMap;
|
|
|
|
import static com.google.common.base.Preconditions.checkNotNull;
|
|
|
|
/**
|
|
* A set of objects with a dynamic partial ordering that can be manually invalidated.
|
|
* The ordering is always defined by a comparator passed to the constructor. Iteration
|
|
* is in this order, with equal elements in insertion order.
|
|
*
|
|
* A "rank" is a set of elements that compare equal. Each rank's "position" is the
|
|
* number of non-empty ranks who's elements compare lower than its own elements. The
|
|
* position of the first rank is 0.
|
|
*
|
|
* The elements are lazily sorted and cached whenever a method is called that depends
|
|
* on the ranking order. These methods are {@link #iterator}, {@link #getPosition},
|
|
* and {@link #getRank}. The cache is invalidated whenever the collection is changed,
|
|
* or {@link #invalidateRanking} is called.
|
|
*/
|
|
public class RankedSet<E> extends ForwardingSet<E> {
|
|
|
|
private final Comparator<E> comparator;
|
|
private final Set<E> set;
|
|
private final List<E> list = new ArrayList<>();
|
|
private final TObjectIntMap<E> rankByElement = new TObjectIntHashMap<>(Constants.DEFAULT_CAPACITY, Constants.DEFAULT_LOAD_FACTOR, -1);
|
|
private final List<Set<E>> ranks = new ArrayList<>();
|
|
private boolean sorted;
|
|
|
|
public RankedSet(Set<E> set, Comparator<E> comparator) {
|
|
this.set = checkNotNull(set);
|
|
this.comparator = checkNotNull(comparator);
|
|
}
|
|
|
|
public RankedSet(Comparator<E> comparator) {
|
|
this(new HashSet<E>(), comparator);
|
|
}
|
|
|
|
@Override
|
|
protected Set<E> delegate() {
|
|
return set;
|
|
}
|
|
|
|
private boolean freshenRanking() {
|
|
if(sorted) return false;
|
|
|
|
Collections.sort(list, comparator);
|
|
|
|
if(!list.isEmpty()) {
|
|
Set<E> rank = null;
|
|
E last = null;
|
|
for(E e : list) {
|
|
if(last == null || comparator.compare(last, e) != 0) {
|
|
ranks.add(rank = new HashSet<>());
|
|
}
|
|
rank.add(e);
|
|
rankByElement.put(e, ranks.size() - 1);
|
|
last = e;
|
|
}
|
|
}
|
|
|
|
sorted = true;
|
|
return true;
|
|
}
|
|
|
|
public void invalidateRanking() {
|
|
sorted = false;
|
|
ranks.clear();
|
|
rankByElement.clear();
|
|
}
|
|
|
|
/**
|
|
* Return the position of the given element in the ranking, or -1 if the element is not present.
|
|
*/
|
|
public int getPosition(E e) {
|
|
freshenRanking();
|
|
return rankByElement.get(e);
|
|
}
|
|
|
|
/**
|
|
* Return the set of elements with the given position.
|
|
* If no elements have the given position, the empty set is returned.
|
|
*/
|
|
public Set<E> getRank(int rank) {
|
|
freshenRanking();
|
|
return rank < ranks.size() ? ranks.get(rank)
|
|
: Collections.<E>emptySet();
|
|
}
|
|
|
|
/**
|
|
* Iterate in ranking order
|
|
*/
|
|
@Override
|
|
public Iterator<E> iterator() {
|
|
freshenRanking();
|
|
return list.iterator();
|
|
}
|
|
|
|
/**
|
|
* Iterate in arbitrary order
|
|
*/
|
|
public Iterator<E> unorderedIterator() {
|
|
return super.iterator();
|
|
}
|
|
|
|
@Override
|
|
public boolean add(E e) {
|
|
list.add(e);
|
|
invalidateRanking();
|
|
return super.add(e);
|
|
}
|
|
|
|
@Override
|
|
public boolean remove(Object e) {
|
|
list.remove(e);
|
|
invalidateRanking();
|
|
return super.remove(e);
|
|
}
|
|
|
|
@Override
|
|
public boolean addAll(Collection<? extends E> c) {
|
|
list.addAll(c);
|
|
invalidateRanking();
|
|
return super.addAll(c);
|
|
}
|
|
|
|
@Override
|
|
public boolean removeAll(Collection<?> c) {
|
|
list.removeAll(c);
|
|
invalidateRanking();
|
|
return super.removeAll(c);
|
|
}
|
|
|
|
@Override
|
|
public boolean retainAll(Collection<?> c) {
|
|
list.retainAll(c);
|
|
invalidateRanking();
|
|
return super.retainAll(c);
|
|
}
|
|
|
|
@Override
|
|
public void clear() {
|
|
list.clear();
|
|
invalidateRanking();
|
|
super.clear();
|
|
}
|
|
}
|