* 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.
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;
if (matchfinder_node_valid(cur_match) &&
(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];
}
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 (!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) {
{
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);
+ if (!c->destructive)
+ FREE(c->in_buffer);
ALIGNED_FREE(c);
}