diff --git a/elfling_unpack.hpp b/elfling_unpack.hpp new file mode 100644 index 0000000..4d623f3 --- /dev/null +++ b/elfling_unpack.hpp @@ -0,0 +1,83 @@ +#ifndef ELFLING_UNPACK_HPP +#define ELFLING_UNPACK_HPP + +#include + +#if !defined(MAX_CONTEXT_COUNT) +#define MAX_CONTEXT_COUNT 16 +#endif + +#if !defined(MAX_CONTEXT_SIZE) +#define MAX_CONTEXT_SIZE (4 << 20) +#endif + +static void elfling_unpack(const uint8_t* weights, const uint8_t* contexts, unsigned contextCount, void* work, + const void* in, void* out, unsigned outLen) +{ + uint8_t* counters[MAX_CONTEXT_COUNT]; // Counter base offsets + uint8_t* cp[MAX_CONTEXT_COUNT]; // Current counters + const uint8_t* archive = static_cast(in); + uint8_t* cout = static_cast(out); + uint8_t* base = static_cast(work); + + for (uint8_t m = 0; m < contextCount; ++m) { + counters[m] = base; + cp[m] = base; + base += MAX_CONTEXT_SIZE; + } + + *cout = 1; + uint32_t x1 = 0, x2 = 0xffffffff; + for (uint32_t j = outLen * 8; j > 0; --j) { + uint32_t n0 = 1, n1 = 1; + for (uint8_t m = 0; m < contextCount; ++m) { + n0 += cp[m][0] * weights[m]; + n1 += cp[m][1] * weights[m]; + } + + uint32_t xmid = x1 + n0 * (uint64_t)(x2 - x1) / (n0 + n1); + + uint8_t y; + cout[0] <<= 1; + if (*(uint32_t*)archive <= xmid) { + x2 = xmid; + y = 0; + } else { + cout[0] += 1; + x1 = xmid + 1; + y = 1; + } + + if (((j - 1) & 7) == 0) { // Start new byte + cout++; + *cout = 1; + } + + // Count y by context + for (uint8_t m = 0; m < contextCount; ++m) { + if (cp[m][y] < 255) + ++cp[m][y]; + if (cp[m][1 - y] > 2) + cp[m][1 - y] = cp[m][1 - y] / 2 + 1; + uint32_t off = 0; + for (char i = 0; i < 8; ++i) { + if (contexts[m] & (1 << i)) { + off = (off << 8) + cout[-i]; + } + } + uint32_t c = 0; + while (*(uint32_t*)&counters[m][c] != 0 && *(uint32_t*)&counters[m][c] != off) c += 6; + *(uint32_t*)&counters[m][c] = off; + cp[m] = &counters[m][c + 4]; + } + + while (((x1 ^ x2) >> 24) == 0) { + x1 <<= 8; + x2 = (x2 << 8) + 255; + --archive; + } + } +} + +#endif + diff --git a/pack.cpp b/pack.cpp index dc96e22..83365f5 100644 --- a/pack.cpp +++ b/pack.cpp @@ -124,7 +124,7 @@ bool Compressor::Compress(CompressionParameters* params, void* in, int inLen, vo CompressSingle(&c, in, inLen, out, &pats[pc].bs); ++pc; } - qsort(pats, pc, sizeof(Context), (__compar_fn_t)CompareContext); + qsort(pats, pc, sizeof(Context), (int (*)(const void*, const void*))CompareContext); if (verbose_) { for (int i = 0; i < pc; ++i) { printf("Pattern %2d [%2.2x] = %d bytes @ %d\n", i, pats[i].ctx, pats[i].bs, pats[i].bw); @@ -154,7 +154,7 @@ bool Compressor::Compress(CompressionParameters* params, void* in, int inLen, vo g[j].fitness = *outLen; CompressSingle(&g[j].params, in, inLen, out, &g[j].fitness); } - qsort(g, GENOME_SIZE, sizeof(Genome), (__compar_fn_t)CompareGenome); + qsort(g, GENOME_SIZE, sizeof(Genome), (int (*)(const void*, const void*))CompareGenome); for (int j = 0; j < GENOME_SIZE; ++j) { if (j >= 3) break; printf("I[%3d,%d]: %d", i, j, g[j].fitness); @@ -189,7 +189,7 @@ bool Compressor::Compress(CompressionParameters* params, void* in, int inLen, vo trg2[k >> 1] = src2[k >> 1]; } } - qsort(g, GENOME_SIZE / 2, sizeof(Genome), (__compar_fn_t)CompareGenome); + qsort(g, GENOME_SIZE / 2, sizeof(Genome), (int (*)(const void*, const void*))CompareGenome); for (int j = 1; j < GENOME_SIZE / 2; ++j) { if (!memcmp(g[j].params.weights, g[j - 1].params.weights, CONTEXT_COUNT) && !memcmp(g[j].params.contexts, g[j - 1].params.contexts, CONTEXT_COUNT)) { int byte = rand() % (2 * CONTEXT_COUNT); diff --git a/unpack.cpp b/unpack.cpp index 1a29246..914d290 100644 --- a/unpack.cpp +++ b/unpack.cpp @@ -16,73 +16,12 @@ #include "pack.h" -#include +#include "elfling_unpack.hpp" + #include void Compressor::Decompress(CompressionParameters* params, void* in, void* out, int outLen) { - u8* counters[MAX_CONTEXT_COUNT]; // Counter base offsets - u8* cp[MAX_CONTEXT_COUNT]; // Current counters - u8* archive = (u8*)in; - u8* cout = (u8*)out; - memset(modelCounters_, 0, MAX_CONTEXT_SIZE * params->contextCount); - u8* base = modelCounters_; - for (int m = 0; m < params->contextCount; ++m) { - counters[m] = base; - cp[m] = base; - base += MAX_CONTEXT_SIZE; - } - - *cout = 1; - u32 x1 = 0, x2 = 0xffffffff; - for (u32 j = outLen * 8; j > 0; --j) { - u32 n0 = 1, n1 = 1; - for (char m = 0; m < params->contextCount; ++m) { - n0 += cp[m][0] * params->weights[m]; - n1 += cp[m][1] * params->weights[m]; - } - - u32 xmid = x1 + n0 * (u64)(x2 - x1) / (n0 + n1); - - char y; - cout[0] <<= 1; - if (*(u32*)archive <= xmid) { - x2 = xmid; - y = 0; - } else { - cout[0] += 1; - x1 = xmid + 1; - y = 1; - } - - if (((j - 1) & 7) == 0) { // Start new byte - cout++; - *cout = 1; - } - - // Count y by context - for (char m = 0; m < params->contextCount; ++m) { - if (cp[m][y] < 255) - ++cp[m][y]; - if (cp[m][1 - y] > 2) - cp[m][1 - y] = cp[m][1 - y] / 2 + 1; - u32 off = 0, cnt = 0; - for (char i = 0; i < 8; ++i) { - if (params->contexts[m] & (1 << i)) { - off = (off << 8) + cout[-i]; - } - } - u32 c = 0; - while (*(u32*)&counters[m][c] != 0 && *(u32*)&counters[m][c] != off) c += 6; - *(u32*)&counters[m][c] = off; - cp[m] = &counters[m][c + 4]; - } - - while (((x1 ^ x2) >> 24) == 0) { - x1 <<= 8; - x2 = (x2 << 8) + 255; - --archive; - } - } + elfling_unpack(params->weights, params->contexts, params->contextCount, modelCounters_, in, out, outLen); }