#ifndef GPU_RZE
#define GPU_RZE
#include "d_zero_elimination.h"
#include "d_repetition_elimination.h"
template <typename T>
static __device__ inline bool d_RZE(int& csize, byte in [CS], byte out [CS], byte temp [CS])
{
const int tid = threadIdx.x;
const int size = csize / sizeof(T); const int extra = csize % sizeof(T);
const int avail = CS - 2 - extra;
const int bits = 8 * sizeof(T);
assert(CS == 16384);
int* const temp_w = (int*)temp;
byte* const bitmap = (byte*)&temp_w[WS + 1];
if (csize < CS) {
for (int i = csize / bits + tid; i < CS / bits; i += TPB) {
bitmap[i] = 0;
}
__syncthreads();
}
int wpos = 0;
if (size > 0) d_ZEencode((T*)in, size, (T*)out, wpos, (T*)bitmap, temp_w);
wpos *= sizeof(T);
if (wpos >= avail) return false;
__syncthreads();
if (wpos != 0) {
int base = 0 / sizeof(T);
int range = 2048 / sizeof(T);
int cnt = avail - wpos;
if (!d_REencode<byte, 2048 / sizeof(T), true>(&bitmap[base], range, &out[wpos], cnt, &bitmap[base + range], temp_w)) return false;
wpos += cnt;
__syncthreads();
base = 2048 / sizeof(T);
range = 256 / sizeof(T);
cnt = avail - wpos;
if (!d_REencode<byte, 256 / sizeof(T), true>(&bitmap[base], range, &out[wpos], cnt, &bitmap[base + range], temp_w)) return false;
wpos += cnt;
__syncthreads();
base = (2048 + 256) / sizeof(T);
range = 32 / sizeof(T);
if constexpr (sizeof(T) < 8) {
cnt = avail - wpos;
if (!d_REencode<byte, 32 / sizeof(T), true>(&bitmap[base], range, &out[wpos], cnt, &bitmap[base + range], temp_w)) return false;
wpos += cnt;
base = (2048 + 256 + 32) / sizeof(T);
range = 4 / sizeof(T);
}
if (wpos >= avail - range) return false;
if (tid < range) { out[wpos + tid] = bitmap[base + tid];
}
wpos += range;
}
if constexpr (sizeof(T) > 1) {
if (tid < extra) out[wpos + tid] = in[csize - extra + tid];
}
const int new_size = wpos + 2 + extra;
if (tid == 0) {
out[new_size - 2] = csize; out[new_size - 1] = csize >> 8; }
csize = new_size;
return true;
}
template <typename T>
static __device__ inline void d_iRZE(int& csize, byte in [CS], byte out [CS], byte temp [CS])
{
const int tid = threadIdx.x;
int rpos = csize;
csize = (int)in[--rpos] << 8; csize |= in[--rpos]; const int size = csize / sizeof(T); assert(CS == 16384);
assert(TPB >= 256);
if constexpr (sizeof(T) > 1) {
const int extra = csize % sizeof(T);
if (tid < extra) out[csize - extra + tid] = in[rpos - extra + tid];
rpos -= extra;
}
if (rpos == 0) {
T* const out_t = (T*)out;
for (int i = tid; i < size; i += TPB) {
out_t[i] = 0;
}
} else {
int* const temp_w = (int*)temp;
byte* const bitmap = (byte*)&temp_w[WS];
int base, range;
if constexpr (sizeof(T) == 8) {
base = (2048 + 256) / sizeof(T);
range = 32 / sizeof(T);
rpos -= range;
if (tid < range) bitmap[base + tid] = in[rpos + tid];
} else {
base = (2048 + 256 + 32) / sizeof(T);
range = 4 / sizeof(T);
rpos -= range;
if (tid < range) bitmap[base + tid] = in[rpos + tid];
rpos -= __syncthreads_count((tid < range * 8) && ((in[rpos + tid / 8] >> (tid % 8)) & 1));
base = (2048 + 256) / sizeof(T);
range = 32 / sizeof(T);
d_REdecode<byte, 32 / sizeof(T)>(range, &in[rpos], &bitmap[base + range], &bitmap[base], temp_w);
}
__syncthreads();
rpos -= __syncthreads_count((tid < range * 8) && ((bitmap[base + tid / 8] >> (tid % 8)) & 1));
base = 2048 / sizeof(T);
range = 256 / sizeof(T);
d_REdecode<byte, 256 / sizeof(T)>(range, &in[rpos], &bitmap[base + range], &bitmap[base], temp_w);
__syncthreads();
if constexpr (sizeof(T) >= 4) {
rpos -= __syncthreads_count((tid < range * 8) && ((bitmap[base + tid / 8] >> (tid % 8)) & 1));
}
if constexpr (sizeof(T) == 2) {
int sum = __syncthreads_count((tid < range * 8) && ((bitmap[base + tid / 8] >> (tid % 8)) & 1));
sum += __syncthreads_count((tid + TPB < range * 8) && ((bitmap[base + (tid + TPB) / 8] >> (tid % 8)) & 1));
rpos -= sum;
}
if constexpr (sizeof(T) == 1) {
int sum = 0;
for (int i = 0; i < TPB * 4; i += TPB) {
sum += __syncthreads_count((tid + i < range * 8) && ((bitmap[base + (tid + i) / 8] >> (tid % 8)) & 1));
}
rpos -= sum;
}
base = 0 / sizeof(T);
range = 2048 / sizeof(T);
d_REdecode<byte, 2048 / sizeof(T)>(range, &in[rpos], &bitmap[base + range], &bitmap[base], temp_w);
__syncthreads();
if (size > 0) d_ZEdecode(size, (T*)in, (T*)bitmap, (T*)out, temp_w);
}
}
#endif