Initial project import

This commit is contained in:
Agila Forge Importer committed 2026-07-13 15:20:32 +00:00
commit 23f2d29e32
11957 files changed
+1754577

No files matched your search

@@ -0,0 +1,44 @@
## LZ Interop Validation (V, C, Python)
This tool validates:
- V compress/decompress roundtrips for all formats: `lz77`, `lz78`, `lzw`,
`lz4`, `lzss`, `lzma`, `lzjb`
- a C `lz77`-like reference implementation
- a Python `lz77`-like reference implementation
The C/Python references are intentionally simple so the benchmark is easy to run
without external dependencies.
### Run
```bash
cd /home/jalon/git/v
./vnew run vlib/compress/lz/interop/lz_interop.v 2>&1
```
Optional args:
1. validation rounds (default: `40`)
2. input size in bytes (default: `524288`)
Example:
```bash
cd /home/jalon/git/v
./vnew run vlib/compress/lz/interop/lz_interop.v 25 262144 2>&1
```
### Output
The tool prints validation status lines only (no timing output).
When helpers are available, it also cross-validates compression/expansion
interoperability with V (`lz77`) in both directions:
- V compress -> C decompress
- C compress -> V decompress
- V compress -> Python decompress
- Python compress -> V decompress
If `cc`/`gcc` or `python3` are missing, that row is skipped with a message.
+256
View File
@@ -0,0 +1,256 @@
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#define MIN_MATCH 3
#define MAX_LITERAL 128
static const uint8_t STREAM_MAGIC[4] = {0x56, 0x4c, 0x5a, 0x31};
static const uint8_t FORMAT_LZ77 = 0;
typedef struct {
uint8_t *data;
size_t len;
size_t cap;
} Buffer;
static void die(const char *msg) {
fprintf(stderr, "%s\n", msg);
exit(1);
}
static void buf_init(Buffer *b, size_t cap) {
b->data = (uint8_t *)malloc(cap > 0 ? cap : 1);
if (!b->data) {
die("allocation failed");
}
b->len = 0;
b->cap = cap > 0 ? cap : 1;
}
static void buf_push(Buffer *b, uint8_t v) {
if (b->len >= b->cap) {
size_t new_cap = b->cap * 2;
uint8_t *n = (uint8_t *)realloc(b->data, new_cap);
if (!n) {
die("reallocation failed");
}
b->data = n;
b->cap = new_cap;
}
b->data[b->len++] = v;
}
static void buf_append(Buffer *b, const uint8_t *src, size_t len) {
for (size_t i = 0; i < len; i++) {
buf_push(b, src[i]);
}
}
static Buffer read_all(const char *path) {
FILE *f = fopen(path, "rb");
if (!f) {
die("could not open input file");
}
if (fseek(f, 0, SEEK_END) != 0) {
fclose(f);
die("could not seek input file");
}
long sz = ftell(f);
if (sz < 0) {
fclose(f);
die("could not read input file size");
}
if (fseek(f, 0, SEEK_SET) != 0) {
fclose(f);
die("could not rewind input file");
}
Buffer in;
buf_init(&in, (size_t)sz + 1);
in.len = (size_t)sz;
if (in.len > 0 && fread(in.data, 1, in.len, f) != in.len) {
fclose(f);
free(in.data);
die("could not read input file");
}
fclose(f);
return in;
}
static void write_all(const char *path, const uint8_t *data, size_t len) {
FILE *f = fopen(path, "wb");
if (!f) {
die("could not open output file");
}
if (len > 0 && fwrite(data, 1, len, f) != len) {
fclose(f);
die("could not write output file");
}
fclose(f);
}
static void write_uvarint(Buffer *out, uint64_t value) {
uint64_t v = value;
while (v >= 0x80) {
buf_push(out, (uint8_t)(v & 0x7f) | 0x80);
v >>= 7;
}
buf_push(out, (uint8_t)v);
}
static int read_uvarint(const uint8_t *data, size_t len, size_t *pos, uint64_t *value) {
uint64_t out = 0;
uint32_t shift = 0;
while (*pos < len && shift <= 63) {
uint8_t b = data[*pos];
(*pos)++;
out |= ((uint64_t)(b & 0x7f)) << shift;
if ((b & 0x80) == 0) {
*value = out;
return 1;
}
shift += 7;
}
return 0;
}
static Buffer compress_lz77(const uint8_t *in, size_t in_len) {
Buffer out;
buf_init(&out, in_len + 32);
buf_append(&out, STREAM_MAGIC, 4);
buf_push(&out, FORMAT_LZ77);
write_uvarint(&out, (uint64_t)in_len);
for (size_t i = 0; i < in_len;) {
size_t lit_len = in_len - i;
if (lit_len > MAX_LITERAL) {
lit_len = MAX_LITERAL;
}
buf_push(&out, (uint8_t)(lit_len - 1));
buf_append(&out, in + i, lit_len);
i += lit_len;
}
return out;
}
static Buffer decompress_lz77(const uint8_t *in, size_t in_len) {
if (in_len < 6 || memcmp(in, STREAM_MAGIC, 4) != 0) {
die("bad magic");
}
if (in[4] != FORMAT_LZ77) {
die("format mismatch");
}
size_t pos = 5;
uint64_t expected_len_u64 = 0;
if (!read_uvarint(in, in_len, &pos, &expected_len_u64)) {
die("bad length varint");
}
size_t expected_len = (size_t)expected_len_u64;
Buffer out;
buf_init(&out, expected_len + 16);
while (pos < in_len) {
uint8_t control = in[pos++];
if ((control & 0x80) == 0) {
size_t lit_len = (size_t)(control & 0x7f) + 1;
if (pos + lit_len > in_len) {
die("truncated literal");
}
buf_append(&out, in + pos, lit_len);
pos += lit_len;
} else {
size_t match_len = (size_t)(control & 0x7f) + MIN_MATCH;
uint64_t offset_u64 = 0;
if (!read_uvarint(in, in_len, &pos, &offset_u64)) {
die("bad match offset");
}
size_t offset = (size_t)offset_u64;
if (offset == 0 || offset > out.len) {
die("bad offset");
}
size_t base = out.len - offset;
for (size_t k = 0; k < match_len; k++) {
buf_push(&out, out.data[base + k]);
}
}
}
if (out.len != expected_len) {
die("length mismatch");
}
return out;
}
static int64_t now_ms(void) {
return (int64_t)((double)clock() * 1000.0 / (double)CLOCKS_PER_SEC);
}
int main(int argc, char **argv) {
if (argc < 2) {
fprintf(stderr,
"usage:\n"
" %s bench <input.bin> <iterations>\n"
" %s compress <input.bin> <output.bin>\n"
" %s decompress <input.bin> <output.bin>\n",
argv[0], argv[0], argv[0]);
return 1;
}
if (strcmp(argv[1], "bench") == 0) {
if (argc < 4) {
fprintf(stderr, "usage: %s bench <input.bin> <iterations>\n", argv[0]);
return 1;
}
int iterations = atoi(argv[3]);
if (iterations <= 0) {
fprintf(stderr, "iterations must be > 0\n");
return 1;
}
Buffer input = read_all(argv[2]);
int64_t start = now_ms();
for (int i = 0; i < iterations; i++) {
Buffer comp = compress_lz77(input.data, input.len);
Buffer decomp = decompress_lz77(comp.data, comp.len);
if (decomp.len != input.len || memcmp(decomp.data, input.data, input.len) != 0) {
fprintf(stderr, "roundtrip mismatch\n");
return 1;
}
free(comp.data);
free(decomp.data);
}
int64_t elapsed = now_ms() - start;
printf("ms=%lld\n", (long long)elapsed);
free(input.data);
return 0;
}
if (strcmp(argv[1], "compress") == 0) {
if (argc < 4) {
fprintf(stderr, "usage: %s compress <input.bin> <output.bin>\n", argv[0]);
return 1;
}
Buffer input = read_all(argv[2]);
Buffer comp = compress_lz77(input.data, input.len);
write_all(argv[3], comp.data, comp.len);
free(input.data);
free(comp.data);
return 0;
}
if (strcmp(argv[1], "decompress") == 0) {
if (argc < 4) {
fprintf(stderr, "usage: %s decompress <input.bin> <output.bin>\n", argv[0]);
return 1;
}
Buffer input = read_all(argv[2]);
Buffer dec = decompress_lz77(input.data, input.len);
write_all(argv[3], dec.data, dec.len);
free(input.data);
free(dec.data);
return 0;
}
fprintf(stderr, "unknown mode: %s\n", argv[1]);
return 1;
}
@@ -0,0 +1,141 @@
#!/usr/bin/env python3
import sys
import time
MIN_MATCH = 3
MAX_LITERAL = 128
STREAM_MAGIC = b'VLZ1'
FORMAT_LZ77 = 0
def encode_uvarint(value: int) -> bytes:
out = bytearray()
v = value
while v >= 0x80:
out.append((v & 0x7F) | 0x80)
v >>= 7
out.append(v)
return bytes(out)
def decode_uvarint(data: bytes, pos: int):
value = 0
shift = 0
i = pos
while i < len(data) and shift <= 63:
b = data[i]
i += 1
value |= (b & 0x7F) << shift
if (b & 0x80) == 0:
return value, i
shift += 7
raise ValueError('bad length varint')
def compress_lz77(data: bytes) -> bytes:
out = bytearray()
out.extend(STREAM_MAGIC)
out.append(FORMAT_LZ77)
out.extend(encode_uvarint(len(data)))
i = 0
while i < len(data):
lit_len = min(MAX_LITERAL, len(data) - i)
out.append(lit_len - 1)
out.extend(data[i : i + lit_len])
i += lit_len
return bytes(out)
def decompress_lz77(data: bytes) -> bytes:
if len(data) < 6 or data[:4] != STREAM_MAGIC:
raise ValueError('bad magic')
if data[4] != FORMAT_LZ77:
raise ValueError('format mismatch')
expected_len, pos = decode_uvarint(data, 5)
out = bytearray()
while pos < len(data):
control = data[pos]
pos += 1
if (control & 0x80) == 0:
literal_len = (control & 0x7F) + 1
if pos + literal_len > len(data):
raise ValueError('truncated literal')
out.extend(data[pos : pos + literal_len])
pos += literal_len
else:
length = (control & 0x7F) + MIN_MATCH
off, pos = decode_uvarint(data, pos)
if off == 0 or off > len(out):
raise ValueError('bad offset')
base = len(out) - off
for k in range(length):
out.append(out[base + k])
if len(out) != expected_len:
raise ValueError('length mismatch')
return bytes(out)
def main() -> int:
if len(sys.argv) < 2:
print(
f'usage:\n'
f' {sys.argv[0]} bench <input.bin> <iterations>\n'
f' {sys.argv[0]} compress <input.bin> <output.bin>\n'
f' {sys.argv[0]} decompress <input.bin> <output.bin>',
file=sys.stderr,
)
return 1
mode = sys.argv[1]
if mode == 'bench':
if len(sys.argv) < 4:
print(f'usage: {sys.argv[0]} bench <input.bin> <iterations>', file=sys.stderr)
return 1
input_path = sys.argv[2]
iterations = int(sys.argv[3])
if iterations <= 0:
print('iterations must be > 0', file=sys.stderr)
return 1
with open(input_path, 'rb') as f:
data = f.read()
start = time.perf_counter()
for _ in range(iterations):
enc = compress_lz77(data)
dec = decompress_lz77(enc)
if dec != data:
print('roundtrip mismatch', file=sys.stderr)
return 1
elapsed_ms = int((time.perf_counter() - start) * 1000)
print(f'ms={elapsed_ms}')
return 0
if mode == 'compress':
if len(sys.argv) < 4:
print(f'usage: {sys.argv[0]} compress <input.bin> <output.bin>', file=sys.stderr)
return 1
with open(sys.argv[2], 'rb') as f:
data = f.read()
out = compress_lz77(data)
with open(sys.argv[3], 'wb') as f:
f.write(out)
return 0
if mode == 'decompress':
if len(sys.argv) < 4:
print(f'usage: {sys.argv[0]} decompress <input.bin> <output.bin>', file=sys.stderr)
return 1
with open(sys.argv[2], 'rb') as f:
data = f.read()
out = decompress_lz77(data)
with open(sys.argv[3], 'wb') as f:
f.write(out)
return 0
print(f'unknown mode: {mode}', file=sys.stderr)
return 1
if __name__ == '__main__':
raise SystemExit(main())
@@ -0,0 +1,172 @@
module main
import compress.lz
import os
const default_data_size = 512 * 1024
fn main() {
mut data_size := default_data_size
if os.args.len > 1 {
parsed := int(os.args[1].i32())
if parsed > 0 {
data_size = parsed
}
}
data := `z`.repeat(data_size).bytes()
println('LZ interop input: ${data.len} bytes')
for format in [lz.Format.lz77, .lz78, .lzw, .lz4, .lzss, .lzma, .lzma2, .lzjb] {
validate_v_roundtrip(data, format) or {
eprintln('V validation failed for ${format}: ${err.msg()}')
exit(1)
}
println('V roundtrip (${format}): OK')
}
tmp_dir := os.join_path(os.temp_dir(), 'v_lz_interop')
os.mkdir_all(tmp_dir) or {
eprintln('Could not create temp directory ${tmp_dir}: ${err.msg()}')
exit(1)
}
defer {
os.rmdir_all(tmp_dir) or {
eprintln('Could not remove temp directory ${tmp_dir}: ${err.msg()}')
}
}
input_path := os.join_path(tmp_dir, 'input.bin')
os.write_file_array(input_path, data) or {
eprintln('Could not write input file ${input_path}: ${err.msg()}')
exit(1)
}
mut c_bin := ''
if bin := compile_c_runner() {
c_bin = bin
} else {
eprintln('Skipping C benchmark: ${err.msg()}')
}
python_ok := has_python3()
if !python_ok {
eprintln('Skipping Python benchmark: python3 is not available')
}
if c_bin.len > 0 {
cross_validate_v_c(c_bin, data, input_path, tmp_dir) or {
eprintln('Cross-validation V<->C failed: ${err.msg()}')
exit(1)
}
println('Cross-validation: V<->C compress/decompress OK')
} else {
println('Cross-validation: skipped V<->C (requires C compiler)')
}
if python_ok {
cross_validate_v_python(data, input_path, tmp_dir) or {
eprintln('Cross-validation V<->Python failed: ${err.msg()}')
exit(1)
}
println('Cross-validation: V<->Python compress/decompress OK')
} else {
println('Cross-validation: skipped V<->Python (requires python3)')
}
}
fn validate_v_roundtrip(data []u8, format lz.Format) ! {
encoded := lz.compress(data, format)!
decoded := lz.decompress(encoded, format)!
if decoded != data {
return error('roundtrip mismatch for ${format}')
}
}
fn compile_c_runner() !string {
cc := choose_cc()
if cc.len == 0 {
return error('no C compiler found (tried cc, gcc, and clang)')
}
bin_path := os.join_path(os.temp_dir(), 'lz77_ref_bench')
c_src := os.join_path(@DIR, 'lz77_ref.c')
compile_cmd := '${cc} -O3 -std=c99 ${os.quoted_path(c_src)} -o ${os.quoted_path(bin_path)}'
compile_res := os.execute(compile_cmd)
if compile_res.exit_code != 0 {
return error('C compile failed: ${compile_res.output.trim_space()}')
}
return bin_path
}
fn choose_cc() string {
for cc in ['cc', 'gcc', 'clang'] {
if os.execute('${cc} --version').exit_code == 0 {
return cc
}
}
return ''
}
fn has_python3() bool {
return os.execute('python3 --version').exit_code == 0
}
fn cross_validate_v_c(c_bin string, original []u8, input_path string, tmp_dir string) ! {
v_encoded := os.join_path(tmp_dir, 'v_encoded.bin')
c_decoded := os.join_path(tmp_dir, 'c_decoded.bin')
c_encoded := os.join_path(tmp_dir, 'c_encoded.bin')
v_stream := lz.compress_lz77(original)!
os.write_file_array(v_encoded, v_stream)!
mut res :=
os.execute('${os.quoted_path(c_bin)} decompress ${os.quoted_path(v_encoded)} ${os.quoted_path(c_decoded)}')
if res.exit_code != 0 {
return error('C decompress(V output) failed: ${res.output.trim_space()}')
}
validate_equal_files(input_path, c_decoded, 'V->C')!
res =
os.execute('${os.quoted_path(c_bin)} compress ${os.quoted_path(input_path)} ${os.quoted_path(c_encoded)}')
if res.exit_code != 0 {
return error('C compress failed: ${res.output.trim_space()}')
}
c_encoded_data := os.read_bytes(c_encoded)!
v_decoded := lz.decompress_lz77(c_encoded_data)!
if v_decoded != original {
return error('C->V output mismatch')
}
}
fn cross_validate_v_python(original []u8, input_path string, tmp_dir string) ! {
v_encoded := os.join_path(tmp_dir, 'v_encoded_for_py.bin')
py_decoded := os.join_path(tmp_dir, 'py_decoded.bin')
py_encoded := os.join_path(tmp_dir, 'py_encoded.bin')
py_script := os.join_path(@DIR, 'lz77_ref.py')
v_stream := lz.compress_lz77(original)!
os.write_file_array(v_encoded, v_stream)!
mut res :=
os.execute('python3 ${os.quoted_path(py_script)} decompress ${os.quoted_path(v_encoded)} ${os.quoted_path(py_decoded)}')
if res.exit_code != 0 {
return error('Python decompress(V output) failed: ${res.output.trim_space()}')
}
validate_equal_files(input_path, py_decoded, 'V->Python')!
res =
os.execute('python3 ${os.quoted_path(py_script)} compress ${os.quoted_path(input_path)} ${os.quoted_path(py_encoded)}')
if res.exit_code != 0 {
return error('Python compress failed: ${res.output.trim_space()}')
}
py_encoded_data := os.read_bytes(py_encoded)!
v_decoded := lz.decompress_lz77(py_encoded_data)!
if v_decoded != original {
return error('Python->V output mismatch')
}
}
fn validate_equal_files(expected_path string, actual_path string, tag string) ! {
expected := os.read_bytes(expected_path)!
actual := os.read_bytes(actual_path)!
if expected != actual {
return error('${tag} output mismatch')
}
}