* cache. However, fallback behavior (immediately terminating the block) on
* cache overflow is still required.
*/
-#define LZX_CACHE_PER_POS 6
+#define LZX_CACHE_PER_POS 7
/*
* LZX_CACHE_LENGTH is the number of lz_match structures in the match cache,
/*
* LZX_BIT_COST is a scaling factor that represents the cost to output one bit.
- * THis makes it possible to consider fractional bit costs.
+ * This makes it possible to consider fractional bit costs.
*
* Note: this is only useful as a statistical trick for when the true costs are
* unknown. In reality, each token in LZX requires a whole number of bits to
/*
* LZX_HASH2_ORDER is the log base 2 of the number of entries in the hash table
* for finding length 2 matches. This can be as high as 16 (in which case the
- * hash function is trivial), but using a smaller hash table actually speeds up
+ * hash function is trivial), but using a smaller hash table speeds up
* compression due to reduced cache pressure.
*/
#define LZX_HASH2_ORDER 12
/* Pointer to the compress() implementation chosen at allocation time */
void (*impl)(struct lzx_compressor *, struct lzx_output_bitstream *);
+ /* If true, the compressor need not preserve the input buffer if it
+ * compresses the data successfully. */
+ bool destructive;
+
/* The Huffman symbol frequency counters for the current block. */
struct lzx_freqs freqs;
* contains the number of matches that were found at
* that position; this is followed by the matches
* themselves, if any, sorted by strictly increasing
- * length and strictly increasing offset.
+ * length.
*
* Note: in rare cases, there will be a very high number
* of matches in the block and this array will overflow.
LZX_MAX_MATCH_LEN - 1];
/* Hash table for finding length 2 matches */
- pos_t hash2_tab[LZX_HASH2_LENGTH]
- _aligned_attribute(MATCHFINDER_ALIGNMENT);
+ pos_t hash2_tab[LZX_HASH2_LENGTH];
/* Binary trees matchfinder (MUST BE LAST!!!) */
struct bt_matchfinder bt_mf;
extra_bits = (offset + LZX_OFFSET_ADJUSTMENT) -
lzx_offset_slot_base[offset_slot];
- BUILD_BUG_ON(LZX_MAINCODE_MAX_NUM_SYMBOLS > (1 << 10));
- BUILD_BUG_ON(LZX_LENCODE_NUM_SYMBOLS > (1 << 8));
+ STATIC_ASSERT(LZX_MAINCODE_MAX_NUM_SYMBOLS <= (1 << 10));
+ STATIC_ASSERT(LZX_LENCODE_NUM_SYMBOLS <= (1 << 8));
*(*next_chosen_item)++ = (struct lzx_item) {
.data = (u64)main_symbol |
((u64)len_symbol << 10) |
* it is no longer needed. */
struct lzx_lru_queue queues[512];
- BUILD_BUG_ON(ARRAY_LEN(queues) < LZX_MAX_MATCH_LEN + 1);
+ STATIC_ASSERT(ARRAY_LEN(queues) >= LZX_MAX_MATCH_LEN + 1);
#define QUEUE(in) (queues[(uintptr_t)(in) % ARRAY_LEN(queues)])
/* Initially, the cost to reach each node is "infinity". */
matchptr = in_next - lzx_lru_queue_R0(QUEUE(in_next));
if (load_u16_unaligned(matchptr) != load_u16_unaligned(in_next))
goto R0_done;
- BUILD_BUG_ON(LZX_MIN_MATCH_LEN != 2);
+ STATIC_ASSERT(LZX_MIN_MATCH_LEN == 2);
do {
u32 cost = cur_node->cost +
c->costs.match_cost[0][
unsigned num_used_bytes;
/* The costs below are hard coded to use a scaling factor of 16. */
- BUILD_BUG_ON(LZX_BIT_COST != 16);
+ STATIC_ASSERT(LZX_BIT_COST == 16);
/*
* Heuristics:
struct lzx_lru_queue queue;
bt_matchfinder_init(&c->bt_mf);
- matchfinder_init(c->hash2_tab, LZX_HASH2_LENGTH);
+ memset(c->hash2_tab, 0, sizeof(c->hash2_tab));
next_hash = bt_matchfinder_hash_3_bytes(in_next);
lzx_lru_queue_init(&queue);
max_len = in_end - in_next;
nice_len = min(max_len, nice_len);
- /* This extra check is needed to ensure that
- * reading the next 3 bytes when looking for a
- * length 2 match is valid. In addition, we
- * cannot allow ourselves to find a length 2
- * match of the very last two bytes with the
- * very first two bytes, since such a match has
- * an offset too large to be represented. */
+ /* This extra check is needed to ensure that we
+ * never output a length 2 match of the very
+ * last two bytes with the very first two bytes,
+ * since such a match has an offset too large to
+ * be represented. */
if (unlikely(max_len < 3)) {
in_next++;
cache_ptr->length = 0;
hash2 = lz_hash_2_bytes(in_next, LZX_HASH2_ORDER);
cur_match = c->hash2_tab[hash2];
c->hash2_tab[hash2] = in_next - in_begin;
- if (matchfinder_node_valid(cur_match) &&
+ if (cur_match != 0 &&
(LZX_HASH2_ORDER == 16 ||
load_u16_unaligned(&in_begin[cur_match]) ==
- load_u16_unaligned(in_next)) &&
- in_begin[cur_match + 2] != in_next[2])
+ load_u16_unaligned(in_next)))
{
lz_matchptr->length = 2;
lz_matchptr->offset = in_next - &in_begin[cur_match];
struct lzx_lru_queue queue,
unsigned *rep_max_idx_ret)
{
- BUILD_BUG_ON(LZX_NUM_RECENT_OFFSETS != 3);
+ STATIC_ASSERT(LZX_NUM_RECENT_OFFSETS == 3);
LZX_ASSERT(bytes_remaining >= 2);
const unsigned max_len = min(bytes_remaining, LZX_MAX_MATCH_LEN);
}
static u64
-lzx_get_needed_memory(size_t max_bufsize, unsigned compression_level)
+lzx_get_needed_memory(size_t max_bufsize, unsigned compression_level,
+ bool destructive)
{
u64 size = 0;
return 0;
size += lzx_get_compressor_size(max_bufsize, compression_level);
- size += max_bufsize; /* in_buffer */
+ if (!destructive)
+ size += max_bufsize; /* in_buffer */
return size;
}
static int
lzx_create_compressor(size_t max_bufsize, unsigned compression_level,
- void **c_ret)
+ bool destructive, void **c_ret)
{
unsigned window_order;
struct lzx_compressor *c;
if (window_order == 0)
return WIMLIB_ERR_INVALID_PARAM;
- c = ALIGNED_MALLOC(lzx_get_compressor_size(max_bufsize,
- compression_level),
- MATCHFINDER_ALIGNMENT);
+ c = MALLOC(lzx_get_compressor_size(max_bufsize, compression_level));
if (!c)
goto oom0;
+ c->destructive = destructive;
+
c->num_main_syms = lzx_get_num_main_syms(window_order);
c->window_order = window_order;
- c->in_buffer = MALLOC(max_bufsize);
- if (!c->in_buffer)
- goto oom1;
+ if (!c->destructive) {
+ c->in_buffer = MALLOC(max_bufsize);
+ if (!c->in_buffer)
+ goto oom1;
+ }
if (compression_level <= LZX_MAX_FAST_LEVEL) {
return 0;
oom1:
- ALIGNED_FREE(c);
+ FREE(c);
oom0:
return WIMLIB_ERR_NOMEM;
}
static size_t
-lzx_compress(const void *in, size_t in_nbytes,
- void *out, size_t out_nbytes_avail, void *_c)
+lzx_compress(const void *restrict in, size_t in_nbytes,
+ void *restrict out, size_t out_nbytes_avail, void *restrict _c)
{
struct lzx_compressor *c = _c;
struct lzx_output_bitstream os;
+ size_t result;
/* Don't bother trying to compress very small inputs. */
if (in_nbytes < 100)
return 0;
/* Copy the input data into the internal buffer and preprocess it. */
- memcpy(c->in_buffer, in, in_nbytes);
+ if (c->destructive)
+ c->in_buffer = (void *)in;
+ else
+ memcpy(c->in_buffer, in, in_nbytes);
c->in_nbytes = in_nbytes;
lzx_do_e8_preprocessing(c->in_buffer, in_nbytes);
(*c->impl)(c, &os);
/* Flush the output bitstream and return the compressed size or 0. */
- return lzx_flush_output(&os);
+ result = lzx_flush_output(&os);
+ if (!result && c->destructive)
+ lzx_undo_e8_preprocessing(c->in_buffer, c->in_nbytes);
+ return result;
}
static void
{
struct lzx_compressor *c = _c;
- FREE(c->in_buffer);
- ALIGNED_FREE(c);
+ if (!c->destructive)
+ FREE(c->in_buffer);
+ FREE(c);
}
const struct compressor_ops lzx_compressor_ops = {