#include <stdexcept>
#include "rcqsmodel.h"
#define TBLSHIFT 7
RCqsmodel::RCqsmodel(bool compress, uint symbols, uint bits, uint period) : RCmodel(symbols), bits(bits), targetrescale(period)
{
if (bits > 16)
throw std::domain_error("fpzip RCqsmodel bits too large");
if (period >= (1u << (bits + 1)))
throw std::domain_error("fpzip RCqsmodel period too large");
uint n = symbols;
symf = new uint[n + 1];
cumf = new uint[n + 1];
cumf[0] = 0;
cumf[n] = 1u << bits;
if (compress)
search = 0;
else {
searchshift = bits - TBLSHIFT;
search = new uint[(1 << TBLSHIFT) + 1];
}
reset();
}
RCqsmodel::~RCqsmodel()
{
delete [] symf;
delete [] cumf;
delete [] search;
}
void RCqsmodel::reset()
{
uint n = symbols;
rescale = (n >> 4) | 2;
more = 0;
uint f = cumf[n] / n;
uint m = cumf[n] % n;
for (uint i = 0; i < m; i++)
symf[i] = f + 1;
for (uint i = m; i < n; i++)
symf[i] = f;
update();
}
uint RCqsmodel::decode(uint& l, uint& r)
{
uint i = l >> searchshift;
uint s = search[i];
uint h = search[i + 1] + 1;
while (s + 1 < h) {
uint m = (s + h) / 2;
if (l < cumf[m])
h = m;
else
s = m;
}
l = cumf[s];
r = cumf[s + 1] - l;
update(s);
return s;
}
void RCqsmodel::update()
{
if (more) { left = more;
more = 0;
incr++;
return;
}
if (rescale != targetrescale) {
rescale *= 2;
if (rescale > targetrescale)
rescale = targetrescale;
}
uint n = symbols;
uint cf = cumf[n];
uint count = cf;
for (uint i = n; i--; ) {
uint sf = symf[i];
cf -= sf;
cumf[i] = cf;
sf = (sf >> 1) | 1;
count -= sf;
symf[i] = sf;
}
incr = count / rescale;
more = count % rescale;
left = rescale - more;
if (search)
for (uint i = n, h = 1 << TBLSHIFT; i--; h = cumf[i] >> searchshift)
for (uint l = cumf[i] >> searchshift; l <= h; l++)
search[l] = i;
}
void RCqsmodel::update(uint s)
{
if (!left)
update();
left--;
symf[s] += incr;
}