Skip to main content

Compression Guide

Overview

HSHM provides a unified compression framework that wraps multiple lossless and lossy compression libraries behind a common Compressor interface. A factory system with preset levels (FAST, BALANCED, BEST) makes it easy to select and configure compressors at runtime.

Headers:

#include <clio_ctp/compress/compress.h>          // Base interface
#include <clio_ctp/compress/compress_factory.h> // Factory + presets

Compile-time flag: CTP_ENABLE_COMPRESS

Supported Libraries

Lossless Compressors (with compression levels)

LibraryClassFAST LevelBALANCED LevelBEST Level
bzip2Bzip2WithModes169
zstdZstdWithModes1319
lz4Lz4WithModesLZ4 defaultLZ4 HC level 6LZ4 HC level 12
zlibZlibWithModes169
lzmaLzmaWithModes069
brotliBrotliWithModes1611

Lossless Compressors (single mode)

LibraryClassNotes
snappySnappyNo compression levels; always uses default
blosc2BloscNo compression levels; always uses default

Lossy Compressors (via LibPressio)

Requires CTP_ENABLE_LIBPRESSIO in addition to CTP_ENABLE_COMPRESS.

LibraryCompressor ID
zfp"zfp"
sz3"sz3"
fpzip"fpzip"

Direct-use Compressors

These classes can be used directly without the factory:

LibraryClassHeader
bzip2ctp::Bzip2<clio_ctp/compress/bzip2.h>
zstdctp::Zstd<clio_ctp/compress/zstd.h>
lz4ctp::Lz4<clio_ctp/compress/lz4.h>
zlibctp::Zlib<clio_ctp/compress/zlib.h>
lzmactp::Lzma<clio_ctp/compress/lzma.h>
brotlictp::Brotli<clio_ctp/compress/brotli.h>
snappyctp::Snappy<clio_ctp/compress/snappy.h>
blosc2ctp::Blosc<clio_ctp/compress/blosc.h>
lzoctp::Lzo<clio_ctp/compress/lzo.h>

API Reference

ctp::Compressor (Base Interface)

#include <cstddef>  // size_t

namespace ctp {

class Compressor {
public:
virtual ~Compressor() = default;

/**
* Compress input buffer into output buffer.
* @param output Pre-allocated output buffer
* @param output_size [in] capacity of output buffer; [out] actual compressed size
* @param input Input data to compress
* @param input_size Size of input data in bytes
* @return true on success, false on failure
*/
virtual bool Compress(void* output, size_t& output_size,
void* input, size_t input_size) = 0;

/**
* Decompress input buffer into output buffer.
* @param output Pre-allocated output buffer
* @param output_size [in] capacity of output buffer; [out] actual decompressed size
* @param input Compressed input data
* @param input_size Size of compressed data in bytes
* @return true on success, false on failure
*/
virtual bool Decompress(void* output, size_t& output_size,
void* input, size_t input_size) = 0;
};

} // namespace ctp

ctp::CompressionPreset

namespace ctp {

enum class CompressionPreset {
FAST, // Fast compression, lower ratio
BALANCED, // Balanced speed and ratio (default)
BEST, // Best ratio, slower
DEFAULT // Default configuration (treated as BALANCED)
};

} // namespace ctp

ctp::CompressionFactory

#include <memory>
#include <string>
#include <utility>

namespace ctp {

class Compressor; // declared in compress.h (see interface above)
enum class CompressionPreset { FAST, BALANCED, BEST, DEFAULT };

class CompressionFactory {
public:
/**
* Create a compressor with the specified preset.
* @param library_name Library name (case-insensitive): "bzip2", "zstd",
* "lz4", "zlib", "lzma", "brotli", "snappy", "blosc2",
* "zfp", "sz3", "fpzip"
* @param preset Compression preset (default: BALANCED)
* @return Unique pointer to compressor, or nullptr if the library is
* unknown or its backend is disabled at build time
*/
static std::unique_ptr<Compressor> GetPreset(
const std::string& library_name,
CompressionPreset preset = CompressionPreset::BALANCED);

/**
* Encode library name + preset into a unique integer ID.
* Useful for model training and runtime compression selection.
*
* ID format: base_id * 10 + preset_id
* Lossless base IDs: bzip2=1, zstd=2, lz4=3, zlib=4, lzma=5, brotli=6, snappy=7, blosc2=8
* Lossy base IDs: zfp=10, sz3=11, fpzip=12
* Preset IDs: FAST=1, BALANCED=2, BEST=3 (single-mode codecs always use 2)
*
* @return Integer ID, or 0 if unknown library
*/
static int GetLibraryId(const std::string& library_name,
CompressionPreset preset);

/**
* Decode a library ID back to (library_name, preset).
* Reverse of GetLibraryId().
*/
static std::pair<std::string, CompressionPreset> GetLibraryInfo(int library_id);

/**
* Convert a preset enum to a string ("fast", "balanced", "best", "default").
*/
static std::string GetPresetName(CompressionPreset preset);
};

} // namespace ctp

Examples

Direct Usage (No Factory)

#include <clio_ctp/compress/zstd.h>
#include <cassert>
#include <string>
#include <vector>

// The concrete codecs are only defined when the build enables compression
// (CTP_ENABLE_COMPRESS); guard usage so it compiles in both configurations.
#if CTP_ENABLE_COMPRESS
void example() {
ctp::Zstd zstd;

std::string raw = "Hello, World!";
std::vector<char> compressed(1024);
std::vector<char> decompressed(1024);

// Compress: compressed_size is capacity on input, byte count on output.
size_t compressed_size = compressed.size();
bool ok = zstd.Compress(compressed.data(), compressed_size,
raw.data(), raw.size());
assert(ok);

// Decompress: decompressed_size is capacity on input, byte count on output.
size_t decompressed_size = decompressed.size();
ok = zstd.Decompress(decompressed.data(), decompressed_size,
compressed.data(), compressed_size);
assert(ok);

std::string result(decompressed.data(), decompressed_size);
assert(result == raw);
}
#endif // CTP_ENABLE_COMPRESS

Factory with Presets

#include <clio_ctp/compress/compress_factory.h>
#include <cassert>
#include <string>
#include <vector>

#if CTP_ENABLE_COMPRESS
void example() {
// Create a fast zstd compressor.
auto compressor = ctp::CompressionFactory::GetPreset(
"zstd", ctp::CompressionPreset::FAST);
assert(compressor != nullptr);

std::string raw = "Hello, World!";
std::vector<char> compressed(1024);
std::vector<char> decompressed(1024);

size_t compressed_size = compressed.size();
compressor->Compress(compressed.data(), compressed_size,
raw.data(), raw.size());

size_t decompressed_size = decompressed.size();
compressor->Decompress(decompressed.data(), decompressed_size,
compressed.data(), compressed_size);

assert(std::string(decompressed.data(), decompressed_size) == raw);
}
#endif // CTP_ENABLE_COMPRESS

Library ID Encoding

#include <clio_ctp/compress/compress_factory.h>
#include <cassert>
#include <string>
#include <utility>

#if CTP_ENABLE_COMPRESS
void example() {
// Encode: zstd + FAST -> integer ID.
int id = ctp::CompressionFactory::GetLibraryId(
"zstd", ctp::CompressionPreset::FAST);
assert(id == 21); // base_id 2 * 10 + preset 1

// Decode: integer ID -> (name, preset).
auto [name, preset] = ctp::CompressionFactory::GetLibraryInfo(id);
assert(name == "zstd");
assert(preset == ctp::CompressionPreset::FAST);

// Get preset name.
std::string preset_name = ctp::CompressionFactory::GetPresetName(preset);
assert(preset_name == "fast");
}
#endif // CTP_ENABLE_COMPRESS

Iterating All Libraries

#include <clio_ctp/compress/compress_factory.h>
#include <cassert>
#include <string>
#include <vector>

#if CTP_ENABLE_COMPRESS
void example() {
std::vector<std::string> libraries = {
"bzip2", "zstd", "lz4", "zlib", "lzma", "brotli", "snappy", "blosc2"
};

std::string raw = "Test data for compression";
std::vector<char> compressed(1024);
std::vector<char> decompressed(1024);

for (const auto& lib : libraries) {
auto compressor = ctp::CompressionFactory::GetPreset(
lib, ctp::CompressionPreset::BALANCED);
if (!compressor) continue; // skipped if the backend is disabled

size_t csz = compressed.size();
size_t dsz = decompressed.size();

bool ok = compressor->Compress(compressed.data(), csz,
raw.data(), raw.size());
assert(ok);

ok = compressor->Decompress(decompressed.data(), dsz,
compressed.data(), csz);
assert(ok);

assert(std::string(decompressed.data(), dsz) == raw);
}
}
#endif // CTP_ENABLE_COMPRESS

Buffer Sizing

The caller is responsible for allocating output buffers with sufficient capacity:

  • Compress: The output buffer should be at least as large as the input. Some algorithms (e.g., LZ4) provide a compressBound() function. When in doubt, allocate 2x the input size.
  • Decompress: The output buffer must be large enough to hold the original uncompressed data. You must track the original size separately (e.g., in metadata).

The output_size parameter serves dual purpose:

  • Input: Maximum capacity of the output buffer
  • Output: Actual number of bytes written

Choosing a Compressor

Use CaseRecommended LibraryPreset
Low-latency streaminglz4FAST
General-purposezstdBALANCED
Maximum compression ratiolzmaBEST
Legacy compatibilityzlibBALANCED
Maximum decompression speedsnappyDEFAULT
Scientific floating-point datazfp / sz3BALANCED