zupt/src/vv_encoder.c

653 lines
26 KiB
C
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/* VaptVupt codec — originally Apache-2.0 by Cristian Cezar Moisés
* Integrated into Zupt — MIT License
* Copyright (c) 2026 Cristian Cezar Moisés
* SPDX-License-Identifier: MIT AND Apache-2.0
*/
#if !defined(_DEFAULT_SOURCE) && !defined(_GNU_SOURCE)
#define _DEFAULT_SOURCE 1
#endif
/*
* VaptVupt — Encoder v2 (Sprint 1)
*
* KEY CHANGES:
* 1. 5-byte multiply-shift hash (fewer collisions than 4-byte)
* 2. Rep-match: check 3 recent offsets before hash probe (30% hit rate)
* 3. Match-skip: after long matches, only insert boundary positions
* 4. AVX2 match extension: 32 bytes/cycle vs 1 byte/cycle scalar
* 5. Lazy-2 parsing for balanced mode (check pos+1 AND pos+2)
* 6. Extreme mode: deeper chains (256) + lazy-2
*/
#include "vaptvupt.h"
#include "vv_huffman.h"
#include "vv_ans.h"
#include <stdlib.h>
#include <string.h>
#if defined(__x86_64__) && defined(__AVX2__)
#include <immintrin.h>
#define VV_ENC_AVX2 1
#else
#define VV_ENC_AVX2 0
#endif
/* ═══════════════════════════════════════════════════════════════
* VARINT WRITER
* ═══════════════════════════════════════════════════════════════ */
static inline size_t write_varint(uint8_t *dst, size_t val) {
size_t n = 0;
while (val >= 255) { dst[n++] = 255; val -= 255; }
dst[n++] = (uint8_t)val;
return n;
}
/* ═══════════════════════════════════════════════════════════════
* IMPROVED HASH: 5-byte multiply-shift (safe read pattern)
*
* Reads exactly 5 bytes using 4+1 to prevent compiler from
* widening to an 8-byte load that over-reads the buffer.
* ═══════════════════════════════════════════════════════════════ */
static inline uint32_t hash5(const uint8_t *p) {
uint32_t lo;
__builtin_memcpy(&lo, p, 4);
uint64_t v = (uint64_t)lo | ((uint64_t)p[4] << 32);
/* Shift by (64 - HC_BITS) to get the top HC_BITS of the product */
return (uint32_t)((v * 889523592379ULL) >> (64 - VV_HC_BITS));
}
/* 4-byte hash for positions near end of buffer */
static inline uint32_t hash4(const uint8_t *p) {
uint32_t v;
__builtin_memcpy(&v, p, 4);
return (v * 2654435761u) >> (32 - VV_HC_BITS);
}
/* Safe hash: picks 5-byte or 4-byte depending on remaining bytes */
static inline uint32_t hash_safe(const uint8_t *p, int32_t remain) {
return (remain >= 5) ? hash5(p) : hash4(p);
}
/* ═══════════════════════════════════════════════════════════════
* AVX2 MATCH EXTENSION
*
* Compare 32 bytes at a time. Returns total match length.
* ~8× faster than byte-by-byte on data with long matches.
* ═══════════════════════════════════════════════════════════════ */
static inline int32_t extend_match(const uint8_t *a, const uint8_t *b,
int32_t max_len) {
int32_t len = 0;
#if VV_ENC_AVX2
while (len + 32 <= max_len) {
__m256i va = _mm256_loadu_si256((const __m256i *)(a + len));
__m256i vb = _mm256_loadu_si256((const __m256i *)(b + len));
__m256i eq = _mm256_cmpeq_epi8(va, vb);
uint32_t mask = ~(uint32_t)_mm256_movemask_epi8(eq);
if (mask) return len + (int32_t)__builtin_ctz(mask);
len += 32;
}
#endif
while (len < max_len && a[len] == b[len]) len++;
return len;
}
/* ═══════════════════════════════════════════════════════════════
* MATCHER: hash chain with 5-byte hash + rep-match
* ═══════════════════════════════════════════════════════════════ */
typedef struct {
int32_t *table; /* Primary: VV_HC_SIZE entries (hash5) */
int32_t *chain; /* Chain array: window_size entries */
uint32_t chain_mask;
uint32_t chain_depth;
uint32_t rep[3]; /* 3 most recent match offsets */
uint8_t wlog; /* Window log: controls max offset distance */
} matcher_t;
static void matcher_init(matcher_t *m, uint32_t window_log, uint32_t depth) {
uint32_t wsz = 1u << window_log;
m->table = (int32_t *)malloc(VV_HC_SIZE * sizeof(int32_t));
m->chain = (int32_t *)malloc(wsz * sizeof(int32_t));
memset(m->table, 0xFF, VV_HC_SIZE * sizeof(int32_t));
memset(m->chain, 0xFF, wsz * sizeof(int32_t));
m->chain_mask = wsz - 1;
m->chain_depth = depth;
m->rep[0] = m->rep[1] = m->rep[2] = 0;
m->wlog = (uint8_t)window_log;
}
static void matcher_free(matcher_t *m) {
free(m->table); m->table = NULL;
free(m->chain); m->chain = NULL;
}
static inline void matcher_insert(matcher_t *m, const uint8_t *data,
int32_t pos, int32_t end) {
if (pos + 4 > end) return;
uint32_t h = hash_safe(data + pos, end - pos);
m->chain[pos & m->chain_mask] = m->table[h];
m->table[h] = pos;
}
/* ─── Rep-match check: O(1), checked BEFORE hash probe ─── */
static inline int32_t try_rep_match(const matcher_t *m, const uint8_t *data,
int32_t pos, int32_t end,
int32_t *rep_idx) {
for (int i = 0; i < 3; i++) {
uint32_t d = m->rep[i];
if (d == 0 || (uint32_t)pos < d) continue;
int32_t ref = pos - (int32_t)d;
uint32_t a, b;
__builtin_memcpy(&a, data + pos, 4);
__builtin_memcpy(&b, data + ref, 4);
if (a == b) {
int32_t max = end - pos;
if (max > VV_MAX_MATCH) max = VV_MAX_MATCH;
int32_t len = 4 + extend_match(data + pos + 4, data + ref + 4, max - 4);
*rep_idx = i;
return len;
}
}
return 0;
}
/* ─── Hash chain match: DUAL HASH (hash5 + hash4) for binary coverage ─── */
static int32_t chain_match(const matcher_t *m, const uint8_t *data,
int32_t pos, int32_t end, int32_t *best_off) {
if (pos + 4 > end) return 0;
int32_t best_len = 0;
*best_off = 0;
int32_t max_dist = (int32_t)((1u << m->wlog) - 1);
int32_t limit = pos - max_dist;
if (limit < 0) limit = 0;
/* Primary hash5 chain traversal */
uint32_t h = hash_safe(data + pos, end - pos);
int32_t ref = m->table[h];
uint32_t depth = m->chain_depth;
while (ref >= 0 && ref >= limit && ref < pos && depth-- > 0) {
uint32_t a, b;
__builtin_memcpy(&a, data + pos, 4);
__builtin_memcpy(&b, data + ref, 4);
if (a == b) {
int32_t max = end - pos;
if (max > VV_MAX_MATCH) max = VV_MAX_MATCH;
int32_t len = 4 + extend_match(data + pos + 4, data + ref + 4, max - 4);
if (len > best_len) {
best_len = len;
*best_off = pos - ref;
if (len >= 256) return best_len;
}
}
ref = m->chain[ref & m->chain_mask];
}
return best_len;
}
/* Update rep offsets (push new offset, shift others down) */
static inline void update_rep(matcher_t *m, uint32_t offset) {
if (offset == m->rep[0]) return;
m->rep[2] = m->rep[1];
m->rep[1] = m->rep[0];
m->rep[0] = offset;
}
/* ═══════════════════════════════════════════════════════════════
* EMIT TOKEN (unchanged from v0.1)
* ═══════════════════════════════════════════════════════════════ */
static size_t emit_seq(uint8_t *dst, const uint8_t *lits,
size_t ll, size_t ml, uint32_t off, int off_bytes) {
uint8_t *op = dst;
uint8_t ll_f = (ll >= 15) ? 15 : (uint8_t)ll;
uint8_t ml_f;
if (ml == 0) { ml_f = 0; }
else { size_t v = ml - VV_MIN_MATCH; ml_f = (v >= 15) ? 15 : (uint8_t)v; }
*op++ = (ll_f << 4) | ml_f;
if (ll >= 15) op += write_varint(op, ll - 15);
if (ll > 0) { memcpy(op, lits, ll); op += ll; }
if (ml > 0) {
/* PERF: 2-byte offset for wlog≤16, 3-byte for wlog>16 */
if (off_bytes == 3) {
op[0] = (uint8_t)(off);
op[1] = (uint8_t)(off >> 8);
op[2] = (uint8_t)(off >> 16);
op += 3;
} else {
vv_write16(op, (uint16_t)off); op += 2;
}
if (ml - VV_MIN_MATCH >= 15)
op += write_varint(op, ml - VV_MIN_MATCH - 15);
}
return (size_t)(op - dst);
}
/* ═══════════════════════════════════════════════════════════════
* COMPRESS BLOCK: greedy / lazy / lazy-2
*
* Match-skip heuristic: after a match of length ≥ 16, only insert
* the last 3 positions into the hash chain. The interior positions
* are inside the match and won't be needed. This saves O(match_len)
* hash insertions, speeding up compression by 15-25% at L3+.
* ═══════════════════════════════════════════════════════════════ */
static size_t compress_block(const uint8_t *src, size_t start_pos, size_t block_len,
uint8_t *dst, size_t dst_cap,
matcher_t *m, vv_mode_t mode) {
uint8_t *op = dst;
int32_t pos = (int32_t)start_pos;
int32_t end = (int32_t)(start_pos + block_len);
const uint8_t *lit_start = src + start_pos;
int off_bytes = (m->wlog > 16) ? 3 : 2;
while (pos < end - (int32_t)VV_MIN_MATCH) {
int32_t mlen = 0, moff = 0;
/* ─── Step 1: Try rep-match (free, no hash lookup) ─── */
int32_t rep_idx = -1;
int32_t rep_len = try_rep_match(m, src, pos, end, &rep_idx);
if (rep_len >= (int32_t)VV_MIN_MATCH) {
mlen = rep_len;
moff = (int32_t)m->rep[rep_idx];
}
/* ─── Step 2: Hash chain match (only if rep didn't find a long one) ─── */
if (mlen < 8) {
int32_t chain_off = 0;
int32_t chain_len = chain_match(m, src, pos, end, &chain_off);
if (chain_len > mlen) {
mlen = chain_len;
moff = chain_off;
rep_idx = -1; /* not a rep match */
}
}
/* ─── Step 3: Lazy evaluation (balanced + extreme) ─── */
if (mode >= VV_MODE_BALANCED && mlen >= (int32_t)VV_MIN_MATCH &&
pos + 1 < end - (int32_t)VV_MIN_MATCH) {
/* Check pos+1 */
matcher_insert(m, src, pos, end);
int32_t noff = 0;
int32_t nlen = chain_match(m, src, pos + 1, end, &noff);
/* Also check rep at pos+1 */
int32_t nri = -1;
int32_t nrl = try_rep_match(m, src, pos + 1, end, &nri);
if (nrl > nlen) { nlen = nrl; noff = (int32_t)m->rep[nri]; }
if (nlen > mlen + 1) {
/* pos+1 is significantly better: emit literal, shift */
pos++;
mlen = nlen; moff = noff;
/* Lazy-2: also check pos+2 (extreme mode) */
if (mode >= VV_MODE_EXTREME && pos + 1 < end - (int32_t)VV_MIN_MATCH) {
matcher_insert(m, src, pos, end);
int32_t n2off = 0;
int32_t n2len = chain_match(m, src, pos + 1, end, &n2off);
int32_t n2ri = -1;
int32_t n2rl = try_rep_match(m, src, pos + 1, end, &n2ri);
if (n2rl > n2len) { n2len = n2rl; n2off = (int32_t)m->rep[n2ri]; }
if (n2len > mlen + 1) {
pos++;
mlen = n2len; moff = n2off;
}
}
}
}
/* ─── Step 4: Emit sequence or literal ─── */
if (mlen >= (int32_t)VV_MIN_MATCH) {
size_t ll = (size_t)(src + pos - lit_start);
size_t needed = 1 + (ll >= 15 ? ll / 255 + 2 : 0)
+ ll + 2 + ((size_t)mlen / 255 + 2);
if ((size_t)(op - dst) + needed > dst_cap) return 0;
op += emit_seq(op, lit_start, ll, (size_t)mlen, (uint32_t)moff, off_bytes);
/* ─── Hash insertion with skip heuristic ─── */
if (mlen >= 16) {
/* Long match: only insert boundary positions */
for (int32_t j = pos; j < pos + 3 && j < end - 4; j++)
matcher_insert(m, src, j, end);
for (int32_t j = pos + mlen - 3; j < pos + mlen && j < end - 4; j++)
matcher_insert(m, src, j, end);
} else {
/* Short match: insert all positions */
for (int32_t j = pos; j < pos + mlen && j < end - 4; j++)
matcher_insert(m, src, j, end);
}
update_rep(m, (uint32_t)moff);
pos += mlen;
lit_start = src + pos;
} else {
matcher_insert(m, src, pos, end);
pos++;
}
}
/* ─── Trailing literals ─── */
{
size_t ll = (size_t)(src + end - lit_start);
size_t needed = 1 + (ll >= 15 ? ll / 255 + 2 : 0) + ll;
if ((size_t)(op - dst) + needed > dst_cap) return 0;
op += emit_seq(op, lit_start, ll, 0, 0, off_bytes);
}
return (size_t)(op - dst);
}
/* ═══════════════════════════════════════════════════════════════
* EXTRACT LITERALS FROM TOKEN STREAM
*
* Walks a type-1 LZ token stream, copies all literal bytes into
* lit_buf and produces a "stripped" token stream (same format but
* with literal bytes removed) in stripped_buf.
*
* Returns the number of literals extracted, or 0 on error.
* ═══════════════════════════════════════════════════════════════ */
static size_t extract_literals(
const uint8_t *tokens, size_t tok_len,
uint8_t *lit_buf, size_t lit_cap,
uint8_t *stripped_buf, size_t *stripped_len, int off_bytes)
{
const uint8_t *tp = tokens;
const uint8_t *tp_end = tokens + tok_len;
uint8_t *sp = stripped_buf;
size_t total_lits = 0;
while (tp < tp_end) {
uint8_t token = *tp++;
*sp++ = token; /* Copy token byte to stripped stream */
size_t ll = token >> 4;
size_t mc = token & 0x0F;
/* Extended literal length */
if (ll == 15) {
size_t ext = 0;
do {
if (tp >= tp_end) return 0;
uint8_t b = *tp++;
*sp++ = b; /* Copy extension byte */
ext += b;
if (b < 255) break;
} while (tp < tp_end);
ll += ext;
}
/* Literal bytes: copy to lit_buf, do NOT copy to stripped stream */
if (tp + ll > tp_end) return 0;
if (total_lits + ll > lit_cap) return 0;
memcpy(lit_buf + total_lits, tp, ll);
total_lits += ll;
tp += ll;
/* End of block: no more data = last sequence (no match) */
if (tp >= tp_end) break;
/* Offset: 2 or 3 bytes, copy to stripped stream */
if (tp + off_bytes > tp_end) return 0;
for (int i = 0; i < off_bytes; i++) *sp++ = *tp++;
/* Extended match length */
if (mc == 15) {
size_t ext = 0;
do {
if (tp >= tp_end) return 0;
uint8_t b = *tp++;
*sp++ = b;
ext += b;
if (b < 255) break;
} while (tp < tp_end);
(void)ext;
}
}
*stripped_len = (size_t)(sp - stripped_buf);
return total_lits;
}
/* ═══════════════════════════════════════════════════════════════
* PUBLIC API: COMPRESS
* ═══════════════════════════════════════════════════════════════ */
size_t vv_compress_bound(size_t src_len) {
return src_len + src_len / 255 + 256
+ sizeof(vv_frame_header_t) + sizeof(vv_frame_footer_t);
}
int64_t vv_compress(const uint8_t *src, size_t src_len,
uint8_t *dst, size_t dst_cap,
const vv_options_t *opts) {
if (!src || !dst || !opts) return VV_ERR_PARAM;
if (dst_cap < sizeof(vv_frame_header_t) + sizeof(vv_frame_footer_t) + 16)
return VV_ERR_OVERFLOW;
uint8_t wlog = opts->window_log;
uint32_t depth;
if (wlog == 0) {
switch (opts->mode) {
case VV_MODE_ULTRA_FAST: wlog = 16; break;
case VV_MODE_BALANCED: wlog = 16; break; /* may be overridden below */
case VV_MODE_EXTREME: wlog = 16; break; /* may be overridden below */
}
}
switch (opts->mode) {
case VV_MODE_ULTRA_FAST: depth = 4; break;
case VV_MODE_BALANCED: depth = 48; break;
case VV_MODE_EXTREME: depth = 256; break;
default: depth = 48;
}
/* ─── ADAPTIVE WINDOW: sample first 64KB at wlog=16 vs wlog=20.
* PERF: only samples 64KB (not full 1MB block) — 16× faster trial.
* If wlog=20 saves ≥3%, use wider window for the whole frame. ─── */
if (opts->window_log == 0 && opts->mode >= VV_MODE_BALANCED && src_len > 65536) {
size_t trial_len = 262144; /* Sample 256KB — catches patterns up to 200KB apart */
if (trial_len > src_len) trial_len = src_len;
size_t trial_cap = trial_len + trial_len / 255 + 1024;
uint8_t *trial_buf = (uint8_t *)malloc(trial_cap);
if (trial_buf) {
/* PERF: use greedy depth=4 for trials — 10× faster than lazy-48 */
matcher_t m16; matcher_init(&m16, 16, 4);
size_t sz16 = compress_block(src, 0, trial_len, trial_buf, trial_cap, &m16, VV_MODE_ULTRA_FAST);
matcher_free(&m16);
matcher_t m20; matcher_init(&m20, 20, 4);
size_t sz20 = compress_block(src, 0, trial_len, trial_buf, trial_cap, &m20, VV_MODE_ULTRA_FAST);
matcher_free(&m20);
free(trial_buf);
if (sz20 > 0 && sz16 > 0 && sz20 < (sz16 * 97 / 100)) wlog = 20;
}
}
/* Frame header */
uint8_t *op = dst;
vv_frame_header_t fh;
memset(&fh, 0, sizeof(fh));
fh.magic = VV_MAGIC;
fh.version = 1;
fh.flags = opts->checksum ? 1 : 0;
fh.mode_hint = (uint8_t)opts->mode;
fh.window_log = wlog;
fh.content_size = (uint64_t)src_len;
memcpy(op, &fh, sizeof(fh)); op += sizeof(fh);
/* Matcher */
matcher_t m;
matcher_init(&m, wlog, depth);
/* Temp buffer */
size_t tcap = VV_MAX_BLOCK_SIZE + VV_MAX_BLOCK_SIZE / 255 + 1024;
uint8_t *tmp = (uint8_t *)malloc(tcap);
if (!tmp) { matcher_free(&m); return VV_ERR_NOMEM; }
/* Additional buffers for entropy path (only allocated if needed) */
uint8_t *lit_buf = NULL, *stripped = NULL, *ent_buf = NULL;
size_t lit_cap = 0, ent_cap = 0;
if (opts->mode >= VV_MODE_BALANCED) {
lit_cap = VV_MAX_BLOCK_SIZE;
ent_cap = vva_bound(VV_MAX_BLOCK_SIZE);
lit_buf = (uint8_t *)malloc(lit_cap);
stripped = (uint8_t *)malloc(tcap);
ent_buf = (uint8_t *)malloc(ent_cap);
if (!lit_buf || !stripped || !ent_buf) {
free(lit_buf); free(stripped); free(ent_buf);
free(tmp); matcher_free(&m);
return VV_ERR_NOMEM;
}
}
size_t remaining = src_len;
const uint8_t *ip = src;
if (remaining == 0) {
uint32_t bh = vv_bh_pack(VV_BLOCK_RAW, 1, 0);
memcpy(op, &bh, 4); op += 4;
}
while (remaining > 0) {
size_t braw = remaining > VV_MAX_BLOCK_SIZE ? VV_MAX_BLOCK_SIZE : remaining;
int last = (remaining <= VV_MAX_BLOCK_SIZE);
size_t block_start = (size_t)(ip - src);
size_t csz = compress_block(src, block_start, braw, tmp, tcap, &m, opts->mode);
if (csz == 0 || csz >= braw) {
/* Incompressible: store raw */
uint32_t bh = vv_bh_pack(VV_BLOCK_RAW, last, (uint32_t)braw);
memcpy(op, &bh, 4); op += 4;
memcpy(op, ip, braw); op += braw;
} else if (opts->mode >= VV_MODE_BALANCED) {
/* ═══ WINNER-TAKES-ALL block selection ═══
* TRADEOFF: we encode the block twice (once 'S', once 'I'/'C')
* and pick the smaller. This costs ~2× encode time but ensures
* we NEVER regress ratio vs any previous codec version.
* Encode speed is not the bottleneck (decode is). */
/* ── Path A: sequence coding ('S') ── */
size_t seq_len = 0;
int seq_valid = 0;
size_t seq_block_sz = (size_t)-1; /* Total bytes if we emit 'S' */
int off_bytes = (wlog > 16) ? 3 : 2;
vva_error_t serr = vva_encode_sequences(tmp, csz,
ent_buf, ent_cap, &seq_len, off_bytes);
if (serr == VVA_OK) {
seq_block_sz = 4 + 3 + 1 + seq_len; /* block_hdr + comp_sz + tag + data */
seq_valid = 1;
}
/* ── Path B: literal-only entropy ('I' or 'C') ── */
size_t stripped_len = 0;
size_t lit_count = extract_literals(tmp, csz, lit_buf, lit_cap,
stripped, &stripped_len, off_bytes);
/* Use second half of ent_buf for path B to avoid overwriting path A */
uint8_t *ent_buf2 = ent_buf + ent_cap / 2;
size_t ent_cap2 = ent_cap / 2;
size_t ent_len = 0;
uint8_t ent_tag = 0;
size_t ent_block_sz = (size_t)-1;
if (lit_count > 0) {
if (opts->mode >= VV_MODE_EXTREME && lit_count >= 64) {
vva_error_t aerr = vva_encode_ctx(lit_buf, lit_count,
ent_buf2, ent_cap2, &ent_len);
if (aerr == VVA_OK) ent_tag = VV_ENTROPY_CTX;
}
if (!ent_tag) {
vva_error_t aerr = vva_encode4(lit_buf, lit_count,
ent_buf2, ent_cap2, &ent_len);
if (aerr == VVA_OK) ent_tag = VV_ENTROPY_ANS4;
}
if (!ent_tag) {
vva_error_t aerr = vva_encode(lit_buf, lit_count,
ent_buf2, ent_cap2, &ent_len);
if (aerr == VVA_OK) ent_tag = VV_ENTROPY_ANS;
}
if (ent_tag) {
ent_block_sz = 4 + 3 + 1 + 2 + 2 + ent_len + stripped_len;
}
}
/* ── Path C: raw type-1 block ── */
size_t raw_block_sz = 4 + 3 + csz;
/* ── Pick winner ── */
if (seq_valid && seq_block_sz <= ent_block_sz && seq_block_sz < raw_block_sz) {
/* 'S' wins — emit sequence-coded block */
uint32_t bh = vv_bh_pack(VV_BLOCK_ENTROPY, last, (uint32_t)braw);
memcpy(op, &bh, 4); op += 4;
uint32_t total_comp = (uint32_t)(1 + seq_len);
op[0] = (uint8_t)(total_comp);
op[1] = (uint8_t)(total_comp >> 8);
op[2] = (uint8_t)(total_comp >> 16);
op += 3;
*op++ = VV_ENTROPY_SEQ;
memcpy(op, ent_buf, seq_len); op += seq_len;
} else if (ent_tag && ent_block_sz < raw_block_sz) {
/* 'I'/'C' wins — emit literal-entropy block */
uint32_t bh = vv_bh_pack(VV_BLOCK_ENTROPY, last, (uint32_t)braw);
memcpy(op, &bh, 4); op += 4;
uint32_t total_comp = (uint32_t)(5 + ent_len + stripped_len);
op[0] = (uint8_t)(total_comp);
op[1] = (uint8_t)(total_comp >> 8);
op[2] = (uint8_t)(total_comp >> 16);
op += 3;
*op++ = ent_tag;
op[0] = (uint8_t)(lit_count); op[1] = (uint8_t)(lit_count >> 8); op += 2;
op[0] = (uint8_t)(ent_len); op[1] = (uint8_t)(ent_len >> 8); op += 2;
memcpy(op, ent_buf2, ent_len); op += ent_len;
memcpy(op, stripped, stripped_len); op += stripped_len;
} else {
/* Raw type-1 wins (or nothing compresses) */
uint32_t bh = vv_bh_pack(VV_BLOCK_COMPRESSED, last, (uint32_t)braw);
memcpy(op, &bh, 4); op += 4;
op[0] = (uint8_t)(csz); op[1] = (uint8_t)(csz >> 8); op[2] = (uint8_t)(csz >> 16);
op += 3;
memcpy(op, tmp, csz); op += csz;
}
} else {
/* Ultra-fast mode: emit type 1 block directly */
uint32_t bh = vv_bh_pack(VV_BLOCK_COMPRESSED, last, (uint32_t)braw);
memcpy(op, &bh, 4); op += 4;
op[0] = (uint8_t)(csz); op[1] = (uint8_t)(csz >> 8); op[2] = (uint8_t)(csz >> 16);
op += 3;
memcpy(op, tmp, csz); op += csz;
}
ip += braw; remaining -= braw;
}
free(lit_buf); free(stripped); free(ent_buf);
free(tmp);
if (opts->checksum) {
vv_frame_footer_t ff;
ff.checksum = vv_xxh64(src, src_len, 0);
ff.footer_magic = 0x56564E44u;
memcpy(op, &ff, sizeof(ff)); op += sizeof(ff);
}
matcher_free(&m);
return (int64_t)(op - dst);
}