mars/lib_rank.h
2013-01-23 20:06:51 +01:00

120 lines
2.9 KiB
C

// (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