xref: /freebsd/contrib/xz/src/liblzma/lz/lz_encoder_mf.c (revision b1f9167f94059fd55c630891d359bcff987bd7eb)
1 ///////////////////////////////////////////////////////////////////////////////
2 //
3 /// \file       lz_encoder_mf.c
4 /// \brief      Match finders
5 ///
6 //  Authors:    Igor Pavlov
7 //              Lasse Collin
8 //
9 //  This file has been put into the public domain.
10 //  You can do whatever you want with this file.
11 //
12 ///////////////////////////////////////////////////////////////////////////////
13 
14 #include "lz_encoder.h"
15 #include "lz_encoder_hash.h"
16 
17 
18 /// \brief      Find matches starting from the current byte
19 ///
20 /// \return     The length of the longest match found
21 extern uint32_t
22 lzma_mf_find(lzma_mf *mf, uint32_t *count_ptr, lzma_match *matches)
23 {
24 	// Call the match finder. It returns the number of length-distance
25 	// pairs found.
26 	// FIXME: Minimum count is zero, what _exactly_ is the maximum?
27 	const uint32_t count = mf->find(mf, matches);
28 
29 	// Length of the longest match; assume that no matches were found
30 	// and thus the maximum length is zero.
31 	uint32_t len_best = 0;
32 
33 	if (count > 0) {
34 #ifndef NDEBUG
35 		// Validate the matches.
36 		for (uint32_t i = 0; i < count; ++i) {
37 			assert(matches[i].len <= mf->nice_len);
38 			assert(matches[i].dist < mf->read_pos);
39 			assert(memcmp(mf_ptr(mf) - 1,
40 				mf_ptr(mf) - matches[i].dist - 2,
41 				matches[i].len) == 0);
42 		}
43 #endif
44 
45 		// The last used element in the array contains
46 		// the longest match.
47 		len_best = matches[count - 1].len;
48 
49 		// If a match of maximum search length was found, try to
50 		// extend the match to maximum possible length.
51 		if (len_best == mf->nice_len) {
52 			// The limit for the match length is either the
53 			// maximum match length supported by the LZ-based
54 			// encoder or the number of bytes left in the
55 			// dictionary, whichever is smaller.
56 			uint32_t limit = mf_avail(mf) + 1;
57 			if (limit > mf->match_len_max)
58 				limit = mf->match_len_max;
59 
60 			// Pointer to the byte we just ran through
61 			// the match finder.
62 			const uint8_t *p1 = mf_ptr(mf) - 1;
63 
64 			// Pointer to the beginning of the match. We need -1
65 			// here because the match distances are zero based.
66 			const uint8_t *p2 = p1 - matches[count - 1].dist - 1;
67 
68 			while (len_best < limit
69 					&& p1[len_best] == p2[len_best])
70 				++len_best;
71 		}
72 	}
73 
74 	*count_ptr = count;
75 
76 	// Finally update the read position to indicate that match finder was
77 	// run for this dictionary offset.
78 	++mf->read_ahead;
79 
80 	return len_best;
81 }
82 
83 
84 /// Hash value to indicate unused element in the hash. Since we start the
85 /// positions from dict_size + 1, zero is always too far to qualify
86 /// as usable match position.
87 #define EMPTY_HASH_VALUE 0
88 
89 
90 /// Normalization must be done when lzma_mf.offset + lzma_mf.read_pos
91 /// reaches MUST_NORMALIZE_POS.
92 #define MUST_NORMALIZE_POS UINT32_MAX
93 
94 
95 /// \brief      Normalizes hash values
96 ///
97 /// The hash arrays store positions of match candidates. The positions are
98 /// relative to an arbitrary offset that is not the same as the absolute
99 /// offset in the input stream. The relative position of the current byte
100 /// is lzma_mf.offset + lzma_mf.read_pos. The distances of the matches are
101 /// the differences of the current read position and the position found from
102 /// the hash.
103 ///
104 /// To prevent integer overflows of the offsets stored in the hash arrays,
105 /// we need to "normalize" the stored values now and then. During the
106 /// normalization, we drop values that indicate distance greater than the
107 /// dictionary size, thus making space for new values.
108 static void
109 normalize(lzma_mf *mf)
110 {
111 	assert(mf->read_pos + mf->offset == MUST_NORMALIZE_POS);
112 
113 	// In future we may not want to touch the lowest bits, because there
114 	// may be match finders that use larger resolution than one byte.
115 	const uint32_t subvalue
116 			= (MUST_NORMALIZE_POS - mf->cyclic_size);
117 				// & (~(UINT32_C(1) << 10) - 1);
118 
119 	const uint32_t count = mf->hash_size_sum + mf->sons_count;
120 	uint32_t *hash = mf->hash;
121 
122 	for (uint32_t i = 0; i < count; ++i) {
123 		// If the distance is greater than the dictionary size,
124 		// we can simply mark the hash element as empty.
125 		//
126 		// NOTE: Only the first mf->hash_size_sum elements are
127 		// initialized for sure. There may be uninitialized elements
128 		// in mf->son. Since we go through both mf->hash and
129 		// mf->son here in normalization, Valgrind may complain
130 		// that the "if" below depends on uninitialized value. In
131 		// this case it is safe to ignore the warning. See also the
132 		// comments in lz_encoder_init() in lz_encoder.c.
133 		if (hash[i] <= subvalue)
134 			hash[i] = EMPTY_HASH_VALUE;
135 		else
136 			hash[i] -= subvalue;
137 	}
138 
139 	// Update offset to match the new locations.
140 	mf->offset -= subvalue;
141 
142 	return;
143 }
144 
145 
146 /// Mark the current byte as processed from point of view of the match finder.
147 static void
148 move_pos(lzma_mf *mf)
149 {
150 	if (++mf->cyclic_pos == mf->cyclic_size)
151 		mf->cyclic_pos = 0;
152 
153 	++mf->read_pos;
154 	assert(mf->read_pos <= mf->write_pos);
155 
156 	if (unlikely(mf->read_pos + mf->offset == UINT32_MAX))
157 		normalize(mf);
158 }
159 
160 
161 /// When flushing, we cannot run the match finder unless there is nice_len
162 /// bytes available in the dictionary. Instead, we skip running the match
163 /// finder (indicating that no match was found), and count how many bytes we
164 /// have ignored this way.
165 ///
166 /// When new data is given after the flushing was completed, the match finder
167 /// is restarted by rewinding mf->read_pos backwards by mf->pending. Then
168 /// the missed bytes are added to the hash using the match finder's skip
169 /// function (with small amount of input, it may start using mf->pending
170 /// again if flushing).
171 ///
172 /// Due to this rewinding, we don't touch cyclic_pos or test for
173 /// normalization. It will be done when the match finder's skip function
174 /// catches up after a flush.
175 static void
176 move_pending(lzma_mf *mf)
177 {
178 	++mf->read_pos;
179 	assert(mf->read_pos <= mf->write_pos);
180 	++mf->pending;
181 }
182 
183 
184 /// Calculate len_limit and determine if there is enough input to run
185 /// the actual match finder code. Sets up "cur" and "pos". This macro
186 /// is used by all find functions and binary tree skip functions. Hash
187 /// chain skip function doesn't need len_limit so a simpler code is used
188 /// in them.
189 #define header(is_bt, len_min, ret_op) \
190 	uint32_t len_limit = mf_avail(mf); \
191 	if (mf->nice_len <= len_limit) { \
192 		len_limit = mf->nice_len; \
193 	} else if (len_limit < (len_min) \
194 			|| (is_bt && mf->action == LZMA_SYNC_FLUSH)) { \
195 		assert(mf->action != LZMA_RUN); \
196 		move_pending(mf); \
197 		ret_op; \
198 	} \
199 	const uint8_t *cur = mf_ptr(mf); \
200 	const uint32_t pos = mf->read_pos + mf->offset
201 
202 
203 /// Header for find functions. "return 0" indicates that zero matches
204 /// were found.
205 #define header_find(is_bt, len_min) \
206 	header(is_bt, len_min, return 0); \
207 	uint32_t matches_count = 0
208 
209 
210 /// Header for a loop in a skip function. "continue" tells to skip the rest
211 /// of the code in the loop.
212 #define header_skip(is_bt, len_min) \
213 	header(is_bt, len_min, continue)
214 
215 
216 /// Calls hc_find_func() or bt_find_func() and calculates the total number
217 /// of matches found. Updates the dictionary position and returns the number
218 /// of matches found.
219 #define call_find(func, len_best) \
220 do { \
221 	matches_count = func(len_limit, pos, cur, cur_match, mf->depth, \
222 				mf->son, mf->cyclic_pos, mf->cyclic_size, \
223 				matches + matches_count, len_best) \
224 			- matches; \
225 	move_pos(mf); \
226 	return matches_count; \
227 } while (0)
228 
229 
230 ////////////////
231 // Hash Chain //
232 ////////////////
233 
234 #if defined(HAVE_MF_HC3) || defined(HAVE_MF_HC4)
235 ///
236 ///
237 /// \param      len_limit       Don't look for matches longer than len_limit.
238 /// \param      pos             lzma_mf.read_pos + lzma_mf.offset
239 /// \param      cur             Pointer to current byte (mf_ptr(mf))
240 /// \param      cur_match       Start position of the current match candidate
241 /// \param      depth           Maximum length of the hash chain
242 /// \param      son             lzma_mf.son (contains the hash chain)
243 /// \param      cyclic_pos
244 /// \param      cyclic_size
245 /// \param      matches         Array to hold the matches.
246 /// \param      len_best        The length of the longest match found so far.
247 static lzma_match *
248 hc_find_func(
249 		const uint32_t len_limit,
250 		const uint32_t pos,
251 		const uint8_t *const cur,
252 		uint32_t cur_match,
253 		uint32_t depth,
254 		uint32_t *const son,
255 		const uint32_t cyclic_pos,
256 		const uint32_t cyclic_size,
257 		lzma_match *matches,
258 		uint32_t len_best)
259 {
260 	son[cyclic_pos] = cur_match;
261 
262 	while (true) {
263 		const uint32_t delta = pos - cur_match;
264 		if (depth-- == 0 || delta >= cyclic_size)
265 			return matches;
266 
267 		const uint8_t *const pb = cur - delta;
268 		cur_match = son[cyclic_pos - delta
269 				+ (delta > cyclic_pos ? cyclic_size : 0)];
270 
271 		if (pb[len_best] == cur[len_best] && pb[0] == cur[0]) {
272 			uint32_t len = 0;
273 			while (++len != len_limit)
274 				if (pb[len] != cur[len])
275 					break;
276 
277 			if (len_best < len) {
278 				len_best = len;
279 				matches->len = len;
280 				matches->dist = delta - 1;
281 				++matches;
282 
283 				if (len == len_limit)
284 					return matches;
285 			}
286 		}
287 	}
288 }
289 
290 
291 #define hc_find(len_best) \
292 	call_find(hc_find_func, len_best)
293 
294 
295 #define hc_skip() \
296 do { \
297 	mf->son[mf->cyclic_pos] = cur_match; \
298 	move_pos(mf); \
299 } while (0)
300 
301 #endif
302 
303 
304 #ifdef HAVE_MF_HC3
305 extern uint32_t
306 lzma_mf_hc3_find(lzma_mf *mf, lzma_match *matches)
307 {
308 	header_find(false, 3);
309 
310 	hash_3_calc();
311 
312 	const uint32_t delta2 = pos - mf->hash[hash_2_value];
313 	const uint32_t cur_match = mf->hash[FIX_3_HASH_SIZE + hash_value];
314 
315 	mf->hash[hash_2_value] = pos;
316 	mf->hash[FIX_3_HASH_SIZE + hash_value] = pos;
317 
318 	uint32_t len_best = 2;
319 
320 	if (delta2 < mf->cyclic_size && *(cur - delta2) == *cur) {
321 		for ( ; len_best != len_limit; ++len_best)
322 			if (*(cur + len_best - delta2) != cur[len_best])
323 				break;
324 
325 		matches[0].len = len_best;
326 		matches[0].dist = delta2 - 1;
327 		matches_count = 1;
328 
329 		if (len_best == len_limit) {
330 			hc_skip();
331 			return 1; // matches_count
332 		}
333 	}
334 
335 	hc_find(len_best);
336 }
337 
338 
339 extern void
340 lzma_mf_hc3_skip(lzma_mf *mf, uint32_t amount)
341 {
342 	do {
343 		if (mf_avail(mf) < 3) {
344 			move_pending(mf);
345 			continue;
346 		}
347 
348 		const uint8_t *cur = mf_ptr(mf);
349 		const uint32_t pos = mf->read_pos + mf->offset;
350 
351 		hash_3_calc();
352 
353 		const uint32_t cur_match
354 				= mf->hash[FIX_3_HASH_SIZE + hash_value];
355 
356 		mf->hash[hash_2_value] = pos;
357 		mf->hash[FIX_3_HASH_SIZE + hash_value] = pos;
358 
359 		hc_skip();
360 
361 	} while (--amount != 0);
362 }
363 #endif
364 
365 
366 #ifdef HAVE_MF_HC4
367 extern uint32_t
368 lzma_mf_hc4_find(lzma_mf *mf, lzma_match *matches)
369 {
370 	header_find(false, 4);
371 
372 	hash_4_calc();
373 
374 	uint32_t delta2 = pos - mf->hash[hash_2_value];
375 	const uint32_t delta3
376 			= pos - mf->hash[FIX_3_HASH_SIZE + hash_3_value];
377 	const uint32_t cur_match = mf->hash[FIX_4_HASH_SIZE + hash_value];
378 
379 	mf->hash[hash_2_value ] = pos;
380 	mf->hash[FIX_3_HASH_SIZE + hash_3_value] = pos;
381 	mf->hash[FIX_4_HASH_SIZE + hash_value] = pos;
382 
383 	uint32_t len_best = 1;
384 
385 	if (delta2 < mf->cyclic_size && *(cur - delta2) == *cur) {
386 		len_best = 2;
387 		matches[0].len = 2;
388 		matches[0].dist = delta2 - 1;
389 		matches_count = 1;
390 	}
391 
392 	if (delta2 != delta3 && delta3 < mf->cyclic_size
393 			&& *(cur - delta3) == *cur) {
394 		len_best = 3;
395 		matches[matches_count++].dist = delta3 - 1;
396 		delta2 = delta3;
397 	}
398 
399 	if (matches_count != 0) {
400 		for ( ; len_best != len_limit; ++len_best)
401 			if (*(cur + len_best - delta2) != cur[len_best])
402 				break;
403 
404 		matches[matches_count - 1].len = len_best;
405 
406 		if (len_best == len_limit) {
407 			hc_skip();
408 			return matches_count;
409 		}
410 	}
411 
412 	if (len_best < 3)
413 		len_best = 3;
414 
415 	hc_find(len_best);
416 }
417 
418 
419 extern void
420 lzma_mf_hc4_skip(lzma_mf *mf, uint32_t amount)
421 {
422 	do {
423 		if (mf_avail(mf) < 4) {
424 			move_pending(mf);
425 			continue;
426 		}
427 
428 		const uint8_t *cur = mf_ptr(mf);
429 		const uint32_t pos = mf->read_pos + mf->offset;
430 
431 		hash_4_calc();
432 
433 		const uint32_t cur_match
434 				= mf->hash[FIX_4_HASH_SIZE + hash_value];
435 
436 		mf->hash[hash_2_value] = pos;
437 		mf->hash[FIX_3_HASH_SIZE + hash_3_value] = pos;
438 		mf->hash[FIX_4_HASH_SIZE + hash_value] = pos;
439 
440 		hc_skip();
441 
442 	} while (--amount != 0);
443 }
444 #endif
445 
446 
447 /////////////////
448 // Binary Tree //
449 /////////////////
450 
451 #if defined(HAVE_MF_BT2) || defined(HAVE_MF_BT3) || defined(HAVE_MF_BT4)
452 static lzma_match *
453 bt_find_func(
454 		const uint32_t len_limit,
455 		const uint32_t pos,
456 		const uint8_t *const cur,
457 		uint32_t cur_match,
458 		uint32_t depth,
459 		uint32_t *const son,
460 		const uint32_t cyclic_pos,
461 		const uint32_t cyclic_size,
462 		lzma_match *matches,
463 		uint32_t len_best)
464 {
465 	uint32_t *ptr0 = son + (cyclic_pos << 1) + 1;
466 	uint32_t *ptr1 = son + (cyclic_pos << 1);
467 
468 	uint32_t len0 = 0;
469 	uint32_t len1 = 0;
470 
471 	while (true) {
472 		const uint32_t delta = pos - cur_match;
473 		if (depth-- == 0 || delta >= cyclic_size) {
474 			*ptr0 = EMPTY_HASH_VALUE;
475 			*ptr1 = EMPTY_HASH_VALUE;
476 			return matches;
477 		}
478 
479 		uint32_t *const pair = son + ((cyclic_pos - delta
480 				+ (delta > cyclic_pos ? cyclic_size : 0))
481 				<< 1);
482 
483 		const uint8_t *const pb = cur - delta;
484 		uint32_t len = my_min(len0, len1);
485 
486 		if (pb[len] == cur[len]) {
487 			while (++len != len_limit)
488 				if (pb[len] != cur[len])
489 					break;
490 
491 			if (len_best < len) {
492 				len_best = len;
493 				matches->len = len;
494 				matches->dist = delta - 1;
495 				++matches;
496 
497 				if (len == len_limit) {
498 					*ptr1 = pair[0];
499 					*ptr0 = pair[1];
500 					return matches;
501 				}
502 			}
503 		}
504 
505 		if (pb[len] < cur[len]) {
506 			*ptr1 = cur_match;
507 			ptr1 = pair + 1;
508 			cur_match = *ptr1;
509 			len1 = len;
510 		} else {
511 			*ptr0 = cur_match;
512 			ptr0 = pair;
513 			cur_match = *ptr0;
514 			len0 = len;
515 		}
516 	}
517 }
518 
519 
520 static void
521 bt_skip_func(
522 		const uint32_t len_limit,
523 		const uint32_t pos,
524 		const uint8_t *const cur,
525 		uint32_t cur_match,
526 		uint32_t depth,
527 		uint32_t *const son,
528 		const uint32_t cyclic_pos,
529 		const uint32_t cyclic_size)
530 {
531 	uint32_t *ptr0 = son + (cyclic_pos << 1) + 1;
532 	uint32_t *ptr1 = son + (cyclic_pos << 1);
533 
534 	uint32_t len0 = 0;
535 	uint32_t len1 = 0;
536 
537 	while (true) {
538 		const uint32_t delta = pos - cur_match;
539 		if (depth-- == 0 || delta >= cyclic_size) {
540 			*ptr0 = EMPTY_HASH_VALUE;
541 			*ptr1 = EMPTY_HASH_VALUE;
542 			return;
543 		}
544 
545 		uint32_t *pair = son + ((cyclic_pos - delta
546 				+ (delta > cyclic_pos ? cyclic_size : 0))
547 				<< 1);
548 		const uint8_t *pb = cur - delta;
549 		uint32_t len = my_min(len0, len1);
550 
551 		if (pb[len] == cur[len]) {
552 			while (++len != len_limit)
553 				if (pb[len] != cur[len])
554 					break;
555 
556 			if (len == len_limit) {
557 				*ptr1 = pair[0];
558 				*ptr0 = pair[1];
559 				return;
560 			}
561 		}
562 
563 		if (pb[len] < cur[len]) {
564 			*ptr1 = cur_match;
565 			ptr1 = pair + 1;
566 			cur_match = *ptr1;
567 			len1 = len;
568 		} else {
569 			*ptr0 = cur_match;
570 			ptr0 = pair;
571 			cur_match = *ptr0;
572 			len0 = len;
573 		}
574 	}
575 }
576 
577 
578 #define bt_find(len_best) \
579 	call_find(bt_find_func, len_best)
580 
581 #define bt_skip() \
582 do { \
583 	bt_skip_func(len_limit, pos, cur, cur_match, mf->depth, \
584 			mf->son, mf->cyclic_pos, \
585 			mf->cyclic_size); \
586 	move_pos(mf); \
587 } while (0)
588 
589 #endif
590 
591 
592 #ifdef HAVE_MF_BT2
593 extern uint32_t
594 lzma_mf_bt2_find(lzma_mf *mf, lzma_match *matches)
595 {
596 	header_find(true, 2);
597 
598 	hash_2_calc();
599 
600 	const uint32_t cur_match = mf->hash[hash_value];
601 	mf->hash[hash_value] = pos;
602 
603 	bt_find(1);
604 }
605 
606 
607 extern void
608 lzma_mf_bt2_skip(lzma_mf *mf, uint32_t amount)
609 {
610 	do {
611 		header_skip(true, 2);
612 
613 		hash_2_calc();
614 
615 		const uint32_t cur_match = mf->hash[hash_value];
616 		mf->hash[hash_value] = pos;
617 
618 		bt_skip();
619 
620 	} while (--amount != 0);
621 }
622 #endif
623 
624 
625 #ifdef HAVE_MF_BT3
626 extern uint32_t
627 lzma_mf_bt3_find(lzma_mf *mf, lzma_match *matches)
628 {
629 	header_find(true, 3);
630 
631 	hash_3_calc();
632 
633 	const uint32_t delta2 = pos - mf->hash[hash_2_value];
634 	const uint32_t cur_match = mf->hash[FIX_3_HASH_SIZE + hash_value];
635 
636 	mf->hash[hash_2_value] = pos;
637 	mf->hash[FIX_3_HASH_SIZE + hash_value] = pos;
638 
639 	uint32_t len_best = 2;
640 
641 	if (delta2 < mf->cyclic_size && *(cur - delta2) == *cur) {
642 		for ( ; len_best != len_limit; ++len_best)
643 			if (*(cur + len_best - delta2) != cur[len_best])
644 				break;
645 
646 		matches[0].len = len_best;
647 		matches[0].dist = delta2 - 1;
648 		matches_count = 1;
649 
650 		if (len_best == len_limit) {
651 			bt_skip();
652 			return 1; // matches_count
653 		}
654 	}
655 
656 	bt_find(len_best);
657 }
658 
659 
660 extern void
661 lzma_mf_bt3_skip(lzma_mf *mf, uint32_t amount)
662 {
663 	do {
664 		header_skip(true, 3);
665 
666 		hash_3_calc();
667 
668 		const uint32_t cur_match
669 				= mf->hash[FIX_3_HASH_SIZE + hash_value];
670 
671 		mf->hash[hash_2_value] = pos;
672 		mf->hash[FIX_3_HASH_SIZE + hash_value] = pos;
673 
674 		bt_skip();
675 
676 	} while (--amount != 0);
677 }
678 #endif
679 
680 
681 #ifdef HAVE_MF_BT4
682 extern uint32_t
683 lzma_mf_bt4_find(lzma_mf *mf, lzma_match *matches)
684 {
685 	header_find(true, 4);
686 
687 	hash_4_calc();
688 
689 	uint32_t delta2 = pos - mf->hash[hash_2_value];
690 	const uint32_t delta3
691 			= pos - mf->hash[FIX_3_HASH_SIZE + hash_3_value];
692 	const uint32_t cur_match = mf->hash[FIX_4_HASH_SIZE + hash_value];
693 
694 	mf->hash[hash_2_value] = pos;
695 	mf->hash[FIX_3_HASH_SIZE + hash_3_value] = pos;
696 	mf->hash[FIX_4_HASH_SIZE + hash_value] = pos;
697 
698 	uint32_t len_best = 1;
699 
700 	if (delta2 < mf->cyclic_size && *(cur - delta2) == *cur) {
701 		len_best = 2;
702 		matches[0].len = 2;
703 		matches[0].dist = delta2 - 1;
704 		matches_count = 1;
705 	}
706 
707 	if (delta2 != delta3 && delta3 < mf->cyclic_size
708 			&& *(cur - delta3) == *cur) {
709 		len_best = 3;
710 		matches[matches_count++].dist = delta3 - 1;
711 		delta2 = delta3;
712 	}
713 
714 	if (matches_count != 0) {
715 		for ( ; len_best != len_limit; ++len_best)
716 			if (*(cur + len_best - delta2) != cur[len_best])
717 				break;
718 
719 		matches[matches_count - 1].len = len_best;
720 
721 		if (len_best == len_limit) {
722 			bt_skip();
723 			return matches_count;
724 		}
725 	}
726 
727 	if (len_best < 3)
728 		len_best = 3;
729 
730 	bt_find(len_best);
731 }
732 
733 
734 extern void
735 lzma_mf_bt4_skip(lzma_mf *mf, uint32_t amount)
736 {
737 	do {
738 		header_skip(true, 4);
739 
740 		hash_4_calc();
741 
742 		const uint32_t cur_match
743 				= mf->hash[FIX_4_HASH_SIZE + hash_value];
744 
745 		mf->hash[hash_2_value] = pos;
746 		mf->hash[FIX_3_HASH_SIZE + hash_3_value] = pos;
747 		mf->hash[FIX_4_HASH_SIZE + hash_value] = pos;
748 
749 		bt_skip();
750 
751 	} while (--amount != 0);
752 }
753 #endif
754