ProjectAres/Util/core/src/main/java/tc/oc/commons/core/util/UsageCollection.java

88 lines
2.2 KiB
Java

package tc.oc.commons.core.util;
import org.apache.commons.lang.mutable.MutableInt;
import tc.oc.commons.core.random.RandomUtils;
import javax.annotation.Nullable;
import java.util.*;
/**
* A map that can ensure even distribution of key outputs.
*/
public class UsageCollection<E> extends HashMap<E, UsageCollection.Index> {
private final Random random;
public UsageCollection(Random random, Collection<E> initial) {
super();
this.random = random;
initial.forEach(this::use);
}
/**
* Add or use an object to this usage collection.
* @param object the object to add or use.
*/
public void use(E object) {
if(!containsKey(object)) {
put(object, new Index());
} else {
get(object).change(+1);
}
}
/**
* Allocate an additional usage space for an object.
* @param object the object to allocate an additional space for.
*/
public void allocate(E object) {
if(containsValue(object)) {
get(object).change(-1);
}
}
/**
* Get the object with the least amount of usages.
* @return the least used object.
*/
public @Nullable E next() {
if(isEmpty()) {
return null;
} else {
E next = getLeastKey();
use(next);
return next;
}
}
protected @Nullable E getLeastKey() {
List<E> leastKeys = new ArrayList<>();
int leastValue = Integer.MAX_VALUE;
for(Map.Entry<E, Index> entry : entrySet()) {
int value = entry.getValue().intValue();
if(entry.getValue().intValue() < leastValue) {
leastValue = value;
leastKeys.clear();
}
if(value == leastValue) {
leastKeys.add(entry.getKey());
}
}
return leastKeys.isEmpty() ? null : RandomUtils.element(random, leastKeys);
}
static class Index extends MutableInt {
public Index() {
super(0);
}
public Index change(int delta) {
setValue(Math.max(0, intValue() + delta));
return this;
}
}
}