#ifndef SIMPLE9_RLE_H_
#define SIMPLE9_RLE_H_
#include "common.h"
#include "codecs.h"
namespace FastPForLib {
static const uint32_t Simple9_Codec_intNumber[] = { 28, 14, 9, 7, 5, 4, 3, 2,
1, 1, 1, 1, 1, 1, 1, 1 };
static const uint32_t Simple9_Codec_bitLength[] = { 1, 2, 3, 4, 5, 7, 9, 14,
31, 31, 31, 31, 31, 31, 31, 31 };
class Simple9_Codec {
static const uint32_t SIMPLE9_BITSIZE = 28;
static const uint32_t SIMPLE9_MAXCODE = 8;
#if !defined(_SIMPLE9_USE_RLE)
static const uint32_t SIMPLE9_MINCODE =
0; #else
static const uint32_t SIMPLE9_MINCODE = 1;
static const uint32_t RLE_SELECTOR_VALUE = 0;
static const uint32_t RLE_MAX_VALUE_BITS = 16;
static const uint32_t RLE_MAX_COUNT_BITS =
SIMPLE9_BITSIZE - RLE_MAX_VALUE_BITS;
static const uint32_t RLE_MAX_VALUE_MASK = (1U << RLE_MAX_VALUE_BITS) - 1;
static const uint32_t RLE_MAX_COUNT_MASK = (1U << 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 >= SIMPLE9_BITSIZE) ? repeatCount : 0;
}
#endif
public:
static int32_t Compress(const uint32_t *input, int32_t inOffset,
uint32_t inCount, uint32_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;
uint32_t outVal = 0;
#if defined(_SIMPLE9_USE_RLE)
uint32_t repeatCount = tryRunLength(input, inPos, remainingCount);
if (repeatCount > 0) {
repeatCount = (repeatCount < RLE_MAX_COUNT_MASK) ? repeatCount
: RLE_MAX_COUNT_MASK;
outVal = (RLE_SELECTOR_VALUE << SIMPLE9_BITSIZE) |
(repeatCount << RLE_MAX_VALUE_BITS) | input[inPos];
inPos += repeatCount;
} else
#endif
{
uint32_t code = SIMPLE9_MINCODE;
for (; code < SIMPLE9_MAXCODE; code++) {
uint32_t intNum = Simple9_Codec_intNumber[code];
uint32_t bitLen = Simple9_Codec_bitLength[code];
intNum = (intNum < remainingCount) ? intNum : remainingCount;
uint32_t maxVal = (1U << bitLen) - 1;
uint32_t val = code << SIMPLE9_BITSIZE;
uint32_t j = 0;
for (; j < intNum; j++) {
uint32_t inputVal = input[inPos + j];
if (inputVal > maxVal) {
break;
}
val |= inputVal << (j * bitLen);
}
if (j == intNum) {
outVal = val;
inPos += intNum;
break;
}
}
if (code == SIMPLE9_MAXCODE) {
outVal = (code << SIMPLE9_BITSIZE) | input[inPos++];
}
}
output[outPos++] = outVal;
}
return outPos - outOffset;
}
static uint32_t Decompress(const uint32_t *input, uint32_t inOffset,
uint32_t *output, uint32_t outOffset,
uint32_t outCount) {
uint32_t inPos = inOffset;
uint32_t outPos = outOffset;
uint32_t outEnd = outOffset + outCount;
while (outPos < outEnd) {
uint32_t remainingCount = outEnd - outPos;
uint32_t val = input[inPos++];
uint32_t code = val >> SIMPLE9_BITSIZE;
#if defined(_SIMPLE9_USE_RLE)
if (code == RLE_SELECTOR_VALUE) {
uint32_t repeatValue = val & RLE_MAX_VALUE_MASK;
uint32_t repeatCount = (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;
}
}
#else
if (SIMPLE9_MINCODE == 1 && code == 0) {
break; }
#endif
else {
uint32_t intNum = Simple9_Codec_intNumber[code];
uint32_t bitLen = Simple9_Codec_bitLength[code];
uint32_t bitMask = (1U << bitLen) - 1;
intNum = (intNum < remainingCount)
? intNum
: remainingCount;
#if defined(_DONT_UNROLL_LOOP)
for (uint32_t i = 0; i < intNum; ++i) {
output[outPos++] = val & bitMask;
val >>= bitLen;
}
#else
uint32_t i = 0;
for (; i < intNum; i += 7) {
auto out = output + outPos + i;
out[0] = val & bitMask;
val >>= bitLen;
out[1] = val & bitMask;
val >>= bitLen;
out[2] = val & bitMask;
val >>= bitLen;
out[3] = val & bitMask;
val >>= bitLen;
out[4] = val & bitMask;
val >>= bitLen;
out[5] = val & bitMask;
val >>= bitLen;
out[6] = val & bitMask;
val >>= bitLen;
}
for (; i < intNum; ++i) {
auto out = output + outPos + i;
out[0] = val & bitMask;
val >>= bitLen;
}
outPos += intNum;
#endif
}
}
return inPos;
}
};
template <bool MarkLength> class Simple9_RLE : public IntegerCODEC {
public:
std::string name() const { return "Simple9_RLE"; }
void encodeArray(const uint32_t *input, const size_t length, uint32_t *out,
size_t &nvalue) {
if (MarkLength) {
*out++ = static_cast<uint32_t>(length);
}
auto count = Simple9_Codec::Compress(input, 0, uint32_t(length), out, 0);
nvalue = count;
}
const uint32_t *decodeArray(const uint32_t *input, const size_t,
uint32_t *out, size_t &nvalue) {
uint32_t markednvalue;
if (MarkLength) {
markednvalue = *input++;
if (markednvalue > nvalue)
throw NotEnoughStorage(markednvalue);
}
const size_t actualvalue = MarkLength ? markednvalue : nvalue;
if (nvalue < actualvalue) {
fprintf(stderr, "possible overrun\n");
}
auto count = actualvalue;
Simple9_Codec::Decompress(input, 0, out, 0, uint32_t(count));
nvalue = MarkLength ? actualvalue : count;
input += count;
return input;
}
};
#undef _SIMPLE9_USE_RLE
}
#endif