#include "Entropy.h" #ifndef COMPRESS2 struct Recode { byte m; byte h1, h2, h3; byte l1, h1l2, h2l3; byte filler; }; String Compress(const char *data, const char *end) { int stat[256] = { 0 }; { RTIMESTOP("Stat"); for(const char *s = data; s < end; s++) stat[(byte)*s]++; } for(int i = 0; i < 256; i++) { LOG(FChar(i) << " " << stat[i]); } LOG("======================"); // 0000 - 1011 most frequent 12 // 1100 0000 - 1110 1111 average 48 // 1111 0000 0000 - 1111 1111 1111 rest byte ndx[256]; for(int i = 0; i < 256; i++) ndx[i] = i; IndexSort(stat, stat + 256, ndx, StdGreater()); for(int m = 1; m < 15; m++) { int mini = 0; int big = 0; for(int i = 0; i < 256; i++) { if(i < m) mini += stat[i]; if(i >= (15 - m) * 16) big += stat[i]; // LOG(FChar(ndx[i]) << " " << stat[i]); } LOG("==== " << m << ":" << (15 - m) * 16 << " ==="); DUMP(mini); DUMP(big); DUMP((mini - big) / 2); LOG("--------------------"); } int mini = 0; int big = 0; for(int i = 0; i < 256; i++) { if(i < 12) mini += stat[i]; if(i >= 12 + 48) big += stat[i]; LOG(FChar(ndx[i]) << " " << stat[i]); } DUMP(mini); DUMP(big); DUMP((mini - big) / 2); LOG("--------------------"); Recode recode[256]; Buffer output(3 * (end - data) / 2 + 10000); byte *t = ~output; *t++ = 1; Poke32le(t, (end - data)); t += 4; for(int i = 0; i < 256; i++) { int c = ndx[i]; LOG(i << ": " << FChar(c)); Recode& r = recode[c]; if(i < 12 + 48) { *t++ = c; if(i < 12) { r.m = 1; r.h1 = i << 4; r.h2 = 0; r.h3 = 0; r.l1 = i; // r.l2 = 0; // r.l3 = 0; } else { int q = i + 0xc0; r.m = 2; r.h1 = q & 0xf0; r.h2 = (q << 4) & 0xf0; r.h3 = 0; r.l1 = (q >> 4) & 0x0f; r.h1l2 = r.h1 | (q & 0x0f); // r.l3 = 0; } } else { r.m = 3; r.h1 = 0xf0; r.h2 = 0xf0 & i; r.h3 = 0xf0 & (i << 4); r.l1 = 0x0f; // r.l2 = 0x0f & (i >> 4); r.h2l3 = r.h2 | (0x0f & i); } } NibblePtr p; p.Set(t); { RTIMESTOP("Compress"); const char *s = data; byte g = 0; for(;;) { nibble0: { if(s >= end) break; Recode& r = recode[(byte)*s++]; if(r.m == 1) { g = r.h1; goto nibble1; } if(r.m == 2) { *t++ = r.h1l2; goto nibble0; } *t++ = r.h1l2; g = r.h3; goto nibble1; } nibble1: { if(s >= end) break; Recode& r = recode[(byte)*s++]; if(r.m == 1) { *t++ = g | r.l1; goto nibble0; } if(r.m == 2) { *t++ = g | r.l1; g = r.h2; goto nibble1; } *t++ = g | r.l1; *t++ = r.h2l3; goto nibble0; } } } return String(~output, t - ~output + 1); } #endif