+ c->cur_window_ptr = c->cur_window;
+ window_ptr = c->cur_window;
+ window_end = window_ptr + c->cur_window_size;
+ c->cache_ptr = c->cached_matches;
+ memset(c->freqs, 0, sizeof(c->freqs));
+ next_chosen_item = c->chosen_items;
+
+ u32 unseen_cost = 9;
+ while (window_ptr != window_end) {
+ raw_item = xpress_choose_near_optimal_item(c);
+ if (raw_item.len >= XPRESS_MIN_MATCH_LEN) {
+ xpress_item = xpress_tally_match(raw_item.len,
+ raw_item.offset,
+ c->freqs);
+ window_ptr += raw_item.len;
+ } else {
+ xpress_item = xpress_tally_literal(*window_ptr,
+ c->freqs);
+ window_ptr += 1;
+ }
+ *next_chosen_item++ = xpress_item;
+
+ /* When doing one-pass near-optimal parsing, rebuild the Huffman
+ * code occasionally. */
+ if (unlikely((next_chosen_item - c->chosen_items) % 2048 == 0) &&
+ c->cur_window_size >= 16384 &&
+ c->params.num_optim_passes == 1)
+ {
+ xpress_make_huffman_code(c);
+ for (unsigned i = 0; i < XPRESS_NUM_SYMBOLS; i++)
+ c->costs[i] = c->lens[i] ? c->lens[i] : unseen_cost;
+ if (unseen_cost < 15)
+ unseen_cost++;
+ }
+ }
+ c->freqs[XPRESS_END_OF_DATA]++;
+ xpress_make_huffman_code(c);
+ return next_chosen_item - c->chosen_items;
+}
+
+/* Lazy parsing */
+static u32
+xpress_choose_items_lazy(struct xpress_compressor *c)
+{
+ struct lz_mf *mf;
+ u32 len_3_too_far;
+ const u8 *window_ptr;
+ const u8 *window_end;
+ u32 num_matches;
+ struct lz_match matches[min(c->params.nice_match_length, c->params.max_search_depth)];
+ struct xpress_item *next_chosen_item;
+ struct lz_match prev_match;
+
+ mf = c->mf;
+
+ lz_mf_load_window(mf, c->cur_window, c->cur_window_size);
+
+ if (c->cur_window_size <= 8192)
+ len_3_too_far = 2048;
+ else
+ len_3_too_far = 4096;
+
+ memset(c->freqs, 0, sizeof(c->freqs));
+
+ window_ptr = c->cur_window;
+ window_end = c->cur_window + c->cur_window_size;
+ next_chosen_item = c->chosen_items;
+
+ for (;;) {
+
+ /* Don't have match at previous position */
+
+ num_matches = lz_mf_get_matches(mf, matches);
+ window_ptr++;
+
+ if (num_matches == 0 ||
+ (matches[num_matches - 1].len == 3 &&
+ matches[num_matches - 1].offset >= len_3_too_far))
+ {
+ /* No matches found => output literal */
+ *next_chosen_item++ = xpress_tally_literal(*(window_ptr - 1),
+ c->freqs);
+ if (window_ptr == window_end)
+ break;
+ continue;
+ }
+
+ prev_match = matches[num_matches - 1];
+
+ have_prev_match:
+ /* Have match at previous position */
+
+ if (prev_match.len >= c->params.nice_match_length) {
+ /* Very long match found => output immediately */
+ *next_chosen_item++ = xpress_tally_match(prev_match.len,
+ prev_match.offset,
+ c->freqs);
+ lz_mf_skip_positions(mf, prev_match.len - 1);
+ window_ptr += prev_match.len - 1;
+ if (window_ptr == window_end)
+ break;
+ continue;
+ }
+
+ num_matches = lz_mf_get_matches(mf, matches);
+ window_ptr++;
+
+ if (num_matches == 0 ||
+ (matches[num_matches - 1].len <= prev_match.len))
+ {
+ /* Next match is not longer => output previous match */
+ *next_chosen_item++ = xpress_tally_match(prev_match.len,
+ prev_match.offset,
+ c->freqs);
+ lz_mf_skip_positions(mf, prev_match.len - 2);
+ window_ptr += prev_match.len - 2;
+ if (window_ptr == window_end)
+ break;
+ continue;
+ }
+
+ /* Next match is longer => output literal */
+
+ *next_chosen_item++ = xpress_tally_literal(*(window_ptr - 2),
+ c->freqs);
+
+ prev_match = matches[num_matches - 1];
+
+ goto have_prev_match;
+ }
+
+ c->freqs[XPRESS_END_OF_DATA]++;
+ xpress_make_huffman_code(c);
+ return next_chosen_item - c->chosen_items;
+}
+
+/* Greedy parsing */
+static u32
+xpress_choose_items_greedy(struct xpress_compressor *c)
+{
+ struct lz_mf *mf;
+ u32 len_3_too_far;
+ const u8 *window_ptr;
+ const u8 *window_end;
+ struct lz_match matches[min(c->params.nice_match_length, c->params.max_search_depth)];
+ u32 num_matches;
+ struct xpress_item *next_chosen_item;
+
+ mf = c->mf;
+
+ lz_mf_load_window(mf, c->cur_window, c->cur_window_size);
+
+ if (c->cur_window_size <= 8192)
+ len_3_too_far = 2048;
+ else
+ len_3_too_far = 4096;
+
+ memset(c->freqs, 0, sizeof(c->freqs));
+
+ window_ptr = c->cur_window;
+ window_end = c->cur_window + c->cur_window_size;
+ next_chosen_item = c->chosen_items;
+
+ do {
+ /* Get longest match at the current position. */
+ num_matches = lz_mf_get_matches(mf, matches);
+
+ if (num_matches == 0 ||
+ (matches[num_matches - 1].len == 3 &&
+ matches[num_matches - 1].offset >= len_3_too_far))
+ {
+ *next_chosen_item++ = xpress_tally_literal(*window_ptr, c->freqs);
+ window_ptr += 1;
+ } else {
+ u32 len = matches[num_matches - 1].len;
+ u32 offset = matches[num_matches - 1].offset;
+
+ *next_chosen_item++ = xpress_tally_match(len, offset, c->freqs);
+ lz_mf_skip_positions(mf, len - 1);
+ window_ptr += len;
+ }
+ } while (window_ptr != window_end);
+
+ c->freqs[XPRESS_END_OF_DATA]++;
+ xpress_make_huffman_code(c);
+ return next_chosen_item - c->chosen_items;