// (c) 2010 Thomas Schoebel-Theuer / 1&1 Internet AG // (c) 2012 Thomas Schoebel-Theuer #ifndef LIB_RANK_H #define LIB_RANK_H /* Generic round-robin scheduler based on ranking information. */ #define RKI_DUMMY INT_MIN struct rank_info { int rki_x; int rki_y; }; struct rank_data { // public readonly long long rkd_current_points; // private long long rkd_tmp; long long rkd_got; }; /* Ranking phase. * * Calls should follow the following usage pattern: * * ranking_start(...); * for (...) { * ranking_compute(&rkd[this_time], ...); * // usually you need at least 1 call for each rkd[] element, * // but you can call more often to include ranking information * // from many different sources. * // Note: instead / additionally, you may also use * // ranking_add() or ranking_override(). * } * ranking_stop(...); * * => now the new ranking values are computed and already active * for the round-robin ranking_select() mechanism described below. * * Important: the rki[] array describes a ranking function at some * example points (x_i,y_i) which must be ordered according to x_i * in ascending order. And, of course, you need to supply at least * two sample points (otherwise a linear function cannot * be described). * The array _must_ always end with a dummy record where the x_i has the * value RKI_DUMMY. */ extern inline void ranking_start(struct rank_data rkd[], int rkd_count) { int i; for (i = 0; i < rkd_count; i++) { rkd[i].rkd_tmp = 0; } } extern void ranking_compute(struct rank_data *rkd, const struct rank_info rki[], int x); /* This may be used to (exceptionally) add some extra salt... */ extern inline void ranking_add(struct rank_data *rkd, int y) { rkd->rkd_tmp += y; } /* This may be used to (exceptionally) override certain ranking values. */ extern inline void ranking_override(struct rank_data *rkd, int y) { rkd->rkd_tmp = y; } extern inline void ranking_stop(struct rank_data rkd[], int rkd_count) { int i; for (i = 0; i < rkd_count; i++) { rkd[i].rkd_current_points = rkd[i].rkd_tmp; } } /* This is a round-robin scheduler taking her weights * from the previous ranking phase (the more ranking points, * the more frequently a candidate will be selected). * * Typical usage pattern (independent from the above ranking phase * usage pattern): * * while (__there_is_work_to_be_done(...)) { * int winner = ranking_select(...); * if (winner >= 0) { * __do_something(winner); * ranking_select_done(..., winner, 1); // or higher, winpoints >= 1 must hold * } * ... * } * */ extern int ranking_select(struct rank_data rkd[], int rkd_count); extern inline void ranking_select_done(struct rank_data rkd[], int winner, int win_points) { if (winner >= 0) { if (win_points < 1) win_points = 1; rkd[winner].rkd_got += win_points; } } #endif