#ifndef SDI2_PAGER_RANGECLASSIFIER_H
#define SDI2_PAGER_RANGECLASSIFIER_H
#include <assert.h>
#include <stdio.h>
class RangeClassifier
{
private:
typedef L4_Word_t addr_t;
typedef unsigned int class_t;
struct interval
{
class_t id;
addr_t to;
interval() {
to = 0;
}
};
static const unsigned int intervalnum = 64;
struct interval interval[intervalnum];
unsigned int usednum;
inline void shift(unsigned int pos)
{
usednum++;
assert(usednum <= intervalnum);
for(unsigned int i = intervalnum-1; i > pos; i--)
{
interval[i] = interval[i-1];
}
}
inline void unshift(unsigned int pos, unsigned int n)
{
assert(n > 0);
assert(pos + n <= usednum);
for(unsigned int i = pos; i < usednum - n; i++)
{
interval[i] = interval[i + n];
}
interval[usednum - n].to = 0;
usednum -= n;
}
inline unsigned int search(addr_t pos) const
{
unsigned int i;
unsigned int low = 0;
unsigned int high = usednum-1;
while(1)
{
i = (high + low) / 2;
if (i > 0 && interval[i-1].to >= pos)
{
high = i-1;
}
else if (interval[i].to < pos)
{
low = i+1;
}
else
{
assert((i == 0 || interval[i-1].to < pos)
&& pos <= interval[i].to);
return i;
}
}
}
public:
explicit inline RangeClassifier(class_t initialid = 0)
: usednum(1)
{
interval[0].to = ~static_cast<addr_t>(0);
interval[0].id = initialid;
}
inline void set(addr_t from, addr_t to, class_t newid)
{
assert(from <= to);
if (from == to) return;
test();
unsigned int i = search(from);
assert(i < usednum);
unsigned int thisfrom = (i > 0 ? interval[i-1].to+1 : 0);
if (thisfrom == from)
{
if (i > 0 && interval[i-1].id == newid)
{
i--;
interval[i].to = to;
}
}
else if (interval[i].id != newid)
{
assert(thisfrom < from);
shift(i);
assert(from > 1);
interval[i].to = from-1;
i++;
}
unsigned int j = i;
while(j < usednum && to > interval[j].to)
j++;
while(j < usednum && interval[j].id == newid) {
to = interval[j].to;
if (j+1 >= usednum) break;
j++;
}
if (j > i) {
unshift(i, j - i);
}
if (to < interval[i].to)
{
shift(i);
}
interval[i].to = to;
interval[i].id = newid;
test();
}
inline class_t get(addr_t pos) const
{
unsigned int i = search(pos);
return interval[i].id;
}
inline class_t get2(addr_t pos) const
{
for(unsigned int i = 0; i < intervalnum; i++)
{
if (interval[i].to == 0) {
assert(0);
return 0;
}
if (pos <= interval[i].to)
return interval[i].id;
}
assert(0);
return 0;
}
inline void test() const
{
for(unsigned int i = 1; i < intervalnum; i++)
{
if (interval[i].to == 0) {
assert(i == usednum);
break;
}
assert(interval[i-1].to < interval[i].to);
assert(interval[i-1].id != interval[i].id);
}
}
inline void dump() const
{
unsigned int prevto = 0;
for(unsigned int i = 0; i < usednum; i++)
{
printf("0x%08x - 0x%08x : %d\n",
static_cast<unsigned int>(prevto),
static_cast<unsigned int>(interval[i].to),
interval[i].id);
prevto = interval[i].to+1;
}
}
};
#endif