#ifndef CPU_RZE
#define CPU_RZE
#include "h_zero_elimination.h"
template <typename T>
static inline bool h_RZE(int& csize, byte in [CS], byte out [CS])
{
const int size = csize / sizeof(T); const int extra = csize % sizeof(T);
const int bits = 8 * sizeof(T);
const int num = (2048 + 256 + 32 + 4) / sizeof(T);
assert(CS == 16384);
byte bitmap [num];
if (csize < CS) {
memset(&bitmap[csize / bits], 0, CS / bits - csize / bits);
}
int wpos = 0;
if (size > 0) h_ZEencode((T*)in, size, (T*)out, wpos, (T*)bitmap);
wpos *= sizeof(T);
if (wpos >= CS - 2 - extra) return false;
if (wpos != 0) {
int base = 0;
int range = CS / bits;
while (range >= 8) { byte prev = 0;
for (int i = 0; i < range; i += 8) {
const long long lval = *((long long*)(&bitmap[base + i]));
byte bmp = 0;
for (int j = 0; j < 8; j++) {
const byte val = (lval >> (j * 8)) & 0xff;
if (val != prev) {
out[wpos++] = prev = val;
bmp |= 1 << j;
if (wpos >= CS - 2 - extra) return false;
}
}
bitmap[base + range + i / 8] = bmp;
}
base += range;
range /= 8;
}
if (wpos >= CS - 2 - extra - range) return false;
for (int i = 0; i < range; i++) { out[wpos++] = bitmap[base + i];
}
}
if constexpr (sizeof(T) > 1) {
for (int i = 0; i < extra; i++) {
out[wpos++] = in[csize - extra + i];
}
}
out[wpos++] = csize; out[wpos++] = csize >> 8; csize = wpos;
return true;
}
template <typename T>
static inline void h_iRZE(int& csize, byte in [CS], byte out [CS])
{
int rpos = csize;
csize = (int)in[--rpos] << 8; csize |= in[--rpos]; const int size = csize / sizeof(T); const int bits = 8 * sizeof(T);
const int num = (2048 + 256 + 32 + 4) / sizeof(T);
assert(CS == 16384);
if constexpr (sizeof(T) > 1) {
const int extra = csize % sizeof(T);
for (int i = 0; i < extra; i++) {
out[csize - extra + i] = in[rpos - extra + i];
}
rpos -= extra;
}
if (rpos == 0) {
memset(out, 0, size * sizeof(T));
} else {
int base = 0;
int range = CS / bits;
while (range >= 8) { base += range;
range /= 8;
}
byte bitmap [num];
rpos -= range;
for (int i = 0; i < range; i++) { bitmap[base + i] = in[rpos + i];
}
while (range < CS / bits) { range *= 8;
base -= range;
if (range % 64 != 0) {
for (int i = 0; i < range; i += 8) {
rpos -= __builtin_popcount((int)bitmap[base + range + i / 8]);
}
} else {
for (int i = 0; i < range; i += 64) {
rpos -= __builtin_popcountll(*((long long*)(&bitmap[base + range + i / 8])));
}
}
int pos = rpos;
byte val = 0;
for (int i = 0; i < range; i++) {
if (bitmap[base + range + i / 8] & (1 << (i % 8))) {
val = in[pos++];
}
bitmap[base + i] = val;
}
}
if (size > 0) h_ZEdecode(size, (T*)in, (T*)bitmap, (T*)out);
}
}
#endif