88 lines
2.2 KiB
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;
|
|
}
|
|
|
|
}
|
|
|
|
}
|