Library / SDK
avaneev/lzav avatar
avaneev/lzav

LZAV: a header-only LZ77 codec that checks its own bounds

Fast In-Memory Data Compression Algorithm (header-only C/C++) 540+MB/s compress, 3000+MB/s decompress, ratio% better than LZ4, Snappy, and Zstd@--1

548 stars26 forksC++MIT

At a glance

What is it?
LZAV is a small, portable, header-only C and C++ compression library for in-memory data, built on LZ77 with an internal out-of-bounds check instead of a checksum on the compressed stream. It is aimed at code that cannot tolerate a crash on malformed input, and it is not aimed at streaming or file formats.
Who is it for?
LZAV fits C and C++ code that compresses blocks in memory and cannot afford a crash or undefined behaviour on damaged input, especially server, real-time and system level software. It does not fit a streaming format or a filesystem compressor, since the library is explicitly for non-streaming data and the only file-oriented port listed is a FreeArc plugin.
Can I use it commercially?
Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
Is it still maintained?
Yes. The repository last received commits 22 days ago.
What is it written in?
Mainly C++, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on October 22, 2026, and from our analysis. They are not legal advice.

Editorial analysis

A single header LZ77 codec for blocks that live in memory

LZAV is described as a fast, general-purpose, in-memory data compression algorithm based on the classic LZ77 lossless method, and the repository is three files: LICENSE, README.md and lzav.h. That is the whole distribution. The library is header-only, scalar and portable, and the README states that it supports big- and little-endian platforms and any memory alignment model, and that it is efficient on both 32- and 64-bit platforms. The audience is developers who already hold a block of data in memory and want it smaller, for a database page, a log buffer or a network payload. It is not a file compressor and not a streaming format. The scope is stated as in-memory and non-streaming, which is the single most important fact for anyone choosing between this and a general purpose compression library.

Internal out-of-bounds checks instead of a checksum on the stream

The design decision that distinguishes LZAV from most codecs in its class is safety on malformed input. The README states that LZAV performs internal out-of-bounds checks and does not trade safety for decompression speed, and that it can be used safely, without crashes or undefined behaviour, even when decompressing malformed or damaged data. The stated consequence is that it does not require calculating a checksum or a hash of the compressed data, though a checksum of the uncompressed data may still be required depending on the application. That removes per-call overhead, and it removes the awkward failure mode where a corrupt frame takes down a server because a decoder trusted a length field. The target environments named for this property are real-time, system-level and server software, where out-of-bounds reads and writes that lead to CPU traps are unacceptable. Note what is not claimed: LZAV protects the process, not the data. A damaged block still decodes to wrong bytes.

Compressing and decompressing with the default entry points

The README's usage section is a short C API. There is no install step, because there is nothing to install beyond the header, and the public functions are declared static, so including lzav.h in several translation units produces no ABI conflict. Compression works by asking for a bound on the output size, allocating that much, and calling the default compressor. The bound function is what makes the buffer safe to size, and the convention for failure is a return of zero when the input was not empty:

c
#include "lzav.h"

int max_len = lzav_compress_bound( src_len );
void* comp_buf = malloc( max_len );
int comp_len = lzav_compress_default( src_buf, comp_buf, src_len, max_len );

if( comp_len == 0 && src_len != 0 )
{
    // Error handling
}

Decompression takes the compressed buffer, the compressed length and the expected original length, and returns the number of bytes written or a negative value on failure. The caller supplies the original size, which is why the bound on the compressed side has to be honoured on the way in:

c
#include "lzav.h"

void* decomp_buf = malloc( src_len );
int l = lzav_decompress( comp_buf, decomp_buf, comp_len, src_len );

if( l < 0 )
{
    // Error handling
}

The API is small enough to read in full from the header, and the README notes that the internal functions in lzav.h also let developers implement and test their own compression algorithms on the same footing.

The hi variant for static assets that are not time critical

There are two compression profiles, and the choice between them is the main tuning decision in the library. The higher ratio variant is intended for non-time-critical uses, with static assets named as the example, such as an application's static files. It uses a different bound function, lzav_compress_bound_hi, and a different entry point, lzav_compress_hi, and the README flags the difference with an inline comment. The cost is visible in the benchmark table: on the Silesia corpus under Apple clang 15.0.0 arm64 on macOS 26.4 with an Apple M1 at 3.5 GHz, LZAV 5.18 compresses at 627 MB/s with a ratio of 39.91 percent, while LZAV 5.18 HI compresses at 147 MB/s with a ratio of 34.85 percent, and decompresses at 3,760 MB/s against 3,830 MB/s. For a build step that runs once, spending four times the CPU to get a smaller bundle is an easy trade. For a request path, it is not.

Keeping the symbols out of the global C++ namespace

In C++, a header-only library that puts its symbols in the global namespace can collide with other code. LZAV handles this with the LZAV_NS_CUSTOM macro, which can be defined externally before the include, and the README shows the pattern with the value lzav. The same mechanism can name any namespace, and the documented example uses my_compressors, after which the functions are referred to as my_compressors::lzav_compress_default(...) and so on. The macro is defined by the user, not by the library, so it is a per translation unit decision rather than a build wide setting, and a project that includes the header from mixed C and C++ code needs to keep that consistent. The README also notes that because all LZAV functions carry the static specifier, there are no ABI conflicts even when the header is included in multiple translation units.

What the Silesia tables say, and where the numbers come from

The README calls its own figures ballpark performance numbers and stresses that they depend on the data being compressed. The geometric means it reports across a variety of datasets are 550 plus or minus 150 MB/s for compression and 3,800 plus or minus 1,300 MB/s for decompression, applying to 64-bit processors released since 2019 running at 4 GHz or higher. The adaptive quality is worth underlining: the README says LZAV may show exceptional performance on your specific data, naming sparse databases, log files and HTML or XML files. In the Apple M1 table, LZ4 1.9.4 compresses at 700 MB/s with a ratio of 47.60 percent, Snappy 1.1.10 at 495 MB/s and 48.22 percent, and LZF 3.6 at 395 MB/s and 48.15 percent, while LZ4HC 1.9.4 at level -9 compresses at 40 MB/s with a ratio of 36.75 percent. The README summarises the trade against LZ4 as 16 percent greater storage savings for about 30 percent slower compression, and points to lzbench for a broader comparison of in-memory algorithms.

Where LZAV sits against hash-table and entropy codecs

The comparison the README draws is not only against LZ4. It argues that methods like LZAV and LZ4 usually have an advantage over explicit dictionary and entropy based methods, because hash-table based compression has low memory usage and minimal operational overhead while classic LZ77 decompression has no overhead at all, which the README says is especially relevant for smaller datasets. That is a different trade from the one file compression libraries make, where a dictionary or entropy coder is usually the only way to squeeze the last bytes. The practical consequence is that LZAV is a reasonable default for small to medium blocks, where a decoder's memory footprint and branch behaviour dominate the ratio difference. Against Zstandard, the difference the README highlights is architectural: LZAV is a small, independent, maintainable codebase, and the internal functions are exposed for experimentation rather than locked behind a format.

Ports, licence, and the absence of tagged releases

The repository is not archived and the last push was on 2026-10-01, but it has no GitHub releases, so there is no tag to pin a dependency to and the version numbers in the benchmark tables, such as LZAV 5.18, come from the project's own naming rather than from a release list. The licence is MIT, which is permissive, though that is a description of the licence and not advice on how to use it. Language ports exist for other ecosystems, listed in the README as C# by AQtun on NuGet, C++ through vcpkg, FreeArc by Shegorat, and Rust by pkolaczk on crates.io. Port quality and API shape are the ports' own, so anyone binding to one of them should read that port's documentation rather than assume the C header's semantics carry over unchanged. On portability testing, the README lists Clang, GCC, MSVC and the Intel C++ compiler on x86, x86-64 from Intel and AMD, and AArch64 on Apple Silicon, running Windows 10, Windows 11, AlmaLinux 9.6 and macOS 26.4.

Editorial conclusion

LZAV fits C and C++ code that compresses blocks in memory and cannot afford a crash or undefined behaviour on damaged input, especially server, real-time and system level software. It does not fit a streaming format or a filesystem compressor, since the library is explicitly for non-streaming data and the only file-oriented port listed is a FreeArc plugin. Verify first that the Silesia ratio and speed figures reported for LZAV 5.18 hold on your own data, then decide between the default and the hi variant per call site, since the hi variant drops compression speed by roughly four times for a smaller output.

Frequently asked questions

How do I use LZAV in a C project?

LZAV is header-only, so you include lzav.h and call the functions directly, with no install step. The README's example calls lzav_compress_bound for the output size, allocates that buffer, and then calls lzav_compress_default, checking for a zero return when the source was not empty.

Does LZAV need a checksum on compressed data?

The README states that LZAV performs internal out-of-bounds checks and can be used safely when decompressing malformed or damaged data, so it does not require calculating a checksum or a hash of the compressed data. A checksum of the uncompressed data may still be required depending on the application.

What is the difference between lzav_compress_default and lzav_compress_hi?

The hi variant is for non-time-critical data such as static assets, and it uses a different bound function, lzav_compress_bound_hi. In the Silesia table on an Apple M1, LZAV 5.18 compresses at 627 MB/s with a 39.91 percent ratio, while LZAV 5.18 HI compresses at 147 MB/s with a 34.85 percent ratio.

How does LZAV compare with LZ4?

The README says LZ4 compresses faster while LZAV provides 16 percent greater storage space savings, with LZAV's compression only about 30 percent slower than LZ4's. It also reports 22 percent greater storage savings than LZ4 on the enwik9 dataset, and points to lzbench for a wider comparison.

Official sources

  1. avaneev/lzav on GitHub
  2. Issues
  3. License: MIT
  4. README
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/avaneev-lzav.svg)](https://hysenlabs.com/projects/avaneev-lzav)

Was this useful?