package org.radargun.utils;
import java.lang.reflect.Array;
import java.util.ArrayList;
import java.util.Arrays;
/**
* Select between multiple weighted options
*
* @author Radim Vansa <rvansa@redhat.com>
*/
public class Selector<T> {
public final int[] ratios;
public final int max;
public final T[] options;
public Selector(int max, T[] options, int[] ratios) {
this.max = max;
this.options = options;
this.ratios = ratios;
}
public T select(int value) {
int index = Arrays.binarySearch(ratios, value);
if (index < 0) {
index = -index - 1;
} else {
index = index + 1;
}
return options[index];
}
public static class Builder<T, S extends Selector<T>> {
private final Class<T> clazz;
protected int max = 0;
protected ArrayList<Integer> ratios = new ArrayList<>();
protected ArrayList<T> options = new ArrayList<>();
public Builder(Class<T> clazz) {
this.clazz = clazz;
}
public Builder<T, S> add(T op, int ratio) {
if (ratio == 0) return this;
if (ratio < 0) throw new IllegalArgumentException("Ratio must be >= 0: " + ratio);
ratios.add(max + ratio);
max += ratio;
options.add(op);
return this;
}
public S build() {
if (max == 0) throw new IllegalStateException("No operations/ratios defined");
int[] ratios = new int[this.ratios.size()];
for (int i = 0; i < ratios.length; ++i) ratios[i] = this.ratios.get(i);
return newSelector(ratios);
}
protected S newSelector(int[] ratios) {
return (S) new Selector<T>(max, options.toArray((T[]) Array.newInstance(clazz, options.size())), ratios);
}
}
}