+ while (end_node < cur_node + best_len)
+ (++end_node)->cost = INFINITE_COST;
+
+ u32 base_cost = cur_node->cost +
+ lzms_bit_1_cost(cur_node->state.main_state,
+ c->probs.main) +
+ lzms_bit_0_cost(cur_node->state.match_state,
+ c->probs.match) +
+ lzms_bit_0_cost(cur_node->state.lz_state,
+ c->probs.lz);
+
+ if (c->try_lzmatch_lit_lzrep0 &&
+ likely(in_end - (in_next + c->matches[0].length) >= 3))
+ {
+ /* try LZ-match + lit + LZ-rep0 */
+
+ u32 l = 2;
+ u32 i = num_matches - 1;
+ do {
+ const u32 len = c->matches[i].length;
+ const u32 offset = c->matches[i].offset;
+ const u32 position_cost = base_cost +
+ lzms_lz_offset_cost(c, offset);
+ do {
+ u32 cost = position_cost + lzms_fast_length_cost(c, l);
+ if (cost < (cur_node + l)->cost) {
+ (cur_node + l)->cost = cost;
+ (cur_node + l)->item = (struct lzms_item) {
+ .length = l,
+ .source = offset + (LZMS_NUM_LZ_REPS - 1),
+ };
+ (cur_node + l)->num_extra_items = 0;
+ }
+ } while (++l <= len);
+
+ const u8 * const matchptr = in_next - offset;
+ if (load_u16_unaligned(matchptr + len + 1) !=
+ load_u16_unaligned(in_next + len + 1))
+ continue;
+
+ const u32 rep0_len = lz_extend(in_next + len + 1,
+ matchptr + len + 1,
+ 2,
+ min(c->mf.nice_match_len,
+ in_end - (in_next + len + 1)));
+
+ unsigned main_state = cur_node->state.main_state;
+ unsigned match_state = cur_node->state.match_state;
+ unsigned lz_state = cur_node->state.lz_state;
+
+ /* update states for LZ-match */
+ main_state = ((main_state << 1) | 1) % LZMS_NUM_MAIN_PROBS;
+ match_state = ((match_state << 1) | 0) % LZMS_NUM_MATCH_PROBS;
+ lz_state = ((lz_state << 1) | 0) % LZMS_NUM_LZ_PROBS;
+
+ /* LZ-match cost */
+ u32 cost = position_cost + lzms_fast_length_cost(c, len);
+
+ /* add literal cost */
+ cost += lzms_literal_cost(c, main_state, *(in_next + len));
+
+ /* update state for literal */
+ main_state = ((main_state << 1) | 0) % LZMS_NUM_MAIN_PROBS;
+
+ /* add LZ-rep0 cost */
+ cost += lzms_bit_1_cost(main_state, c->probs.main) +
+ lzms_bit_0_cost(match_state, c->probs.match) +
+ lzms_bit_1_cost(lz_state, c->probs.lz) +
+ lzms_bit_0_cost(cur_node->state.lz_rep_states[0],
+ c->probs.lz_rep[0]) +
+ lzms_fast_length_cost(c, rep0_len);
+
+ const u32 total_len = len + 1 + rep0_len;
+
+ while (end_node < cur_node + total_len)
+ (++end_node)->cost = INFINITE_COST;
+
+ if (cost < (cur_node + total_len)->cost) {
+ (cur_node + total_len)->cost = cost;
+ (cur_node + total_len)->item = (struct lzms_item) {
+ .length = rep0_len,
+ .source = 0,
+ };
+ (cur_node + total_len)->extra_items[0] = (struct lzms_item) {
+ .length = 1,
+ .source = *(in_next + len),
+ };
+ (cur_node + total_len)->extra_items[1] = (struct lzms_item) {
+ .length = len,
+ .source = offset + LZMS_NUM_LZ_REPS - 1,
+ };
+ (cur_node + total_len)->num_extra_items = 2;
+ }
+ } while (i--);
+ } else {
+ u32 l = 2;
+ u32 i = num_matches - 1;
+ do {
+ u32 position_cost = base_cost +
+ lzms_lz_offset_cost(c, c->matches[i].offset);
+ do {
+ u32 cost = position_cost + lzms_fast_length_cost(c, l);
+ if (cost < (cur_node + l)->cost) {
+ (cur_node + l)->cost = cost;
+ (cur_node + l)->item = (struct lzms_item) {
+ .length = l,
+ .source = c->matches[i].offset +
+ (LZMS_NUM_LZ_REPS - 1),
+ };
+ (cur_node + l)->num_extra_items = 0;
+ }
+ } while (++l <= c->matches[i].length);
+ } while (i--);
+ }
+ }