1 /* ucl_swd.c -- sliding window dictionary
3 This file is part of the UCL data compression library.
5 Copyright (C) 1996-2002 Markus Franz Xaver Johannes Oberhumer
8 The UCL library is free software; you can redistribute it and/or
9 modify it under the terms of the GNU General Public License as
10 published by the Free Software Foundation; either version 2 of
11 the License, or (at your option) any later version.
13 The UCL library is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
18 You should have received a copy of the GNU General Public License
19 along with the UCL library; see the file COPYING.
20 If not, write to the Free Software Foundation, Inc.,
21 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
23 Markus F.X.J. Oberhumer
24 <markus@oberhumer.com>
28 #if (UCL_UINT_MAX < UCL_0xffffffffL)
29 # error "UCL_UINT_MAX"
33 /***********************************************************************
35 ************************************************************************/
44 # define SWD_THRESHOLD THRESHOLD
47 /* unsigned type for dictionary access - don't waste memory here */
48 #if (SWD_N + SWD_F + SWD_F < USHRT_MAX)
49 typedef unsigned short swd_uint;
50 # define SWD_UINT_MAX USHRT_MAX
52 typedef ucl_uint swd_uint;
53 # define SWD_UINT_MAX UCL_UINT_MAX
55 #define SWD_UINT(x) ((swd_uint)(x))
59 # define SWD_HSIZE 16384
62 # define SWD_MAX_CHAIN 2048
68 (((0x9f5f*(((((ucl_uint32)b[p]<<5)^b[p+1])<<5)^b[p+2]))>>5) & (SWD_HSIZE-1))
71 (((0x9f5f*(((((ucl_uint32)b[p+2]<<5)^b[p+1])<<5)^b[p]))>>5) & (SWD_HSIZE-1))
75 #if (SWD_THRESHOLD == 1) && !defined(HEAD2)
76 # if 1 && defined(UCL_UNALIGNED_OK_2)
77 # define HEAD2(b,p) (* (const ucl_ushortp) &(b[p]))
79 # define HEAD2(b,p) (b[p] ^ ((unsigned)b[p+1]<<8))
81 # define NIL2 SWD_UINT_MAX
85 #if defined(__UCL_CHECKER)
86 /* malloc arrays of the exact size to detect any overrun */
87 # ifndef SWD_USE_MALLOC
88 # define SWD_USE_MALLOC
95 /* public - "built-in" */
100 /* public - configuration */
102 ucl_uint nice_length;
103 ucl_bool use_best_off;
104 ucl_uint lazy_insert;
106 /* public - output */
111 #if defined(SWD_BEST_OFF)
112 ucl_uint best_off[ SWD_BEST_OFF ];
118 #if defined(SWD_BEST_OFF)
119 ucl_uint best_pos[ SWD_BEST_OFF ];
123 const ucl_byte *dict;
124 const ucl_byte *dict_end;
128 ucl_uint ip; /* input pointer (lookahead) */
129 ucl_uint bp; /* buffer pointer */
130 ucl_uint rp; /* remove pointer */
133 unsigned char *b_wrap;
138 #if defined(SWD_USE_MALLOC)
148 unsigned char b [ SWD_N + SWD_F + SWD_F ];
149 swd_uint head3 [ SWD_HSIZE ];
150 swd_uint succ3 [ SWD_N + SWD_F ];
151 swd_uint best3 [ SWD_N + SWD_F ];
152 swd_uint llen3 [ SWD_HSIZE ];
154 swd_uint head2 [ UCL_UINT32_C(65536) ];
161 /* Access macro for head3.
162 * head3[key] may be uninitialized if the list is emtpy,
163 * but then its value will never be used.
165 #if defined(__UCL_CHECKER)
166 # define s_head3(s,key) \
167 ((s->llen3[key] == 0) ? SWD_UINT_MAX : s->head3[key])
169 # define s_head3(s,key) s->head3[key]
173 /***********************************************************************
175 ************************************************************************/
178 void swd_initdict(ucl_swd_t *s, const ucl_byte *dict, ucl_uint dict_len)
180 s->dict = s->dict_end = NULL;
183 if (!dict || dict_len <= 0)
187 dict += dict_len - s->n;
192 s->dict_len = dict_len;
193 s->dict_end = dict + dict_len;
194 ucl_memcpy(s->b,dict,dict_len);
200 void swd_insertdict(ucl_swd_t *s, ucl_uint node, ucl_uint len)
204 s->node_count = s->n - len;
209 key = HEAD3(s->b,node);
210 s->succ3[node] = s_head3(s,key);
211 s->head3[key] = SWD_UINT(node);
212 s->best3[node] = SWD_UINT(s->f + 1);
214 assert(s->llen3[key] <= s->n);
217 key = HEAD2(s->b,node);
218 s->head2[key] = SWD_UINT(node);
226 /***********************************************************************
228 ************************************************************************/
231 int swd_init(ucl_swd_t *s, const ucl_byte *dict, ucl_uint dict_len)
240 s->threshold = SWD_THRESHOLD;
241 if (s->n > SWD_N || s->f > SWD_F)
242 return UCL_E_INVALID_ARGUMENT;
244 #if defined(SWD_USE_MALLOC)
245 s->b = (unsigned char *) ucl_alloc(s->n + s->f + s->f, 1);
246 s->head3 = (swd_uint *) ucl_alloc(SWD_HSIZE, sizeof(*s->head3));
247 s->succ3 = (swd_uint *) ucl_alloc(s->n + s->f, sizeof(*s->succ3));
248 s->best3 = (swd_uint *) ucl_alloc(s->n + s->f, sizeof(*s->best3));
249 s->llen3 = (swd_uint *) ucl_alloc(SWD_HSIZE, sizeof(*s->llen3));
250 if (!s->b || !s->head3 || !s->succ3 || !s->best3 || !s->llen3)
251 return UCL_E_OUT_OF_MEMORY;
253 s->head2 = (swd_uint *) ucl_alloc(UCL_UINT32_C(65536), sizeof(*s->head2));
255 return UCL_E_OUT_OF_MEMORY;
260 s->max_chain = SWD_MAX_CHAIN;
261 s->nice_length = s->f;
265 s->b_size = s->n + s->f;
266 if (s->b_size + s->f >= SWD_UINT_MAX)
268 s->b_wrap = s->b + s->b_size;
269 s->node_count = s->n;
271 ucl_memset(s->llen3, 0, sizeof(s->llen3[0]) * SWD_HSIZE);
274 ucl_memset(s->head2, 0xff, sizeof(s->head2[0]) * UCL_UINT32_C(65536));
275 assert(s->head2[0] == NIL2);
277 for (i = 0; i < UCL_UINT32_C(65536); i++)
283 swd_initdict(s,dict,dict_len);
287 assert(s->ip + s->f <= s->b_size);
289 s->look = (ucl_uint) (s->c->in_end - s->c->ip);
294 ucl_memcpy(&s->b[s->ip],s->c->ip,s->look);
300 while (s->look < s->f)
302 if ((c = getbyte(*(s->c))) < 0)
304 s->b[s->ip] = UCL_BYTE(c);
309 if (s->ip == s->b_size)
312 if (s->look >= 2 && s->dict_len > 0)
313 swd_insertdict(s,0,s->dict_len);
316 if (s->rp >= s->node_count)
317 s->rp -= s->node_count;
319 s->rp += s->b_size - s->node_count;
321 #if defined(__UCL_CHECKER)
322 /* initialize memory for the first few HEAD3 (if s->ip is not far
323 * enough ahead to do this job for us). The value doesn't matter. */
325 ucl_memset(&s->b[s->bp+s->look],0,3);
335 void swd_exit(ucl_swd_t *s)
337 #if defined(SWD_USE_MALLOC)
338 /* free in reverse order of allocations */
340 ucl_free(s->head2); s->head2 = NULL;
342 ucl_free(s->llen3); s->llen3 = NULL;
343 ucl_free(s->best3); s->best3 = NULL;
344 ucl_free(s->succ3); s->succ3 = NULL;
345 ucl_free(s->head3); s->head3 = NULL;
346 ucl_free(s->b); s->b = NULL;
353 #define swd_pos2off(s,pos) \
354 (s->bp > (pos) ? s->bp - (pos) : s->b_size - ((pos) - s->bp))
357 /***********************************************************************
359 ************************************************************************/
362 void swd_getbyte(ucl_swd_t *s)
366 if ((c = getbyte(*(s->c))) < 0)
370 #if defined(__UCL_CHECKER)
371 /* initialize memory - value doesn't matter */
374 s->b_wrap[s->ip] = 0;
379 s->b[s->ip] = UCL_BYTE(c);
381 s->b_wrap[s->ip] = UCL_BYTE(c);
383 if (++s->ip == s->b_size)
385 if (++s->bp == s->b_size)
387 if (++s->rp == s->b_size)
392 /***********************************************************************
393 // remove node from lists
394 ************************************************************************/
397 void swd_remove_node(ucl_swd_t *s, ucl_uint node)
399 if (s->node_count == 0)
404 if (s->first_rp != UCL_UINT_MAX)
406 if (node != s->first_rp)
407 printf("Remove %5d: %5d %5d %5d %5d %6d %6d\n",
408 node, s->rp, s->ip, s->bp, s->first_rp,
409 s->ip - node, s->ip - s->bp);
410 assert(node == s->first_rp);
411 s->first_rp = UCL_UINT_MAX;
415 key = HEAD3(s->b,node);
416 assert(s->llen3[key] > 0);
420 key = HEAD2(s->b,node);
421 assert(s->head2[key] != NIL2);
422 if ((ucl_uint) s->head2[key] == node)
423 s->head2[key] = NIL2;
431 /***********************************************************************
433 ************************************************************************/
436 void swd_accept(ucl_swd_t *s, ucl_uint n)
438 assert(n <= s->look);
444 swd_remove_node(s,s->rp);
446 /* add bp into HEAD3 */
447 key = HEAD3(s->b,s->bp);
448 s->succ3[s->bp] = s_head3(s,key);
449 s->head3[key] = SWD_UINT(s->bp);
450 s->best3[s->bp] = SWD_UINT(s->f + 1);
452 assert(s->llen3[key] <= s->n);
455 /* add bp into HEAD2 */
456 key = HEAD2(s->b,s->bp);
457 s->head2[key] = SWD_UINT(s->bp);
465 /***********************************************************************
467 ************************************************************************/
470 void swd_search(ucl_swd_t *s, ucl_uint node, ucl_uint cnt)
472 #if 0 && defined(__GNUC__) && defined(__i386__)
473 register const unsigned char *p1 __asm__("%edi");
474 register const unsigned char *p2 __asm__("%esi");
475 register const unsigned char *px __asm__("%edx");
477 const unsigned char *p1;
478 const unsigned char *p2;
479 const unsigned char *px;
481 ucl_uint m_len = s->m_len;
482 const unsigned char * b = s->b;
483 const unsigned char * bp = s->b + s->bp;
484 const unsigned char * bx = s->b + s->bp + s->look;
485 unsigned char scan_end1;
487 assert(s->m_len > 0);
489 scan_end1 = bp[m_len - 1];
490 for ( ; cnt-- > 0; node = s->succ3[node])
496 assert(m_len < s->look);
500 p2[m_len - 1] == scan_end1 &&
501 p2[m_len] == p1[m_len] &&
507 assert(ucl_memcmp(bp,&b[node],3) == 0);
509 #if 0 && defined(UCL_UNALIGNED_OK_4)
511 while (p1 < px && * (const ucl_uint32p) p1 == * (const ucl_uint32p) p2)
513 while (p1 < px && *p1 == *p2)
517 do {} while (++p1 < px && *p1 == *++p2);
522 if (ucl_memcmp(bp,&b[node],i) != 0)
523 printf("%5ld %5ld %02x%02x %02x%02x\n",
524 (long)s->bp, (long) node,
525 bp[0], bp[1], b[node], b[node+1]);
527 assert(ucl_memcmp(bp,&b[node],i) == 0);
529 #if defined(SWD_BEST_OFF)
530 if (i < SWD_BEST_OFF)
532 if (s->best_pos[i] == 0)
533 s->best_pos[i] = node + 1;
538 s->m_len = m_len = i;
540 if (m_len == s->look)
542 if (m_len >= s->nice_length)
544 if (m_len > (ucl_uint) s->best3[node])
546 scan_end1 = bp[m_len - 1];
553 /***********************************************************************
555 ************************************************************************/
560 ucl_bool swd_search2(ucl_swd_t *s)
564 assert(s->look >= 2);
565 assert(s->m_len > 0);
567 key = s->head2[ HEAD2(s->b,s->bp) ];
571 if (ucl_memcmp(&s->b[s->bp],&s->b[key],2) != 0)
572 printf("%5ld %5ld %02x%02x %02x%02x\n", (long)s->bp, (long)key,
573 s->b[s->bp], s->b[s->bp+1], s->b[key], s->b[key+1]);
575 assert(ucl_memcmp(&s->b[s->bp],&s->b[key],2) == 0);
576 #if defined(SWD_BEST_OFF)
577 if (s->best_pos[2] == 0)
578 s->best_pos[2] = key + 1;
592 /***********************************************************************
594 ************************************************************************/
597 void swd_findbest(ucl_swd_t *s)
603 assert(s->m_len > 0);
605 /* get current head, add bp into HEAD3 */
606 key = HEAD3(s->b,s->bp);
607 node = s->succ3[s->bp] = s_head3(s,key);
608 cnt = s->llen3[key]++;
609 assert(s->llen3[key] <= s->n + s->f);
610 if (cnt > s->max_chain && s->max_chain > 0)
612 s->head3[key] = SWD_UINT(s->bp);
614 s->b_char = s->b[s->bp];
616 if (s->m_len >= s->look)
621 s->best3[s->bp] = SWD_UINT(s->f + 1);
629 swd_search(s,node,cnt);
631 s->m_off = swd_pos2off(s,s->m_pos);
632 s->best3[s->bp] = SWD_UINT(s->m_len);
634 #if defined(SWD_BEST_OFF)
638 for (i = 2; i < SWD_BEST_OFF; i++)
639 if (s->best_pos[i] > 0)
640 s->best_off[i] = swd_pos2off(s,s->best_pos[i]-1);
647 swd_remove_node(s,s->rp);
650 /* add bp into HEAD2 */
651 key = HEAD2(s->b,s->bp);
652 s->head2[key] = SWD_UINT(s->bp);