sclass Best is IBest {
A best;
double score;
bool verboseNewBest, replaceIfSameScore;
settable bool lowerIsBetter;
transient O onChange;
transient O stringifier; // func(A) -> S
synchronized bool isNewBest(double score) {
ret best == null || !isNaN(score)
&& (replaceIfSameScore
? compareScores(score, this.score) >= 0
: compareScores(score, this.score) > 0);
}
double worstScore() {
ret lowerIsBetter ? infinity() : minusInfinity();
}
int compareScores(double a, double b) {
ret lowerIsBetter ? -cmp(a, b) : cmp(a, b);
}
synchronized double bestScore() {
ret best == null ? worstScore() : score;
}
double score() { ret bestScore(); }
double getScore() { ret bestScore(); }
synchronized float floatScoreOr(float defaultValue) {
ret best == null ? defaultValue : (float) score;
}
bool put(Scored extends A> s) {
ret s != null && put(s!, s.score());
}
bool put(Pair extends A, Double> p) {
ret p != null && put(p.a, p.b);
}
bool put(Best extends A> b) {
ret b != null && put(b!, b.score);
}
public bool put(A a, double score) {
ping();
bool change = false;
if (a != null) synchronized(this) {
if (isNewBest(score)) {
best = a;
this.score = score;
change = true;
}
}
if (change) {
if (verboseNewBest) print("New best! " + this);
pcallF(onChange);
}
ret change;
}
synchronized A get() { ret best; }
synchronized bool has() { ret best != null; }
synchronized Pair pair() { ret main pair(best, bestScore()); }
synchronized Scored scored() { ret best == null ?: new Scored(best, bestScore()); }
synchronized A getIfScoreAbove(double x) { ret compareScores(score(), x) >= 0 ? best : null; }
toString {
ret "Score " + formatDouble_significant2(score, 4) + ": " + callStringifier(stringifier, best);
}
bool putAndPrintIfNewBest(A a, double score) {
if (!put(a, score)) false;
ret true with print(this);
}
synchronized void clear() { best = null; score = 0; }
}