## diffname port/thwack.c 1999/1001
## diff -e /dev/null /n/emeliedump/1999/1001/sys/src/brazil/port/thwack.c
0a
#include "u.h"
#include "../port/lib.h"
#include "mem.h"
#include "dat.h"
#include "fns.h"
#include "thwack.h"
typedef struct Huff Huff;
struct Huff
{
short bits; /* length of the code */
ulong encode; /* the code */
};
static Huff lentab[MaxLen] =
{
{1, 0x0}, /* 0 */
{2, 0x2}, /* 10 */
{4, 0xc}, /* 1100 */
{4, 0xd}, /* 1101 */
{5, 0x1e}, /* 11110 */
{6, 0x3e}, /* 111110 */
{6, 0x3f}, /* 111111 */
{4, 0xe}, /* 1110 */
};
static void bitput(Thwack *tw, int c, int n);
static int iomegaput(Thwack *tw, ulong v);
void
thwackinit(Thwack *tw)
{
int i;
memset(tw, 0, sizeof *tw);
for(i = 0; i < EWinBlocks; i++){
tw->blocks[i].data = tw->data[i];
tw->blocks[i].edata = tw->blocks[i].data;
tw->blocks[i].hash = tw->hash[i];
tw->blocks[i].acked = 0;
}
}
/*
* acknowledgement for block seq & nearby preds
*/
void
thwackack(Thwack *tw, ulong seq, ulong mask)
{
int slot, b;
slot = tw->slot;
for(;;){
for(;;){
slot--;
if(slot < 0)
slot += EWinBlocks;
if(slot == tw->slot)
return;
if(tw->blocks[slot].seq == seq){
tw->blocks[slot].acked = 1;
break;
}
}
if(mask == 0)
break;
do{
b = mask & 1;
seq--;
mask >>= 1;
}while(!b);
}
}
/*
* find a string in the dictionary
*/
static int
thwmatch(ThwBlock *b, ThwBlock *eblocks, uchar **ss, uchar *esrc, ulong h)
{
int then, toff, w;
uchar *s, *t;
s = *ss;
if(esrc < s + MinMatch)
return 0;
toff = 0;
for(; b < eblocks; b++){
then = b->hash[h];
toff += b->maxoff;
w = (ushort)(then - b->begin);
if(w >= b->maxoff)
continue;
/*
* don't need to check for the end because
* 1) s too close check above
* 2) entries too close not added to hash tables
*/
t = w + b->data;
if(s[0] != t[0] || s[1] != t[1] || s[2] != t[2])
continue;
if(esrc - s > b->edata - t)
esrc = s + (b->edata - t);
t += 3;
for(s += 3; s < esrc; s++){
if(*s != *t)
break;
t++;
}
*ss = s;
return toff - w;
}
return 0;
}
/*
* knuth vol. 3 multiplicative hashing
* each byte x chosen according to rules
* 1/4 < x < 3/10, 1/3 x < < 3/7, 4/7 < x < 2/3, 7/10 < x < 3/4
* with reasonable spread between the bytes & their complements
*
* the 3 byte value appears to be as almost good as the 4 byte value,
* and might be faster on some machines
*/
//#define hashit(c) (((((ulong)(c) & 0xffffff) * 0x6b43a9b5) >> (32 - HashLog)) & HashMask)
#define hashit(c) ((((ulong)(c) * 0x6b43a9) >> (24 - HashLog)) & HashMask)
/*
* lz77 compression with single lookup in a hash table for each block
*/
int
thwack(Thwack *tw, uchar *dst, uchar *src, int n, ulong seq)
{
ThwBlock *eblocks, *b, blocks[CompBlocks];
uchar *s, *ss, *sss, *esrc, *half;
ulong cont, cseq, bseq, cmask;
int now, toff;
int h, m, slot, bits, totmatched;
if(n > ThwMaxBlock || n < MinMatch || waserror())
return -1;
tw->dst = dst;
tw->dmax = dst + n;
tw->nbits = 0;
/*
* add source to the coding window
* there is always enough space
*/
slot = tw->slot;
b = &tw->blocks[slot];
b->seq = seq;
b->acked = 0;
now = b->begin + b->maxoff;
s = b->data;
memmove(s, src, n);
b->edata = s + n;
b->begin = now;
b->maxoff = n;
/*
* set up the history blocks
*/
cseq = seq;
cmask = 0;
*blocks = *b;
b = blocks;
b->maxoff = 0;
b++;
while(b < blocks + CompBlocks){
slot--;
if(slot < 0)
slot += EWinBlocks;
if(slot == tw->slot)
break;
if(!tw->blocks[slot].acked)
continue;
bseq = tw->blocks[slot].seq;
if(cseq == seq){
if(seq - bseq >= MaxSeqStart)
break;
cseq = bseq;
}else if(cseq - bseq > MaxSeqMask)
break;
else
cmask |= 1 << (cseq - bseq - 1);
*b = tw->blocks[slot];
b++;
}
eblocks = b;
bitput(tw, ((seq - cseq) << MaxSeqMask) | cmask, 16);
cont = (s[0] << 16) | (s[2] << 8) | s[2];
totmatched = 0;
esrc = s + n;
half = s + (n >> 1);
while(s < esrc){
h = hashit(cont);
sss = s;
toff = thwmatch(blocks, eblocks, &sss, esrc, h);
ss = sss;
m = ss - s;
if(m < MinMatch){
bitput(tw, 0x100|*s, 9);
ss = s + 1;
}else{
totmatched += m;
toff--;
for(bits = OffBase; toff >= (1 << bits); bits++)
;
if(bits >= MaxOff+OffBase)
error("thwack offset");
bitput(tw, bits - OffBase, 4);
if(bits != OffBase)
bits--;
bitput(tw, toff & ((1 << bits) - 1), bits);
m -= MinMatch;
if(m < MaxLen-1){
bitput(tw, lentab[m].encode, lentab[m].bits);
}else{
bitput(tw, lentab[MaxLen-1].encode, lentab[MaxLen-1].bits);
iomegaput(tw, m - (MaxLen - 2));
}
}
blocks->maxoff += ss - s;
/*
* speed hack
* check for compression progress, bail if none achieved
*/
if(s < half && ss >= half && totmatched * 10 < n)
error("thwack likely expanding");
for(; s != ss; s++){
if(s + MinMatch <= esrc){
h = hashit(cont);
blocks->hash[h] = now;
if(s + MinMatch < esrc)
cont = (cont << 8) | s[MinMatch];
}
now++;
}
}
if(tw->nbits)
bitput(tw, 0, 8 - tw->nbits);
tw->slot++;
if(tw->slot >= EWinBlocks)
tw->slot = 0;
poperror();
return tw->dst - dst;
}
static void
bitput(Thwack *tw, int c, int n)
{
tw->bits = (tw->bits << n) | c;
for(tw->nbits += n; tw->nbits >= 8; tw->nbits -= 8){
if(tw->dst >= tw->dmax)
error("thwack expanding");
*tw->dst++ = tw->bits >> (tw->nbits - 8);
}
}
/*
* elias's omega code, modified
* for at least 3 bit transmission
*/
static Huff omegatab[16] =
{
{0, 0}, /* 1 */
{0, 0},
{0, 0},
{0, 0},
{3, 0x4}, /* 5 */
{3, 0x5},
{3, 0x6},
{3, 0x7},
{7, 0x48},
{7, 0x49}, /* 10 */
{7, 0x4a},
{7, 0x4b},
{7, 0x4c},
{7, 0x4d},
{7, 0x4e}, /* 15 */
{7, 0x4f},
};
static int
iomegaput(Thwack *tw, ulong v)
{
int b, bb;
v--;
if(v < 4){
bitput(tw, v, 3);
return 3;
}
if(v < 16){
b = omegatab[v].bits + 1;
bitput(tw, omegatab[v].encode << 1, b);
return b;
}
for(bb = 5; v >= (1 << bb); bb++)
;
if(bb >= 16)
error("thwack omegaput");
b = bb + omegatab[bb].bits + 1;
bitput(tw, (omegatab[bb].encode << (bb + 1)) | (v << 1), b);
return b;
}
.
## diffname port/thwack.c 1999/1007
## diff -e /n/emeliedump/1999/1001/sys/src/brazil/port/thwack.c /n/emeliedump/1999/1007/sys/src/brazil/port/thwack.c
276,324d
233,234c
code = BigLenCode;
bits = BigLenBits;
use = BigLenBase;
m -= MaxFastLen;
while(m >= use){
m -= use;
code = (code + use) << 1;
use <<= bits & 1;
bits++;
}
bitput(tw, (code + m), bits);
.
230c
if(m < MaxFastLen){
.
144c
int h, m, slot, bits, use, totmatched;
.
142c
ulong cont, cseq, bseq, cmask, code;
.
22,25c
{5, 0x1c}, /* 11100 */
{6, 0x3a}, /* 111010 */
{6, 0x3b}, /* 111011 */
{7, 0x78}, /* 1111000 */
{7, 0x79}, /* 1111001 */
.
16c
static Huff lentab[MaxFastLen] =
.
2c
#include "lib.h"
.
## diffname port/thwack.c 1999/1022
## diff -e /n/emeliedump/1999/1007/sys/src/brazil/port/thwack.c /n/emeliedump/1999/1022/sys/src/brazil/port/thwack.c
277,285c
return twdst - dst;
.
273,275c
stats[StatOutBytes] += twdst - dst;
.
267,268c
stats[StatBytes] += blocks->maxoff;
stats[StatLits] += lits;
stats[StatMatches] += matches;
stats[StatLitBits] += (twdst - (dst + 2)) * 8 + twnbits - offbits - lenbits;
stats[StatOffBits] += offbits;
stats[StatLenBits] += lenbits;
if(twnbits & 7){
twbits <<= 8 - (twnbits & 7);
twnbits += 8 - (twnbits & 7);
}
for(; twnbits >= 8; twnbits -= 8){
if(twdst >= twdmax)
return -1;
*twdst++ = twbits >> (twnbits - 8);
}
.
259c
blocks->hash[(h ^ blocks->seq) & HashMask] = now;
.
255a
toff--;
for(bits = OffBase; toff >= (1 << bits); bits++)
;
if(bits >= MaxOff+OffBase)
panic("thwack offset");
twbits = (twbits << 4) | 0x8 | (bits - OffBase);
if(bits != OffBase)
bits--;
twbits = (twbits << bits) | toff & ((1 << bits) - 1);
twnbits += bits + 4;
offbits += bits + 4;
len -= MinMatch;
if(len < MaxFastLen){
bits = lentab[len].bits;
twbits = (twbits << bits) | lentab[len].encode;
twnbits += bits;
lenbits += bits;
}else{
for(; twnbits >= 8; twnbits -= 8){
if(twdst >= twdmax)
return -1;
*twdst++ = twbits >> (twnbits - 8);
}
code = BigLenCode;
bits = BigLenBits;
use = BigLenBase;
len -= MaxFastLen;
while(len >= use){
len -= use;
code = (code + use) << 1;
use <<= bits & 1;
bits++;
}
if(bits > MaxLenDecode + BigLenBits)
panic("length too big");
twbits = (twbits << bits) | (code + len);
twnbits += bits;
lenbits += bits;
}
.
249,254c
blocks->maxoff += len;
matches++;
.
247d
245a
now++;
s++;
continue;
.
230,244c
if(s + MinMatch <= esrc){
blocks->hash[(h ^ blocks->seq) & HashMask] = now;
if(s + MinMatch < esrc)
cont = (cont << 8) | s[MinMatch];
.
220,228c
/*
* speed hack
* check for compression progress, bail if none achieved
*/
if(s > half){
if(4 * blocks->maxoff < 5 * lits)
return -1;
half = esrc;
}
.
213,218c
len = ss - s;
for(; twnbits >= 8; twnbits -= 8){
if(twdst >= twdmax)
return -1;
*twdst++ = twbits >> (twnbits - 8);
}
if(len < MinMatch){
toff = *s;
lithist = (lithist << 1) | toff < 32 | toff > 127;
if(lithist & 0x1e){
twbits = (twbits << 9) | toff;
twnbits += 9;
}else if(lithist & 1){
toff = (toff + 64) & 0xff;
if(toff < 96){
twbits = (twbits << 10) | toff;
twnbits += 10;
}else{
twbits = (twbits << 11) | toff;
twnbits += 11;
}
}else{
twbits = (twbits << 8) | toff;
twnbits += 8;
}
lits++;
blocks->maxoff++;
.
205a
twnbits = 0;
twbits = 0;
lits = 0;
matches = 0;
offbits = 0;
lenbits = 0;
lithist = ~0;
.
203d
201c
cont = (s[0] << 16) | (s[1] << 8) | s[2];
.
199c
*twdst++ = seq - cseq;
*twdst++ = cmask;
.
150,152c
twdst = dst;
twdmax = dst + n;
.
147c
if(n > ThwMaxBlock || n < MinMatch)
.
142,145c
uchar *s, *ss, *sss, *esrc, *half, *twdst, *twdmax;
ulong cont, cseq, bseq, cmask, code, twbits;
int now, toff, lithist, h, len, slot, bits, use, twnbits, lits, matches, offbits, lenbits;
.
139c
thwack(Thwack *tw, uchar *dst, uchar *src, int n, ulong seq, ulong stats[ThwStats])
.
132,133c
/*
#define hashit(c) (((ulong)(c) * 0x6b43a9) >> (24 - HashLog))
*/
#define hashit(c) ((((ulong)(c) & 0xffffff) * 0x6b43a9b5) >> (32 - HashLog))
.
108,109c
ok = b->edata - t;
if(esrc - s > ok)
esrc = s + ok;
.
99a
.
93c
then = b->hash[(h ^ b->seq) & HashMask];
.
84c
int then, toff, w, ok;
.
29,31d
9a
enum
{
StatBytes,
StatOutBytes,
StatLits,
StatMatches,
StatLitBits,
StatOffBits,
StatLenBits,
StatProbe,
StatProbeMiss,
MaxStat
};
.
2c
#include "../port/lib.h"
.
## diffname port/thwack.c 1999/1111
## diff -e /n/emeliedump/1999/1022/sys/src/brazil/port/thwack.c /n/emeliedump/1999/1111/sys/src/9/port/thwack.c
358a
#endif
.
355a
#ifdef NOUNCOMP
.
327a
/*
* offset in history
*/
toff--;
for(bits = OffBase; toff >= (1 << bits); bits++)
;
if(bits < MaxOff+OffBase-1){
twbits = (twbits << 3) | (bits - OffBase);
if(bits != OffBase)
bits--;
twnbits += bits + 3;
offbits += bits + 3;
}else{
twbits = (twbits << 4) | 0xe | (bits - (MaxOff+OffBase-1));
bits--;
twnbits += bits + 4;
offbits += bits + 4;
}
twbits = (twbits << bits) | toff & ((1 << bits) - 1);
.
325a
for(; twnbits >= 8; twnbits -= 8){
if(twdst >= twdmax)
return -1;
*twdst++ = twbits >> (twnbits - 8);
}
.
321,322d
318c
use <<= (bits & 1) ^ 1;
.
306,310d
287,298c
/*
* length of match
*/
.
272a
#endif
.
263a
#ifdef NOUNCOMP
.
217a
#ifndef NOUNCOMP
tw->slot++;
if(tw->slot >= EWinBlocks)
tw->slot = 0;
#endif
.
40,43c
{5, 0x1d}, /* 11101 */
{6, 0x3c}, /* 111100 */
{7, 0x7a}, /* 1111010 */
{7, 0x7b}, /* 1111011 */
{8, 0xf8}, /* 11111000 */
{8, 0xf9}, /* 11111001 */
.
37,38c
{3, 0x6}, /* 110 */
.
35d
12a
MaxFastLen = 9,
BigLenCode = 0x1f4, /* minimum code for large lenth encoding */
BigLenBits = 9,
BigLenBase = 4 /* starting items to encode for big lens */
};
enum
{
.
8a
/*
* don't include compressed blocks
*/
#define NOUNCOMP
.
2c
#include "lib.h"
.
## diffname port/thwack.c 1999/1116
## diff -e /n/emeliedump/1999/1111/sys/src/9/port/thwack.c /n/emeliedump/1999/1116/sys/src/9/port/thwack.c
391d
387d
375a
stats[StatDelay] = stats[StatDelay]*7/8 + dst[0];
stats[StatHist] = stats[StatHist]*7/8 + nhist;
.
373d
293d
283d
231,236d
224a
nhist += b->maxoff;
.
206a
nhist = 0;
.
175c
int now, toff, lithist, h, len, slot, bits, use, twnbits, lits, matches, offbits, lenbits, nhist;
.
34,35c
StatDelay,
StatHist,
.
30d
9,13d
## diffname port/thwack.c 2001/0609
## diff -e /n/emeliedump/1999/1116/sys/src/9/port/thwack.c /n/emeliedump/2001/0609/sys/src/9/port/thwack.c
379a
stats[StatBytes] += blocks->maxoff;
stats[StatLits] += lits;
stats[StatMatches] += matches;
stats[StatOffBits] += offbits;
stats[StatLenBits] += lenbits;
stats[StatDelay] = stats[StatDelay]*7/8 + dst[0];
stats[StatHist] = stats[StatHist]*7/8 + nhist;
.
358,364d
253c
lithist = (lithist << 1) | (toff < 32) | (toff > 127);
.
88a
tw->blocks[slot].acked = 1;
.
77,87c
slot--;
if(slot < 0)
slot += EWinBlocks;
if(slot == tw->slot)
break;
if(tw->blocks[slot].seq != seq)
continue;
.
|