#ifndef SIMPLE8B_RLE_H_
#define SIMPLE8B_RLE_H_
#include "common.h"
#include "codecs.h"
#define _SIMPLE8B_USE_RLE
namespace FastPForLib {
static const uint32_t Simple8b_Codec_bitLength[] = {1, 1, 2, 3, 4, 5, 6, 7,
8, 10, 12, 15, 20, 30, 60, 32};
class Simple8b_Codec {
static const uint32_t SIMPLE8B_BITSIZE = 60;
static const uint32_t SIMPLE8B_MAXCODE = 15;
static const uint32_t SIMPLE8B_MINCODE = 1;
#if defined(_SIMPLE8B_USE_RLE)
static const uint32_t RLE_MAX_VALUE_BITS = 32;
static const uint32_t RLE_MAX_COUNT_BITS =
SIMPLE8B_BITSIZE - RLE_MAX_VALUE_BITS;
static const uint64_t RLE_MAX_VALUE_MASK = (1ULL << RLE_MAX_VALUE_BITS) - 1;
static const uint64_t RLE_MAX_COUNT_MASK = (1ULL << RLE_MAX_COUNT_BITS) - 1;
static uint32_t tryRunLength(const uint32_t *input, uint32_t pos,
uint32_t count) {
uint32_t startPos = pos;
uint32_t endPos = pos + count;
uint32_t test = input[pos++];
if (test > RLE_MAX_VALUE_MASK)
return 0;
while (pos < endPos && test == input[pos]) {
pos++;
}
uint32_t bitLen = bits(test | 1U);
uint32_t repeatCount = (pos - startPos);
return (bitLen * repeatCount >= SIMPLE8B_BITSIZE) ? repeatCount : 0;
}
#endif
public:
static int32_t Compress(const uint32_t *input, int32_t inOffset,
uint32_t inCount, uint64_t *output,
int32_t outOffset) {
uint32_t inPos = inOffset;
uint32_t inEnd = inOffset + inCount;
uint32_t outPos = outOffset;
while (inPos < inEnd) {
uint32_t remainingCount = inEnd - inPos;
uint64_t outVal = 0;
#if defined(_SIMPLE8B_USE_RLE)
uint64_t repeatCount = tryRunLength(input, inPos, remainingCount);
if (repeatCount > 0) {
repeatCount = (repeatCount < RLE_MAX_COUNT_MASK) ? repeatCount
: RLE_MAX_COUNT_MASK;
outVal = (static_cast<uint64_t>(SIMPLE8B_MAXCODE) << SIMPLE8B_BITSIZE) |
(repeatCount << RLE_MAX_VALUE_BITS) | input[inPos];
inPos += static_cast<uint32_t>(repeatCount);
} else
#endif
{
uint32_t code = SIMPLE8B_MINCODE;
for (; code < SIMPLE8B_MAXCODE; code++) {
uint32_t intNum = Simple8b_Codec_bitLength[SIMPLE8B_MAXCODE - code];
uint32_t bitLen = Simple8b_Codec_bitLength[code];
intNum = (intNum < remainingCount) ? intNum : remainingCount;
uint64_t maxVal = (1ULL << bitLen) - 1;
uint64_t val = static_cast<uint64_t>(code) << SIMPLE8B_BITSIZE;
uint32_t j = 0;
for (; j < intNum; j++) {
uint64_t inputVal = static_cast<uint64_t>(input[inPos + j]);
if (inputVal > maxVal) {
break;
}
val |= inputVal << (j * bitLen);
}
if (j == intNum) {
outVal = val;
inPos += intNum;
break;
}
}
if (code == SIMPLE8B_MAXCODE) {
outVal = (static_cast<uint64_t>(code) << SIMPLE8B_BITSIZE) |
input[inPos++];
}
}
output[outPos++] = outVal;
}
return outPos - outOffset;
}
static uint32_t Decompress(const uint64_t *input, uint32_t,
uint32_t *output, uint32_t outOffset,
uint32_t outCount) {
uint32_t inPos = 0;
uint32_t outPos = outOffset;
uint32_t outEnd = outOffset + outCount;
while (outPos < outEnd) {
uint32_t remainingCount = outEnd - outPos;
uint64_t val = input[inPos++];
uint32_t code = static_cast<uint32_t>(val >> SIMPLE8B_BITSIZE);
if (code == 0) {
break; }
#if defined(_SIMPLE8B_USE_RLE)
else if (code == SIMPLE8B_MAXCODE) {
uint32_t repeatValue = static_cast<uint32_t>(val & RLE_MAX_VALUE_MASK);
uint32_t repeatCount = static_cast<uint32_t>(
(val >> RLE_MAX_VALUE_BITS) & RLE_MAX_COUNT_MASK);
repeatCount =
(repeatCount < remainingCount) ? repeatCount : remainingCount;
for (uint32_t i = 0; i < repeatCount; ++i) {
output[outPos++] = repeatValue;
}
}
#endif
else {
uint32_t intNum = Simple8b_Codec_bitLength[SIMPLE8B_MAXCODE - code];
uint32_t bitLen = Simple8b_Codec_bitLength[code];
uint64_t bitMask = (1ULL << bitLen) - 1;
intNum = (intNum < remainingCount)
? intNum
: remainingCount;
#if defined(_DONT_UNROLL_LOOP)
for (uint32_t i = 0; i < intNum; ++i) {
output[outPos++] = static_cast<uint32_t>(val & bitMask);
val >>= bitLen;
}
#else
uint32_t i = 0;
for (; i < intNum; i += 8) {
auto out = output + outPos + i;
out[0] = static_cast<uint32_t>(val & bitMask);
val >>= bitLen;
out[1] = static_cast<uint32_t>(val & bitMask);
val >>= bitLen;
out[2] = static_cast<uint32_t>(val & bitMask);
val >>= bitLen;
out[3] = static_cast<uint32_t>(val & bitMask);
val >>= bitLen;
out[4] = static_cast<uint32_t>(val & bitMask);
val >>= bitLen;
out[5] = static_cast<uint32_t>(val & bitMask);
val >>= bitLen;
out[6] = static_cast<uint32_t>(val & bitMask);
val >>= bitLen;
out[7] = static_cast<uint32_t>(val & bitMask);
val >>= bitLen;
}
for (; i < intNum; ++i) {
auto out = output + outPos + i;
out[0] = static_cast<uint32_t>(val & bitMask);
val >>= bitLen;
}
outPos += intNum;
#endif
}
}
return inPos;
}
};
template <bool MarkLength> class Simple8b_RLE : public IntegerCODEC {
public:
std::string name() const { return "Simple8b_RLE"; }
void encodeArray(const uint32_t *in, const size_t length, uint32_t *out,
size_t &nvalue) {
if (MarkLength) {
*out++ = static_cast<uint32_t>(length);
}
uint64_t *out64 = reinterpret_cast<uint64_t *>(out);
auto count = Simple8b_Codec::Compress(in, 0, uint32_t(length), out64, 0);
nvalue = count * 2;
}
const uint32_t *decodeArray(const uint32_t *in, const size_t length,
uint32_t *out, size_t &nvalue) {
(void)length;
uint32_t markednvalue;
if (MarkLength) {
markednvalue = *in++;
if (markednvalue > nvalue)
throw NotEnoughStorage(markednvalue);
}
const size_t actualvalue = MarkLength ? markednvalue : nvalue;
const uint64_t *in64 = reinterpret_cast<const uint64_t *>(in);
#ifndef NDEBUG
const uint32_t *const endin(in + length);
const uint64_t *finalin64 = reinterpret_cast<const uint64_t *>(endin);
#endif
if (nvalue < actualvalue) {
fprintf(stderr, "possible overrun\n");
}
nvalue = actualvalue;
uint32_t pos = 0;
pos = Simple8b_Codec::Decompress(in64, 0, out, 0, uint32_t(nvalue));
assert(in64 + pos <= finalin64);
in = reinterpret_cast<const uint32_t *>(in64 + pos);
assert(in <= endin);
nvalue = MarkLength ? actualvalue : nvalue;
return in;
}
};
#undef _SIMPLE8B_USE_RLE
}
#endif