1 /* lzo_swd.ch -- sliding window dictionary
3 This file is part of the LZO real-time data compression library.
5 Copyright (C) 2011 Markus Franz Xaver Johannes Oberhumer
6 Copyright (C) 2010 Markus Franz Xaver Johannes Oberhumer
7 Copyright (C) 2009 Markus Franz Xaver Johannes Oberhumer
8 Copyright (C) 2008 Markus Franz Xaver Johannes Oberhumer
9 Copyright (C) 2007 Markus Franz Xaver Johannes Oberhumer
10 Copyright (C) 2006 Markus Franz Xaver Johannes Oberhumer
11 Copyright (C) 2005 Markus Franz Xaver Johannes Oberhumer
12 Copyright (C) 2004 Markus Franz Xaver Johannes Oberhumer
13 Copyright (C) 2003 Markus Franz Xaver Johannes Oberhumer
14 Copyright (C) 2002 Markus Franz Xaver Johannes Oberhumer
15 Copyright (C) 2001 Markus Franz Xaver Johannes Oberhumer
16 Copyright (C) 2000 Markus Franz Xaver Johannes Oberhumer
17 Copyright (C) 1999 Markus Franz Xaver Johannes Oberhumer
18 Copyright (C) 1998 Markus Franz Xaver Johannes Oberhumer
19 Copyright (C) 1997 Markus Franz Xaver Johannes Oberhumer
20 Copyright (C) 1996 Markus Franz Xaver Johannes Oberhumer
23 The LZO library is free software; you can redistribute it and/or
24 modify it under the terms of the GNU General Public License as
25 published by the Free Software Foundation; either version 2 of
26 the License, or (at your option) any later version.
28 The LZO library is distributed in the hope that it will be useful,
29 but WITHOUT ANY WARRANTY; without even the implied warranty of
30 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
31 GNU General Public License for more details.
33 You should have received a copy of the GNU General Public License
34 along with the LZO library; see the file COPYING.
35 If not, write to the Free Software Foundation, Inc.,
36 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
38 Markus F.X.J. Oberhumer
39 <markus@oberhumer.com>
40 http://www.oberhumer.com/opensource/lzo/
44 #if (LZO_UINT_MAX < LZO_0xffffffffL)
45 # error "LZO_UINT_MAX"
47 #if defined(LZO_DEBUG)
50 #if defined(__LZO_CHECKER)
55 /***********************************************************************
57 ************************************************************************/
59 /* unsigned type for dictionary access - don't waste memory here */
60 #if (0UL + SWD_N + SWD_F + SWD_F < 0UL + USHRT_MAX)
61 typedef unsigned short swd_uint;
62 # define SWD_UINT_MAX USHRT_MAX
63 #elif (0UL + SWD_N + SWD_F + SWD_F < 0UL + UINT_MAX)
64 typedef unsigned swd_uint;
65 # define SWD_UINT_MAX UINT_MAX
67 typedef lzo_uint swd_uint;
68 # define SWD_UINT_MAX LZO_UINT_MAX
70 #define swd_uintp swd_uint __LZO_MMODEL *
71 #define SWD_UINT(x) ((swd_uint)(x))
75 # define SWD_HSIZE 16384
78 # define SWD_MAX_CHAIN 2048
84 ((DMUL(0x9f5f,(((((lzo_xint)b[p]<<5)^b[p+1])<<5)^b[p+2]))>>5) & (SWD_HSIZE-1))
87 ((DMUL(0x9f5f,(((((lzo_xint)b[p+2]<<5)^b[p+1])<<5)^b[p]))>>5) & (SWD_HSIZE-1))
91 #if !(SWD_NO_HEAD2) && (SWD_THRESHOLD == 1) && !defined(HEAD2)
92 # if 1 && defined(LZO_UNALIGNED_OK_2)
93 # define HEAD2(b,p) UA_GET16((b)+(p))
95 # define HEAD2(b,p) (b[p] ^ ((unsigned)b[p+1]<<8))
97 # define NIL2 SWD_UINT_MAX
100 #define IF_HEAD2(s) /*empty*/
106 /* public - "built-in" */
109 lzo_uint swd_threshold;
111 /* public - configuration */
113 lzo_uint nice_length;
114 lzo_bool use_best_off;
115 lzo_uint lazy_insert;
117 /* public - output */
122 #if defined(SWD_BEST_OFF)
123 lzo_uint best_off[ SWD_BEST_OFF ];
129 #if defined(SWD_BEST_OFF)
130 lzo_uint best_pos[ SWD_BEST_OFF ];
134 const lzo_bytep dict;
135 const lzo_bytep dict_end;
139 lzo_uint ip; /* input pointer (lookahead) */
140 lzo_uint bp; /* buffer pointer */
141 lzo_uint rp; /* remove pointer */
149 #if defined(__LZO_MMODEL_HUGE)
150 # define A(type, n) ((((n) * sizeof(type)) + 3UL) &~ 3UL)
153 # define O_head3(s) (O_b(s) + A(char, 0UL + SWD_N + SWD_F + SWD_F))
154 # define O_succ3(s) (O_head3(s) + A(swd_uint, 0UL + SWD_HSIZE))
155 # define O_best3(s) (O_succ3(s) + A(swd_uint, 0UL + SWD_N + SWD_F))
156 # define O_llen3(s) (O_best3(s) + A(swd_uint, 0UL + SWD_N + SWD_F))
158 # define O_head2(s) (O_llen3(s) + A(swd_uint, 0UL + SWD_HSIZE))
159 # define O_END(s) (O_head2(s) + A(swd_uint, 0UL + 65536L))
161 # define O_END(s) (O_llen3(s) + A(swd_uint, 0UL + SWD_HSIZE))
164 # define S_DEF(s,type,off) ((type) ((lzo_bytep)s + 0L + sizeof(*s) + off))
165 # define s_b(s) S_DEF(s, lzo_bytep, O_b(s))
166 # define s_head3(s) S_DEF(s, swd_uintp, O_head3(s))
167 # define s_succ3(s) S_DEF(s, swd_uintp, O_succ3(s))
168 # define s_best3(s) S_DEF(s, swd_uintp, O_best3(s))
169 # define s_llen3(s) S_DEF(s, swd_uintp, O_llen3(s))
171 # define s_head2(s) S_DEF(s, swd_uintp, O_head2(s))
174 #elif defined(__LZO_CHECKER)
175 /* malloc arrays of the exact size to detect any overrun */
186 unsigned char b [ SWD_N + SWD_F + SWD_F ];
187 swd_uint head3 [ SWD_HSIZE ];
188 swd_uint succ3 [ SWD_N + SWD_F ];
189 swd_uint best3 [ SWD_N + SWD_F ];
190 swd_uint llen3 [ SWD_HSIZE ];
192 swd_uint head2 [ 65536L ];
197 #define lzo_swd_p lzo_swd_t __LZO_MMODEL *
200 #if defined(__LZO_MMODEL_HUGE)
201 #define SIZEOF_LZO_SWD_T O_END(0)
204 #define s_head3(s) s->head3
205 #define s_succ3(s) s->succ3
206 #define s_best3(s) s->best3
207 #define s_llen3(s) s->llen3
209 #define s_head2(s) s->head2
211 #define SIZEOF_LZO_SWD_T (sizeof(lzo_swd_t))
215 /* Access macro for head3.
216 * head3[key] may be uninitialized if the list is emtpy,
217 * but then its value will never be used.
219 #if defined(__LZO_CHECKER)
220 # define s_get_head3(s,key) \
221 ((s_llen3(s)[key] == 0) ? SWD_UINT_MAX : s_head3(s)[key])
223 # define s_get_head3(s,key) s_head3(s)[key]
227 /***********************************************************************
229 ************************************************************************/
232 void swd_initdict(lzo_swd_p s, const lzo_bytep dict, lzo_uint dict_len)
234 s->dict = s->dict_end = NULL;
237 if (!dict || dict_len == 0)
239 if (dict_len > s->swd_n)
241 dict += dict_len - s->swd_n;
246 s->dict_len = dict_len;
247 s->dict_end = dict + dict_len;
248 lzo_memcpy(s_b(s),dict,dict_len);
254 void swd_insertdict(lzo_swd_p s, lzo_uint node, lzo_uint len)
258 s->node_count = s->swd_n - len;
263 key = HEAD3(s_b(s),node);
264 s_succ3(s)[node] = s_get_head3(s,key);
265 s_head3(s)[key] = SWD_UINT(node);
266 s_best3(s)[node] = SWD_UINT(s->swd_f + 1);
268 assert(s_llen3(s)[key] <= s->swd_n);
272 key = HEAD2(s_b(s),node);
273 s_head2(s)[key] = SWD_UINT(node);
283 /***********************************************************************
285 ************************************************************************/
288 int swd_init(lzo_swd_p s, const lzo_bytep dict, lzo_uint dict_len)
290 #if defined(__LZO_CHECKER)
291 s->b = (lzo_bytep) malloc(SWD_N + SWD_F + SWD_F);
292 s->head3 = (swd_uintp) malloc(sizeof(swd_uint) * SWD_HSIZE);
293 s->succ3 = (swd_uintp) malloc(sizeof(swd_uint) * (SWD_N + SWD_F));
294 s->best3 = (swd_uintp) malloc(sizeof(swd_uint) * (SWD_N + SWD_F));
295 s->llen3 = (swd_uintp) malloc(sizeof(swd_uint) * SWD_HSIZE);
298 s->head2 = (swd_uintp) malloc(sizeof(swd_uint) * 65536L);
305 #if defined(SWD_BEST_OFF)
308 for (i = 0; i < SWD_BEST_OFF; i++)
309 s->best_off[i] = s->best_pos[i] = 0;
315 s->swd_threshold = SWD_THRESHOLD;
318 s->max_chain = SWD_MAX_CHAIN;
319 s->nice_length = s->swd_f;
323 s->b_size = s->swd_n + s->swd_f;
325 if (2 * s->swd_f >= s->swd_n || s->b_size + s->swd_f >= SWD_UINT_MAX)
328 LZO_COMPILE_TIME_ASSERT(!(0ul + 2 * SWD_F >= SWD_N))
329 LZO_COMPILE_TIME_ASSERT(!(0ul + SWD_N + SWD_F + SWD_F >= SWD_UINT_MAX))
331 s->b_wrap = s_b(s) + s->b_size;
332 s->node_count = s->swd_n;
334 lzo_memset(s_llen3(s), 0, (lzo_uint)sizeof(s_llen3(s)[0]) * (lzo_uint)SWD_HSIZE);
338 lzo_memset(s_head2(s), 0xff, (lzo_uint)sizeof(s_head2(s)[0]) * 65536L);
339 assert(s_head2(s)[0] == NIL2);
342 for (i = 0; i < 65536L; i++)
343 s_head2(s)[i] = NIL2;
349 swd_initdict(s,dict,dict_len);
353 assert(s->ip + s->swd_f <= s->b_size);
355 s->look = (lzo_uint) (s->c->in_end - s->c->ip);
358 if (s->look > s->swd_f)
360 lzo_memcpy(&s_b(s)[s->ip],s->c->ip,s->look);
366 while (s->look < s->swd_f)
369 if ((c = getbyte(*(s->c))) < 0)
371 s_b(s)[s->ip] = LZO_BYTE(c);
376 if (s->ip == s->b_size)
379 if (s->look >= 2 && s->dict_len > 0)
380 swd_insertdict(s,0,s->dict_len);
383 if (s->rp >= s->node_count)
384 s->rp -= s->node_count;
386 s->rp += s->b_size - s->node_count;
388 #if 1 || defined(__LZO_CHECKER)
389 /* initialize memory for the first few HEAD3 (if s->ip is not far
390 * enough ahead to do this job for us). The value doesn't matter. */
392 lzo_bytep p = &s_b(s)[s->bp+s->look];
393 p[0] = p[1] = p[2] = 0;
402 void swd_exit(lzo_swd_p s)
404 #if defined(__LZO_CHECKER)
405 /* free in reverse order of allocations */
407 free(s->head2); s->head2 = NULL;
409 free(s->llen3); s->llen3 = NULL;
410 free(s->best3); s->best3 = NULL;
411 free(s->succ3); s->succ3 = NULL;
412 free(s->head3); s->head3 = NULL;
413 free(s->b); s->b = NULL;
420 #define swd_pos2off(s,pos) \
421 (s->bp > (pos) ? s->bp - (pos) : s->b_size - ((pos) - s->bp))
424 /***********************************************************************
426 ************************************************************************/
429 void swd_getbyte(lzo_swd_p s)
433 if ((c = getbyte(*(s->c))) < 0)
437 #if defined(__LZO_CHECKER)
438 /* initialize memory - value doesn't matter */
440 if (s->ip < s->swd_f)
441 s->b_wrap[s->ip] = 0;
446 s_b(s)[s->ip] = LZO_BYTE(c);
447 if (s->ip < s->swd_f)
448 s->b_wrap[s->ip] = LZO_BYTE(c);
450 if (++s->ip == s->b_size)
452 if (++s->bp == s->b_size)
454 if (++s->rp == s->b_size)
459 /***********************************************************************
460 // remove node from lists
461 ************************************************************************/
464 void swd_remove_node(lzo_swd_p s, lzo_uint node)
466 if (s->node_count == 0)
471 if (s->first_rp != LZO_UINT_MAX)
473 if (node != s->first_rp)
474 printf("Remove %5ld: %5ld %5ld %5ld %5ld %6ld %6ld\n",
475 (long)node, (long)s->rp, (long)s->ip, (long)s->bp,
476 (long)s->first_rp, (long)(s->ip - node),
477 (long)(s->ip - s->bp));
478 assert(node == s->first_rp);
479 s->first_rp = LZO_UINT_MAX;
483 key = HEAD3(s_b(s),node);
484 assert(s_llen3(s)[key] > 0);
489 key = HEAD2(s_b(s),node);
490 assert(s_head2(s)[key] != NIL2);
491 if ((lzo_uint) s_head2(s)[key] == node)
492 s_head2(s)[key] = NIL2;
501 /***********************************************************************
503 ************************************************************************/
506 void swd_accept(lzo_swd_p s, lzo_uint n)
508 assert(n <= s->look);
514 swd_remove_node(s,s->rp);
516 /* add bp into HEAD3 */
517 key = HEAD3(s_b(s),s->bp);
518 s_succ3(s)[s->bp] = s_get_head3(s,key);
519 s_head3(s)[key] = SWD_UINT(s->bp);
520 s_best3(s)[s->bp] = SWD_UINT(s->swd_f + 1);
522 assert(s_llen3(s)[key] <= s->swd_n);
525 /* add bp into HEAD2 */
527 key = HEAD2(s_b(s),s->bp);
528 s_head2(s)[key] = SWD_UINT(s->bp);
537 /***********************************************************************
539 ************************************************************************/
542 void swd_search(lzo_swd_p s, lzo_uint node, lzo_uint cnt)
547 lzo_uint m_len = s->m_len;
548 const lzo_bytep b = s_b(s);
549 const lzo_bytep bp = s_b(s) + s->bp;
550 const lzo_bytep bx = s_b(s) + s->bp + s->look;
551 unsigned char scan_end1;
553 assert(s->m_len > 0);
555 scan_end1 = bp[m_len - 1];
556 for ( ; cnt-- > 0; node = s_succ3(s)[node])
562 assert(m_len < s->look);
566 p2[m_len - 1] == scan_end1 &&
567 p2[m_len] == p1[m_len] &&
573 assert(lzo_memcmp(bp,&b[node],3) == 0);
575 #if 0 && defined(LZO_UNALIGNED_OK_4)
577 while (p1 + 4 <= px && UA_GET32(p1) == UA_GET32(p2))
579 while (p1 < px && *p1 == *p2)
583 do {} while (++p1 < px && *p1 == *++p2);
588 if (lzo_memcmp(bp,&b[node],i) != 0)
589 printf("%5ld %5ld %5ld %02x/%02x %02x/%02x\n",
590 (long)s->bp, (long) node, (long) i,
591 bp[0], bp[1], b[node], b[node+1]);
593 assert(lzo_memcmp(bp,&b[node],i) == 0);
595 #if defined(SWD_BEST_OFF)
596 if (i < SWD_BEST_OFF)
598 if (s->best_pos[i] == 0)
599 s->best_pos[i] = node + 1;
604 s->m_len = m_len = i;
606 if (m_len == s->look)
608 if (m_len >= s->nice_length)
610 if (m_len > (lzo_uint) s_best3(s)[node])
612 scan_end1 = bp[m_len - 1];
619 /***********************************************************************
621 ************************************************************************/
626 lzo_bool swd_search2(lzo_swd_p s)
630 assert(s->look >= 2);
631 assert(s->m_len > 0);
633 key = s_head2(s)[ HEAD2(s_b(s),s->bp) ];
637 if (lzo_memcmp(&s_b(s)[s->bp],&s_b(s)[key],2) != 0)
638 printf("%5ld %5ld %02x/%02x %02x/%02x\n", (long)s->bp, (long)key,
639 s_b(s)[s->bp], s_b(s)[s->bp+1], s_b(s)[key], s_b(s)[key+1]);
641 assert(lzo_memcmp(&s_b(s)[s->bp],&s_b(s)[key],2) == 0);
642 #if defined(SWD_BEST_OFF)
643 if (s->best_pos[2] == 0)
644 s->best_pos[2] = key + 1;
658 /***********************************************************************
660 ************************************************************************/
663 void swd_findbest(lzo_swd_p s)
669 assert(s->m_len > 0);
671 /* get current head, add bp into HEAD3 */
672 key = HEAD3(s_b(s),s->bp);
673 node = s_succ3(s)[s->bp] = s_get_head3(s,key);
674 cnt = s_llen3(s)[key]++;
675 assert(s_llen3(s)[key] <= s->swd_n + s->swd_f);
676 if (cnt > s->max_chain && s->max_chain > 0)
678 s_head3(s)[key] = SWD_UINT(s->bp);
680 s->b_char = s_b(s)[s->bp];
682 if (s->m_len >= s->look)
687 s_best3(s)[s->bp] = SWD_UINT(s->swd_f + 1);
692 if (swd_search2(s) && s->look >= 3)
693 swd_search(s,node,cnt);
696 swd_search(s,node,cnt);
699 s->m_off = swd_pos2off(s,s->m_pos);
700 s_best3(s)[s->bp] = SWD_UINT(s->m_len);
702 #if defined(SWD_BEST_OFF)
706 for (i = 2; i < SWD_BEST_OFF; i++)
707 if (s->best_pos[i] > 0)
708 s->best_off[i] = swd_pos2off(s,s->best_pos[i]-1);
715 swd_remove_node(s,s->rp);
718 /* add bp into HEAD2 */
720 key = HEAD2(s_b(s),s->bp);
721 s_head2(s)[key] = SWD_UINT(s->bp);