9#ifndef GRIDFORMAT_COMPRESSION_LZ4_HPP_
10#define GRIDFORMAT_COMPRESSION_LZ4_HPP_
11#if GRIDFORMAT_HAVE_LZ4
22#include <gridformat/common/exceptions.hpp>
23#include <gridformat/common/serialization.hpp>
24#include <gridformat/common/logging.hpp>
29namespace GridFormat::Compression {
37 int acceleration_factor = 1;
43 static_assert(
sizeof(
typename Serialization::Byte) ==
sizeof(LZ4Byte));
45 struct BlockDecompressor {
46 using ByteType = LZ4Byte;
48 void operator()(std::span<const ByteType> in, std::span<ByteType> out)
const {
49 int decompressed_length = LZ4_decompress_safe(
52 static_cast<int>(in.size()),
53 static_cast<int>(out.size())
55 if (decompressed_length !=
static_cast<int>(out.size()))
56 throw IOError(
"(LZ4Compressor) Error upon block decompression");
64 : _opts(std::move(opts))
67 template<std::
integral HeaderType = std::
size_t>
69 static_assert(
sizeof(
typename Serialization::Byte) ==
sizeof(LZ4Byte));
70 if (std::numeric_limits<HeaderType>::max() < in.size())
71 throw TypeError(
"Chosen HeaderType is too small for given number of bytes");
72 if (std::numeric_limits<HeaderType>::max() < _opts.block_size)
73 throw TypeError(
"Chosen HeaderType is too small for given block size");
75 auto [blocks, out] = _compress<HeaderType>(in.template as_span_of<const LZ4Byte>());
77 in.resize(blocks.compressed_size());
81 template<
typename HeaderType>
87 return LZ4{std::move(opts)};
91 template<std::
integral HeaderType>
92 auto _compress(std::span<const LZ4Byte> in)
const {
93 HeaderType block_size =
static_cast<HeaderType
>(_opts.block_size);
94 HeaderType size_in_bytes =
static_cast<HeaderType
>(in.size());
97 Serialization compressed;
98 std::vector<LZ4Byte> block_buffer;
99 std::vector<HeaderType> compressed_block_sizes;
100 block_buffer.reserve(LZ4_COMPRESSBOUND(_opts.block_size));
101 compressed_block_sizes.reserve(blocks.number_of_blocks);
102 compressed.resize(block_buffer.capacity()*blocks.number_of_blocks);
104 HeaderType cur_in = 0;
105 HeaderType cur_out = 0;
106 auto out = compressed.template as_span_of<LZ4Byte>();
107 while (cur_in < size_in_bytes) {
109 const HeaderType cur_block_size = min(block_size, size_in_bytes - cur_in);
110 assert(cur_in + cur_block_size <= size_in_bytes);
112 const auto compressed_length = LZ4_compress_fast(
116 block_buffer.capacity(),
117 _opts.acceleration_factor
119 if (compressed_length == 0)
120 throw InvalidState(as_error(
"Error upon compression with LZ4"));
122 assert(cur_out + compressed_length <= out.size());
123 std::copy_n(block_buffer.data(),
125 out.data() + cur_out);
126 cur_in += cur_block_size;
127 cur_out += compressed_length;
128 compressed_block_sizes.push_back(
static_cast<HeaderType
>(compressed_length));
131 if (cur_in != size_in_bytes)
132 throw InvalidState(as_error(
"(LZ4Compressor) unexpected number of bytes processed"));
134 return std::make_tuple(
146namespace Detail {
inline constexpr bool _have_lz4 =
true; }
155namespace GridFormat::Compression {
157namespace Detail {
inline constexpr bool _have_lz4 =
false; }
161 template<
bool b =
false,
typename... Args>
162 explicit LZ4(Args&&...) {
static_assert(b,
"LZ4 compressor requires the LZ4 library."); }
Common classes used in the context of data compression.
Decompress compressed data.
constexpr LZ4 lz4
Instance of the lz4 compressor.
Definition: lz4.hpp:143
void decompress(Serialization &in, const CompressedBlocks< HeaderType > &blocks, const Decompressor &block_decompressor)
Decompress compressed data.
Definition: decompress.hpp:26
constexpr std::size_t default_block_size
as in VTK (https://gitlab.kitware.com/vtk/vtk/-/blob/65fc526a83ac829628a9462f61fa57f1801e2c7e/IO/XML/...
Definition: common.hpp:23