#include <limits.h>
static void _t2(fwd_xform, Int, DIMS)(Int* p);
static void
_t1(pad_block, Scalar)(Scalar* p, size_t n, ptrdiff_t s)
{
switch (n) {
case 0:
p[0 * s] = 0;
case 1:
p[1 * s] = p[0 * s];
case 2:
p[2 * s] = p[1 * s];
case 3:
p[3 * s] = p[0 * s];
default:
break;
}
}
static void
_t1(fwd_lift, Int)(Int* p, ptrdiff_t s)
{
Int x, y, z, w;
x = *p; p += s;
y = *p; p += s;
z = *p; p += s;
w = *p; p += s;
x += w; x >>= 1; w -= x;
z += y; z >>= 1; y -= z;
x += z; x >>= 1; z -= x;
w += y; w >>= 1; y -= w;
w += y >> 1; y -= w >> 1;
p -= s; *p = w;
p -= s; *p = z;
p -= s; *p = y;
p -= s; *p = x;
}
#if ZFP_ROUNDING_MODE == ZFP_ROUND_FIRST
static void
_t1(fwd_round, Int)(Int* iblock, uint n, uint maxprec)
{
if (maxprec < (uint)(CHAR_BIT * sizeof(Int))) {
Int bias = (NBMASK >> 2) >> maxprec;
if (maxprec & 1u)
do *iblock++ += bias; while (--n);
else
do *iblock++ -= bias; while (--n);
}
}
#endif
static UInt
_t1(int2uint, Int)(Int x)
{
return ((UInt)x + NBMASK) ^ NBMASK;
}
static void
_t1(fwd_order, Int)(UInt* ublock, const Int* iblock, const uchar* perm, uint n)
{
do
*ublock++ = _t1(int2uint, Int)(iblock[*perm++]);
while (--n);
}
static uint
_t1(encode_few_ints, UInt)(bitstream* restrict_ stream, uint maxbits, uint maxprec, const UInt* restrict_ data, uint size)
{
bitstream s = *stream;
uint intprec = (uint)(CHAR_BIT * sizeof(UInt));
uint kmin = intprec > maxprec ? intprec - maxprec : 0;
uint bits = maxbits;
uint i, k, m, n;
uint64 x;
for (k = intprec, n = 0; bits && k-- > kmin;) {
x = 0;
for (i = 0; i < size; i++)
x += (uint64)((data[i] >> k) & 1u) << i;
m = MIN(n, bits);
bits -= m;
x = stream_write_bits(&s, x, m);
for (; bits && n < size; x >>= 1, n++) {
bits--;
if (stream_write_bit(&s, !!x)) {
for (; bits && n < size - 1; x >>= 1, n++) {
bits--;
if (stream_write_bit(&s, x & 1u))
break;
}
}
else {
break;
}
}
}
*stream = s;
return maxbits - bits;
}
static uint
_t1(encode_many_ints, UInt)(bitstream* restrict_ stream, uint maxbits, uint maxprec, const UInt* restrict_ data, uint size)
{
bitstream s = *stream;
uint intprec = (uint)(CHAR_BIT * sizeof(UInt));
uint kmin = intprec > maxprec ? intprec - maxprec : 0;
uint bits = maxbits;
uint i, k, m, n, c;
for (k = intprec, n = 0; bits && k-- > kmin;) {
m = MIN(n, bits);
bits -= m;
for (i = 0; i < m; i++)
stream_write_bit(&s, (data[i] >> k) & 1u);
c = 0;
for (i = m; i < size; i++)
c += (data[i] >> k) & 1u;
for (; bits && n < size; n++) {
bits--;
if (stream_write_bit(&s, !!c)) {
for (c--; bits && n < size - 1; n++) {
bits--;
if (stream_write_bit(&s, (data[n] >> k) & 1u))
break;
}
}
else {
break;
}
}
}
*stream = s;
return maxbits - bits;
}
static uint
_t1(encode_few_ints_prec, UInt)(bitstream* restrict_ stream, uint maxprec, const UInt* restrict_ data, uint size)
{
bitstream s = *stream;
size_t offset = stream_wtell(&s);
uint intprec = (uint)(CHAR_BIT * sizeof(UInt));
uint kmin = intprec > maxprec ? intprec - maxprec : 0;
uint i, k, n;
for (k = intprec, n = 0; k-- > kmin;) {
uint64 x = 0;
for (i = 0; i < size; i++)
x += (uint64)((data[i] >> k) & 1u) << i;
x = stream_write_bits(&s, x, n);
for (; n < size && stream_write_bit(&s, !!x); x >>= 1, n++)
for (; n < size - 1 && !stream_write_bit(&s, x & 1u); x >>= 1, n++)
;
}
*stream = s;
return (uint)(stream_wtell(&s) - offset);
}
static uint
_t1(encode_many_ints_prec, UInt)(bitstream* restrict_ stream, uint maxprec, const UInt* restrict_ data, uint size)
{
bitstream s = *stream;
size_t offset = stream_wtell(&s);
uint intprec = (uint)(CHAR_BIT * sizeof(UInt));
uint kmin = intprec > maxprec ? intprec - maxprec : 0;
uint i, k, n, c;
for (k = intprec, n = 0; k-- > kmin;) {
for (i = 0; i < n; i++)
stream_write_bit(&s, (data[i] >> k) & 1u);
c = 0;
for (i = n; i < size; i++)
c += (data[i] >> k) & 1u;
for (; n < size && stream_write_bit(&s, !!c); n++)
for (c--; n < size - 1 && !stream_write_bit(&s, (data[n] >> k) & 1u); n++)
;
}
*stream = s;
return (uint)(stream_wtell(&s) - offset);
}
static uint
_t1(encode_ints, UInt)(bitstream* restrict_ stream, uint maxbits, uint maxprec, const UInt* restrict_ data, uint size)
{
if (with_maxbits(maxbits, maxprec, size)) {
if (size <= 64)
return _t1(encode_few_ints, UInt)(stream, maxbits, maxprec, data, size);
else
return _t1(encode_many_ints, UInt)(stream, maxbits, maxprec, data, size);
}
else {
if (size <= 64)
return _t1(encode_few_ints_prec, UInt)(stream, maxprec, data, size);
else
return _t1(encode_many_ints_prec, UInt)(stream, maxprec, data, size);
}
}
static uint
_t2(encode_block, Int, DIMS)(bitstream* stream, int minbits, int maxbits, int maxprec, Int* iblock)
{
int bits;
cache_align_(UInt ublock[BLOCK_SIZE]);
_t2(fwd_xform, Int, DIMS)(iblock);
#if ZFP_ROUNDING_MODE == ZFP_ROUND_FIRST
_t1(fwd_round, Int)(iblock, BLOCK_SIZE, maxprec);
#endif
_t1(fwd_order, Int)(ublock, iblock, PERM, BLOCK_SIZE);
bits = _t1(encode_ints, UInt)(stream, maxbits, maxprec, ublock, BLOCK_SIZE);
if (bits < minbits) {
stream_pad(stream, minbits - bits);
bits = minbits;
}
return bits;
}