mirror of
https://git.tukaani.org/xz.git
synced 2025-12-26 07:18:44 +00:00
This has no semantic changes. I find the new names slightly more logical and they match the names that are already used in XZ Embedded. The name fastpos wasn't changed (not worth the hassle).
865 lines
23 KiB
C
865 lines
23 KiB
C
///////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
/// \file lzma_encoder_optimum_normal.c
|
|
//
|
|
// Author: Igor Pavlov
|
|
//
|
|
// This file has been put into the public domain.
|
|
// You can do whatever you want with this file.
|
|
//
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
|
|
#include "lzma_encoder_private.h"
|
|
#include "fastpos.h"
|
|
|
|
|
|
////////////
|
|
// Prices //
|
|
////////////
|
|
|
|
static uint32_t
|
|
get_literal_price(const lzma_coder *const coder, const uint32_t pos,
|
|
const uint32_t prev_byte, const bool match_mode,
|
|
uint32_t match_byte, uint32_t symbol)
|
|
{
|
|
const probability *const subcoder = literal_subcoder(coder->literal,
|
|
coder->literal_context_bits, coder->literal_pos_mask,
|
|
pos, prev_byte);
|
|
|
|
uint32_t price = 0;
|
|
|
|
if (!match_mode) {
|
|
price = rc_bittree_price(subcoder, 8, symbol);
|
|
} else {
|
|
uint32_t offset = 0x100;
|
|
symbol += UINT32_C(1) << 8;
|
|
|
|
do {
|
|
match_byte <<= 1;
|
|
|
|
const uint32_t match_bit = match_byte & offset;
|
|
const uint32_t subcoder_index
|
|
= offset + match_bit + (symbol >> 8);
|
|
const uint32_t bit = (symbol >> 7) & 1;
|
|
price += rc_bit_price(subcoder[subcoder_index], bit);
|
|
|
|
symbol <<= 1;
|
|
offset &= ~(match_byte ^ symbol);
|
|
|
|
} while (symbol < (UINT32_C(1) << 16));
|
|
}
|
|
|
|
return price;
|
|
}
|
|
|
|
|
|
static inline uint32_t
|
|
get_len_price(const lzma_length_encoder *const lencoder,
|
|
const uint32_t len, const uint32_t pos_state)
|
|
{
|
|
// NOTE: Unlike the other price tables, length prices are updated
|
|
// in lzma_encoder.c
|
|
return lencoder->prices[pos_state][len - MATCH_LEN_MIN];
|
|
}
|
|
|
|
|
|
static inline uint32_t
|
|
get_short_rep_price(const lzma_coder *const coder,
|
|
const lzma_lzma_state state, const uint32_t pos_state)
|
|
{
|
|
return rc_bit_0_price(coder->is_rep0[state])
|
|
+ rc_bit_0_price(coder->is_rep0_long[state][pos_state]);
|
|
}
|
|
|
|
|
|
static inline uint32_t
|
|
get_pure_rep_price(const lzma_coder *const coder, const uint32_t rep_index,
|
|
const lzma_lzma_state state, uint32_t pos_state)
|
|
{
|
|
uint32_t price;
|
|
|
|
if (rep_index == 0) {
|
|
price = rc_bit_0_price(coder->is_rep0[state]);
|
|
price += rc_bit_1_price(coder->is_rep0_long[state][pos_state]);
|
|
} else {
|
|
price = rc_bit_1_price(coder->is_rep0[state]);
|
|
|
|
if (rep_index == 1) {
|
|
price += rc_bit_0_price(coder->is_rep1[state]);
|
|
} else {
|
|
price += rc_bit_1_price(coder->is_rep1[state]);
|
|
price += rc_bit_price(coder->is_rep2[state],
|
|
rep_index - 2);
|
|
}
|
|
}
|
|
|
|
return price;
|
|
}
|
|
|
|
|
|
static inline uint32_t
|
|
get_rep_price(const lzma_coder *const coder, const uint32_t rep_index,
|
|
const uint32_t len, const lzma_lzma_state state,
|
|
const uint32_t pos_state)
|
|
{
|
|
return get_len_price(&coder->rep_len_encoder, len, pos_state)
|
|
+ get_pure_rep_price(coder, rep_index, state, pos_state);
|
|
}
|
|
|
|
|
|
static inline uint32_t
|
|
get_dist_len_price(const lzma_coder *const coder, const uint32_t dist,
|
|
const uint32_t len, const uint32_t pos_state)
|
|
{
|
|
const uint32_t dist_state = get_dist_state(len);
|
|
uint32_t price;
|
|
|
|
if (dist < FULL_DISTANCES) {
|
|
price = coder->dist_prices[dist_state][dist];
|
|
} else {
|
|
const uint32_t dist_slot = get_dist_slot_2(dist);
|
|
price = coder->dist_slot_prices[dist_state][dist_slot]
|
|
+ coder->align_prices[dist & ALIGN_MASK];
|
|
}
|
|
|
|
price += get_len_price(&coder->match_len_encoder, len, pos_state);
|
|
|
|
return price;
|
|
}
|
|
|
|
|
|
static void
|
|
fill_dist_prices(lzma_coder *coder)
|
|
{
|
|
for (uint32_t dist_state = 0; dist_state < DIST_STATES; ++dist_state) {
|
|
|
|
uint32_t *const dist_slot_prices
|
|
= coder->dist_slot_prices[dist_state];
|
|
|
|
// Price to encode the dist_slot.
|
|
for (uint32_t dist_slot = 0;
|
|
dist_slot < coder->dist_table_size; ++dist_slot)
|
|
dist_slot_prices[dist_slot] = rc_bittree_price(
|
|
coder->dist_slot[dist_state],
|
|
DIST_SLOT_BITS, dist_slot);
|
|
|
|
// For matches with distance >= FULL_DISTANCES, add the price
|
|
// of the direct bits part of the match distance. (Align bits
|
|
// are handled by fill_align_prices()).
|
|
for (uint32_t dist_slot = DIST_MODEL_END;
|
|
dist_slot < coder->dist_table_size;
|
|
++dist_slot)
|
|
dist_slot_prices[dist_slot] += rc_direct_price(
|
|
((dist_slot >> 1) - 1) - ALIGN_BITS);
|
|
|
|
// Distances in the range [0, 3] are fully encoded with
|
|
// dist_slot, so they are used for coder->dist_prices
|
|
// as is.
|
|
for (uint32_t i = 0; i < DIST_MODEL_START; ++i)
|
|
coder->dist_prices[dist_state][i]
|
|
= dist_slot_prices[i];
|
|
}
|
|
|
|
// Distances in the range [4, 127] depend on dist_slot and
|
|
// dist_special. We do this in a loop separate from the above
|
|
// loop to avoid redundant calls to get_dist_slot().
|
|
for (uint32_t i = DIST_MODEL_START; i < FULL_DISTANCES; ++i) {
|
|
const uint32_t dist_slot = get_dist_slot(i);
|
|
const uint32_t footer_bits = ((dist_slot >> 1) - 1);
|
|
const uint32_t base = (2 | (dist_slot & 1)) << footer_bits;
|
|
const uint32_t price = rc_bittree_reverse_price(
|
|
coder->dist_special + base - dist_slot - 1,
|
|
footer_bits, i - base);
|
|
|
|
for (uint32_t dist_state = 0; dist_state < DIST_STATES;
|
|
++dist_state)
|
|
coder->dist_prices[dist_state][i]
|
|
= price + coder->dist_slot_prices[
|
|
dist_state][dist_slot];
|
|
}
|
|
|
|
coder->match_price_count = 0;
|
|
return;
|
|
}
|
|
|
|
|
|
static void
|
|
fill_align_prices(lzma_coder *coder)
|
|
{
|
|
for (uint32_t i = 0; i < ALIGN_SIZE; ++i)
|
|
coder->align_prices[i] = rc_bittree_reverse_price(
|
|
coder->dist_align, ALIGN_BITS, i);
|
|
|
|
coder->align_price_count = 0;
|
|
return;
|
|
}
|
|
|
|
|
|
/////////////
|
|
// Optimal //
|
|
/////////////
|
|
|
|
static inline void
|
|
make_literal(lzma_optimal *optimal)
|
|
{
|
|
optimal->back_prev = UINT32_MAX;
|
|
optimal->prev_1_is_literal = false;
|
|
}
|
|
|
|
|
|
static inline void
|
|
make_short_rep(lzma_optimal *optimal)
|
|
{
|
|
optimal->back_prev = 0;
|
|
optimal->prev_1_is_literal = false;
|
|
}
|
|
|
|
|
|
#define is_short_rep(optimal) \
|
|
((optimal).back_prev == 0)
|
|
|
|
|
|
static void
|
|
backward(lzma_coder *restrict coder, uint32_t *restrict len_res,
|
|
uint32_t *restrict back_res, uint32_t cur)
|
|
{
|
|
coder->opts_end_index = cur;
|
|
|
|
uint32_t pos_mem = coder->opts[cur].pos_prev;
|
|
uint32_t back_mem = coder->opts[cur].back_prev;
|
|
|
|
do {
|
|
if (coder->opts[cur].prev_1_is_literal) {
|
|
make_literal(&coder->opts[pos_mem]);
|
|
coder->opts[pos_mem].pos_prev = pos_mem - 1;
|
|
|
|
if (coder->opts[cur].prev_2) {
|
|
coder->opts[pos_mem - 1].prev_1_is_literal
|
|
= false;
|
|
coder->opts[pos_mem - 1].pos_prev
|
|
= coder->opts[cur].pos_prev_2;
|
|
coder->opts[pos_mem - 1].back_prev
|
|
= coder->opts[cur].back_prev_2;
|
|
}
|
|
}
|
|
|
|
const uint32_t pos_prev = pos_mem;
|
|
const uint32_t back_cur = back_mem;
|
|
|
|
back_mem = coder->opts[pos_prev].back_prev;
|
|
pos_mem = coder->opts[pos_prev].pos_prev;
|
|
|
|
coder->opts[pos_prev].back_prev = back_cur;
|
|
coder->opts[pos_prev].pos_prev = cur;
|
|
cur = pos_prev;
|
|
|
|
} while (cur != 0);
|
|
|
|
coder->opts_current_index = coder->opts[0].pos_prev;
|
|
*len_res = coder->opts[0].pos_prev;
|
|
*back_res = coder->opts[0].back_prev;
|
|
|
|
return;
|
|
}
|
|
|
|
|
|
//////////
|
|
// Main //
|
|
//////////
|
|
|
|
static inline uint32_t
|
|
helper1(lzma_coder *restrict coder, lzma_mf *restrict mf,
|
|
uint32_t *restrict back_res, uint32_t *restrict len_res,
|
|
uint32_t position)
|
|
{
|
|
const uint32_t nice_len = mf->nice_len;
|
|
|
|
uint32_t len_main;
|
|
uint32_t matches_count;
|
|
|
|
if (mf->read_ahead == 0) {
|
|
len_main = mf_find(mf, &matches_count, coder->matches);
|
|
} else {
|
|
assert(mf->read_ahead == 1);
|
|
len_main = coder->longest_match_length;
|
|
matches_count = coder->matches_count;
|
|
}
|
|
|
|
const uint32_t buf_avail = my_min(mf_avail(mf) + 1, MATCH_LEN_MAX);
|
|
if (buf_avail < 2) {
|
|
*back_res = UINT32_MAX;
|
|
*len_res = 1;
|
|
return UINT32_MAX;
|
|
}
|
|
|
|
const uint8_t *const buf = mf_ptr(mf) - 1;
|
|
|
|
uint32_t rep_lens[REPS];
|
|
uint32_t rep_max_index = 0;
|
|
|
|
for (uint32_t i = 0; i < REPS; ++i) {
|
|
const uint8_t *const buf_back = buf - coder->reps[i] - 1;
|
|
|
|
if (not_equal_16(buf, buf_back)) {
|
|
rep_lens[i] = 0;
|
|
continue;
|
|
}
|
|
|
|
uint32_t len_test;
|
|
for (len_test = 2; len_test < buf_avail
|
|
&& buf[len_test] == buf_back[len_test];
|
|
++len_test) ;
|
|
|
|
rep_lens[i] = len_test;
|
|
if (len_test > rep_lens[rep_max_index])
|
|
rep_max_index = i;
|
|
}
|
|
|
|
if (rep_lens[rep_max_index] >= nice_len) {
|
|
*back_res = rep_max_index;
|
|
*len_res = rep_lens[rep_max_index];
|
|
mf_skip(mf, *len_res - 1);
|
|
return UINT32_MAX;
|
|
}
|
|
|
|
|
|
if (len_main >= nice_len) {
|
|
*back_res = coder->matches[matches_count - 1].dist + REPS;
|
|
*len_res = len_main;
|
|
mf_skip(mf, len_main - 1);
|
|
return UINT32_MAX;
|
|
}
|
|
|
|
const uint8_t current_byte = *buf;
|
|
const uint8_t match_byte = *(buf - coder->reps[0] - 1);
|
|
|
|
if (len_main < 2 && current_byte != match_byte
|
|
&& rep_lens[rep_max_index] < 2) {
|
|
*back_res = UINT32_MAX;
|
|
*len_res = 1;
|
|
return UINT32_MAX;
|
|
}
|
|
|
|
coder->opts[0].state = coder->state;
|
|
|
|
const uint32_t pos_state = position & coder->pos_mask;
|
|
|
|
coder->opts[1].price = rc_bit_0_price(
|
|
coder->is_match[coder->state][pos_state])
|
|
+ get_literal_price(coder, position, buf[-1],
|
|
!is_literal_state(coder->state),
|
|
match_byte, current_byte);
|
|
|
|
make_literal(&coder->opts[1]);
|
|
|
|
const uint32_t match_price = rc_bit_1_price(
|
|
coder->is_match[coder->state][pos_state]);
|
|
const uint32_t rep_match_price = match_price
|
|
+ rc_bit_1_price(coder->is_rep[coder->state]);
|
|
|
|
if (match_byte == current_byte) {
|
|
const uint32_t short_rep_price = rep_match_price
|
|
+ get_short_rep_price(
|
|
coder, coder->state, pos_state);
|
|
|
|
if (short_rep_price < coder->opts[1].price) {
|
|
coder->opts[1].price = short_rep_price;
|
|
make_short_rep(&coder->opts[1]);
|
|
}
|
|
}
|
|
|
|
const uint32_t len_end = my_max(len_main, rep_lens[rep_max_index]);
|
|
|
|
if (len_end < 2) {
|
|
*back_res = coder->opts[1].back_prev;
|
|
*len_res = 1;
|
|
return UINT32_MAX;
|
|
}
|
|
|
|
coder->opts[1].pos_prev = 0;
|
|
|
|
for (uint32_t i = 0; i < REPS; ++i)
|
|
coder->opts[0].backs[i] = coder->reps[i];
|
|
|
|
uint32_t len = len_end;
|
|
do {
|
|
coder->opts[len].price = RC_INFINITY_PRICE;
|
|
} while (--len >= 2);
|
|
|
|
|
|
for (uint32_t i = 0; i < REPS; ++i) {
|
|
uint32_t rep_len = rep_lens[i];
|
|
if (rep_len < 2)
|
|
continue;
|
|
|
|
const uint32_t price = rep_match_price + get_pure_rep_price(
|
|
coder, i, coder->state, pos_state);
|
|
|
|
do {
|
|
const uint32_t cur_and_len_price = price
|
|
+ get_len_price(
|
|
&coder->rep_len_encoder,
|
|
rep_len, pos_state);
|
|
|
|
if (cur_and_len_price < coder->opts[rep_len].price) {
|
|
coder->opts[rep_len].price = cur_and_len_price;
|
|
coder->opts[rep_len].pos_prev = 0;
|
|
coder->opts[rep_len].back_prev = i;
|
|
coder->opts[rep_len].prev_1_is_literal = false;
|
|
}
|
|
} while (--rep_len >= 2);
|
|
}
|
|
|
|
|
|
const uint32_t normal_match_price = match_price
|
|
+ rc_bit_0_price(coder->is_rep[coder->state]);
|
|
|
|
len = rep_lens[0] >= 2 ? rep_lens[0] + 1 : 2;
|
|
if (len <= len_main) {
|
|
uint32_t i = 0;
|
|
while (len > coder->matches[i].len)
|
|
++i;
|
|
|
|
for(; ; ++len) {
|
|
const uint32_t dist = coder->matches[i].dist;
|
|
const uint32_t cur_and_len_price = normal_match_price
|
|
+ get_dist_len_price(coder,
|
|
dist, len, pos_state);
|
|
|
|
if (cur_and_len_price < coder->opts[len].price) {
|
|
coder->opts[len].price = cur_and_len_price;
|
|
coder->opts[len].pos_prev = 0;
|
|
coder->opts[len].back_prev = dist + REPS;
|
|
coder->opts[len].prev_1_is_literal = false;
|
|
}
|
|
|
|
if (len == coder->matches[i].len)
|
|
if (++i == matches_count)
|
|
break;
|
|
}
|
|
}
|
|
|
|
return len_end;
|
|
}
|
|
|
|
|
|
static inline uint32_t
|
|
helper2(lzma_coder *coder, uint32_t *reps, const uint8_t *buf,
|
|
uint32_t len_end, uint32_t position, const uint32_t cur,
|
|
const uint32_t nice_len, const uint32_t buf_avail_full)
|
|
{
|
|
uint32_t matches_count = coder->matches_count;
|
|
uint32_t new_len = coder->longest_match_length;
|
|
uint32_t pos_prev = coder->opts[cur].pos_prev;
|
|
lzma_lzma_state state;
|
|
|
|
if (coder->opts[cur].prev_1_is_literal) {
|
|
--pos_prev;
|
|
|
|
if (coder->opts[cur].prev_2) {
|
|
state = coder->opts[coder->opts[cur].pos_prev_2].state;
|
|
|
|
if (coder->opts[cur].back_prev_2 < REPS)
|
|
update_long_rep(state);
|
|
else
|
|
update_match(state);
|
|
|
|
} else {
|
|
state = coder->opts[pos_prev].state;
|
|
}
|
|
|
|
update_literal(state);
|
|
|
|
} else {
|
|
state = coder->opts[pos_prev].state;
|
|
}
|
|
|
|
if (pos_prev == cur - 1) {
|
|
if (is_short_rep(coder->opts[cur]))
|
|
update_short_rep(state);
|
|
else
|
|
update_literal(state);
|
|
} else {
|
|
uint32_t pos;
|
|
if (coder->opts[cur].prev_1_is_literal
|
|
&& coder->opts[cur].prev_2) {
|
|
pos_prev = coder->opts[cur].pos_prev_2;
|
|
pos = coder->opts[cur].back_prev_2;
|
|
update_long_rep(state);
|
|
} else {
|
|
pos = coder->opts[cur].back_prev;
|
|
if (pos < REPS)
|
|
update_long_rep(state);
|
|
else
|
|
update_match(state);
|
|
}
|
|
|
|
if (pos < REPS) {
|
|
reps[0] = coder->opts[pos_prev].backs[pos];
|
|
|
|
uint32_t i;
|
|
for (i = 1; i <= pos; ++i)
|
|
reps[i] = coder->opts[pos_prev].backs[i - 1];
|
|
|
|
for (; i < REPS; ++i)
|
|
reps[i] = coder->opts[pos_prev].backs[i];
|
|
|
|
} else {
|
|
reps[0] = pos - REPS;
|
|
|
|
for (uint32_t i = 1; i < REPS; ++i)
|
|
reps[i] = coder->opts[pos_prev].backs[i - 1];
|
|
}
|
|
}
|
|
|
|
coder->opts[cur].state = state;
|
|
|
|
for (uint32_t i = 0; i < REPS; ++i)
|
|
coder->opts[cur].backs[i] = reps[i];
|
|
|
|
const uint32_t cur_price = coder->opts[cur].price;
|
|
|
|
const uint8_t current_byte = *buf;
|
|
const uint8_t match_byte = *(buf - reps[0] - 1);
|
|
|
|
const uint32_t pos_state = position & coder->pos_mask;
|
|
|
|
const uint32_t cur_and_1_price = cur_price
|
|
+ rc_bit_0_price(coder->is_match[state][pos_state])
|
|
+ get_literal_price(coder, position, buf[-1],
|
|
!is_literal_state(state), match_byte, current_byte);
|
|
|
|
bool next_is_literal = false;
|
|
|
|
if (cur_and_1_price < coder->opts[cur + 1].price) {
|
|
coder->opts[cur + 1].price = cur_and_1_price;
|
|
coder->opts[cur + 1].pos_prev = cur;
|
|
make_literal(&coder->opts[cur + 1]);
|
|
next_is_literal = true;
|
|
}
|
|
|
|
const uint32_t match_price = cur_price
|
|
+ rc_bit_1_price(coder->is_match[state][pos_state]);
|
|
const uint32_t rep_match_price = match_price
|
|
+ rc_bit_1_price(coder->is_rep[state]);
|
|
|
|
if (match_byte == current_byte
|
|
&& !(coder->opts[cur + 1].pos_prev < cur
|
|
&& coder->opts[cur + 1].back_prev == 0)) {
|
|
|
|
const uint32_t short_rep_price = rep_match_price
|
|
+ get_short_rep_price(coder, state, pos_state);
|
|
|
|
if (short_rep_price <= coder->opts[cur + 1].price) {
|
|
coder->opts[cur + 1].price = short_rep_price;
|
|
coder->opts[cur + 1].pos_prev = cur;
|
|
make_short_rep(&coder->opts[cur + 1]);
|
|
next_is_literal = true;
|
|
}
|
|
}
|
|
|
|
if (buf_avail_full < 2)
|
|
return len_end;
|
|
|
|
const uint32_t buf_avail = my_min(buf_avail_full, nice_len);
|
|
|
|
if (!next_is_literal && match_byte != current_byte) { // speed optimization
|
|
// try literal + rep0
|
|
const uint8_t *const buf_back = buf - reps[0] - 1;
|
|
const uint32_t limit = my_min(buf_avail_full, nice_len + 1);
|
|
|
|
uint32_t len_test = 1;
|
|
while (len_test < limit && buf[len_test] == buf_back[len_test])
|
|
++len_test;
|
|
|
|
--len_test;
|
|
|
|
if (len_test >= 2) {
|
|
lzma_lzma_state state_2 = state;
|
|
update_literal(state_2);
|
|
|
|
const uint32_t pos_state_next = (position + 1) & coder->pos_mask;
|
|
const uint32_t next_rep_match_price = cur_and_1_price
|
|
+ rc_bit_1_price(coder->is_match[state_2][pos_state_next])
|
|
+ rc_bit_1_price(coder->is_rep[state_2]);
|
|
|
|
//for (; len_test >= 2; --len_test) {
|
|
const uint32_t offset = cur + 1 + len_test;
|
|
|
|
while (len_end < offset)
|
|
coder->opts[++len_end].price = RC_INFINITY_PRICE;
|
|
|
|
const uint32_t cur_and_len_price = next_rep_match_price
|
|
+ get_rep_price(coder, 0, len_test,
|
|
state_2, pos_state_next);
|
|
|
|
if (cur_and_len_price < coder->opts[offset].price) {
|
|
coder->opts[offset].price = cur_and_len_price;
|
|
coder->opts[offset].pos_prev = cur + 1;
|
|
coder->opts[offset].back_prev = 0;
|
|
coder->opts[offset].prev_1_is_literal = true;
|
|
coder->opts[offset].prev_2 = false;
|
|
}
|
|
//}
|
|
}
|
|
}
|
|
|
|
|
|
uint32_t start_len = 2; // speed optimization
|
|
|
|
for (uint32_t rep_index = 0; rep_index < REPS; ++rep_index) {
|
|
const uint8_t *const buf_back = buf - reps[rep_index] - 1;
|
|
if (not_equal_16(buf, buf_back))
|
|
continue;
|
|
|
|
uint32_t len_test;
|
|
for (len_test = 2; len_test < buf_avail
|
|
&& buf[len_test] == buf_back[len_test];
|
|
++len_test) ;
|
|
|
|
while (len_end < cur + len_test)
|
|
coder->opts[++len_end].price = RC_INFINITY_PRICE;
|
|
|
|
const uint32_t len_test_temp = len_test;
|
|
const uint32_t price = rep_match_price + get_pure_rep_price(
|
|
coder, rep_index, state, pos_state);
|
|
|
|
do {
|
|
const uint32_t cur_and_len_price = price
|
|
+ get_len_price(&coder->rep_len_encoder,
|
|
len_test, pos_state);
|
|
|
|
if (cur_and_len_price < coder->opts[cur + len_test].price) {
|
|
coder->opts[cur + len_test].price = cur_and_len_price;
|
|
coder->opts[cur + len_test].pos_prev = cur;
|
|
coder->opts[cur + len_test].back_prev = rep_index;
|
|
coder->opts[cur + len_test].prev_1_is_literal = false;
|
|
}
|
|
} while (--len_test >= 2);
|
|
|
|
len_test = len_test_temp;
|
|
|
|
if (rep_index == 0)
|
|
start_len = len_test + 1;
|
|
|
|
|
|
uint32_t len_test_2 = len_test + 1;
|
|
const uint32_t limit = my_min(buf_avail_full,
|
|
len_test_2 + nice_len);
|
|
for (; len_test_2 < limit
|
|
&& buf[len_test_2] == buf_back[len_test_2];
|
|
++len_test_2) ;
|
|
|
|
len_test_2 -= len_test + 1;
|
|
|
|
if (len_test_2 >= 2) {
|
|
lzma_lzma_state state_2 = state;
|
|
update_long_rep(state_2);
|
|
|
|
uint32_t pos_state_next = (position + len_test) & coder->pos_mask;
|
|
|
|
const uint32_t cur_and_len_literal_price = price
|
|
+ get_len_price(&coder->rep_len_encoder,
|
|
len_test, pos_state)
|
|
+ rc_bit_0_price(coder->is_match[state_2][pos_state_next])
|
|
+ get_literal_price(coder, position + len_test,
|
|
buf[len_test - 1], true,
|
|
buf_back[len_test], buf[len_test]);
|
|
|
|
update_literal(state_2);
|
|
|
|
pos_state_next = (position + len_test + 1) & coder->pos_mask;
|
|
|
|
const uint32_t next_rep_match_price = cur_and_len_literal_price
|
|
+ rc_bit_1_price(coder->is_match[state_2][pos_state_next])
|
|
+ rc_bit_1_price(coder->is_rep[state_2]);
|
|
|
|
//for(; len_test_2 >= 2; len_test_2--) {
|
|
const uint32_t offset = cur + len_test + 1 + len_test_2;
|
|
|
|
while (len_end < offset)
|
|
coder->opts[++len_end].price = RC_INFINITY_PRICE;
|
|
|
|
const uint32_t cur_and_len_price = next_rep_match_price
|
|
+ get_rep_price(coder, 0, len_test_2,
|
|
state_2, pos_state_next);
|
|
|
|
if (cur_and_len_price < coder->opts[offset].price) {
|
|
coder->opts[offset].price = cur_and_len_price;
|
|
coder->opts[offset].pos_prev = cur + len_test + 1;
|
|
coder->opts[offset].back_prev = 0;
|
|
coder->opts[offset].prev_1_is_literal = true;
|
|
coder->opts[offset].prev_2 = true;
|
|
coder->opts[offset].pos_prev_2 = cur;
|
|
coder->opts[offset].back_prev_2 = rep_index;
|
|
}
|
|
//}
|
|
}
|
|
}
|
|
|
|
|
|
//for (uint32_t len_test = 2; len_test <= new_len; ++len_test)
|
|
if (new_len > buf_avail) {
|
|
new_len = buf_avail;
|
|
|
|
matches_count = 0;
|
|
while (new_len > coder->matches[matches_count].len)
|
|
++matches_count;
|
|
|
|
coder->matches[matches_count++].len = new_len;
|
|
}
|
|
|
|
|
|
if (new_len >= start_len) {
|
|
const uint32_t normal_match_price = match_price
|
|
+ rc_bit_0_price(coder->is_rep[state]);
|
|
|
|
while (len_end < cur + new_len)
|
|
coder->opts[++len_end].price = RC_INFINITY_PRICE;
|
|
|
|
uint32_t i = 0;
|
|
while (start_len > coder->matches[i].len)
|
|
++i;
|
|
|
|
for (uint32_t len_test = start_len; ; ++len_test) {
|
|
const uint32_t cur_back = coder->matches[i].dist;
|
|
uint32_t cur_and_len_price = normal_match_price
|
|
+ get_dist_len_price(coder,
|
|
cur_back, len_test, pos_state);
|
|
|
|
if (cur_and_len_price < coder->opts[cur + len_test].price) {
|
|
coder->opts[cur + len_test].price = cur_and_len_price;
|
|
coder->opts[cur + len_test].pos_prev = cur;
|
|
coder->opts[cur + len_test].back_prev
|
|
= cur_back + REPS;
|
|
coder->opts[cur + len_test].prev_1_is_literal = false;
|
|
}
|
|
|
|
if (len_test == coder->matches[i].len) {
|
|
// Try Match + Literal + Rep0
|
|
const uint8_t *const buf_back = buf - cur_back - 1;
|
|
uint32_t len_test_2 = len_test + 1;
|
|
const uint32_t limit = my_min(buf_avail_full,
|
|
len_test_2 + nice_len);
|
|
|
|
for (; len_test_2 < limit &&
|
|
buf[len_test_2] == buf_back[len_test_2];
|
|
++len_test_2) ;
|
|
|
|
len_test_2 -= len_test + 1;
|
|
|
|
if (len_test_2 >= 2) {
|
|
lzma_lzma_state state_2 = state;
|
|
update_match(state_2);
|
|
uint32_t pos_state_next
|
|
= (position + len_test) & coder->pos_mask;
|
|
|
|
const uint32_t cur_and_len_literal_price = cur_and_len_price
|
|
+ rc_bit_0_price(
|
|
coder->is_match[state_2][pos_state_next])
|
|
+ get_literal_price(coder,
|
|
position + len_test,
|
|
buf[len_test - 1],
|
|
true,
|
|
buf_back[len_test],
|
|
buf[len_test]);
|
|
|
|
update_literal(state_2);
|
|
pos_state_next = (pos_state_next + 1) & coder->pos_mask;
|
|
|
|
const uint32_t next_rep_match_price
|
|
= cur_and_len_literal_price
|
|
+ rc_bit_1_price(
|
|
coder->is_match[state_2][pos_state_next])
|
|
+ rc_bit_1_price(coder->is_rep[state_2]);
|
|
|
|
// for(; len_test_2 >= 2; --len_test_2) {
|
|
const uint32_t offset = cur + len_test + 1 + len_test_2;
|
|
|
|
while (len_end < offset)
|
|
coder->opts[++len_end].price = RC_INFINITY_PRICE;
|
|
|
|
cur_and_len_price = next_rep_match_price
|
|
+ get_rep_price(coder, 0, len_test_2,
|
|
state_2, pos_state_next);
|
|
|
|
if (cur_and_len_price < coder->opts[offset].price) {
|
|
coder->opts[offset].price = cur_and_len_price;
|
|
coder->opts[offset].pos_prev = cur + len_test + 1;
|
|
coder->opts[offset].back_prev = 0;
|
|
coder->opts[offset].prev_1_is_literal = true;
|
|
coder->opts[offset].prev_2 = true;
|
|
coder->opts[offset].pos_prev_2 = cur;
|
|
coder->opts[offset].back_prev_2
|
|
= cur_back + REPS;
|
|
}
|
|
//}
|
|
}
|
|
|
|
if (++i == matches_count)
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
return len_end;
|
|
}
|
|
|
|
|
|
extern void
|
|
lzma_lzma_optimum_normal(lzma_coder *restrict coder, lzma_mf *restrict mf,
|
|
uint32_t *restrict back_res, uint32_t *restrict len_res,
|
|
uint32_t position)
|
|
{
|
|
// If we have symbols pending, return the next pending symbol.
|
|
if (coder->opts_end_index != coder->opts_current_index) {
|
|
assert(mf->read_ahead > 0);
|
|
*len_res = coder->opts[coder->opts_current_index].pos_prev
|
|
- coder->opts_current_index;
|
|
*back_res = coder->opts[coder->opts_current_index].back_prev;
|
|
coder->opts_current_index = coder->opts[
|
|
coder->opts_current_index].pos_prev;
|
|
return;
|
|
}
|
|
|
|
// Update the price tables. In LZMA SDK <= 4.60 (and possibly later)
|
|
// this was done in both initialization function and in the main loop.
|
|
// In liblzma they were moved into this single place.
|
|
if (mf->read_ahead == 0) {
|
|
if (coder->match_price_count >= (1 << 7))
|
|
fill_dist_prices(coder);
|
|
|
|
if (coder->align_price_count >= ALIGN_SIZE)
|
|
fill_align_prices(coder);
|
|
}
|
|
|
|
// TODO: This needs quite a bit of cleaning still. But splitting
|
|
// the original function into two pieces makes it at least a little
|
|
// more readable, since those two parts don't share many variables.
|
|
|
|
uint32_t len_end = helper1(coder, mf, back_res, len_res, position);
|
|
if (len_end == UINT32_MAX)
|
|
return;
|
|
|
|
uint32_t reps[REPS];
|
|
memcpy(reps, coder->reps, sizeof(reps));
|
|
|
|
uint32_t cur;
|
|
for (cur = 1; cur < len_end; ++cur) {
|
|
assert(cur < OPTS);
|
|
|
|
coder->longest_match_length = mf_find(
|
|
mf, &coder->matches_count, coder->matches);
|
|
|
|
if (coder->longest_match_length >= mf->nice_len)
|
|
break;
|
|
|
|
len_end = helper2(coder, reps, mf_ptr(mf) - 1, len_end,
|
|
position + cur, cur, mf->nice_len,
|
|
my_min(mf_avail(mf) + 1, OPTS - 1 - cur));
|
|
}
|
|
|
|
backward(coder, len_res, back_res, cur);
|
|
return;
|
|
}
|