| Line |
Branch |
Exec |
Source |
| 1 |
|
|
// <Compress.hpp> -*- C++ -*- |
| 2 |
|
|
|
| 3 |
|
|
#pragma once |
| 4 |
|
|
|
| 5 |
|
|
#include "simdb/Assert.hpp" |
| 6 |
|
|
#include "simdb/Exceptions.hpp" |
| 7 |
|
|
#include <cstring> |
| 8 |
|
|
#include <vector> |
| 9 |
|
|
#include <zlib.h> |
| 10 |
|
|
|
| 11 |
|
|
namespace simdb { |
| 12 |
|
|
|
| 13 |
|
|
/// Compression modes of operation. |
| 14 |
|
|
enum class CompressionModes { COMPRESSED, UNCOMPRESSED }; |
| 15 |
|
|
|
| 16 |
|
|
/// Compression levels for zlib. |
| 17 |
|
|
enum class CompressionLevel { |
| 18 |
|
|
DISABLED = Z_NO_COMPRESSION, |
| 19 |
|
|
DEFAULT = Z_DEFAULT_COMPRESSION, |
| 20 |
|
|
FASTEST = Z_BEST_SPEED, |
| 21 |
|
|
HIGHEST = Z_BEST_COMPRESSION |
| 22 |
|
|
}; |
| 23 |
|
|
|
| 24 |
|
|
/// Perform zlib compression. |
| 25 |
|
26689 |
inline void compressData(const void* data_ptr, size_t num_bytes, std::vector<char>& out, const int compression_level) |
| 26 |
|
|
{ |
| 27 |
2/2
✓ Branch 2 → 3 taken 1 time.
✓ Branch 2 → 5 taken 26688 times.
|
26689 |
if (num_bytes == 0) |
| 28 |
|
|
{ |
| 29 |
|
1 |
out.clear(); |
| 30 |
|
1 |
return; |
| 31 |
|
|
} |
| 32 |
|
|
|
| 33 |
|
26688 |
z_stream defstream{}; |
| 34 |
|
26688 |
defstream.zalloc = Z_NULL; |
| 35 |
|
26688 |
defstream.zfree = Z_NULL; |
| 36 |
|
26688 |
defstream.opaque = Z_NULL; |
| 37 |
|
|
|
| 38 |
|
26688 |
defstream.avail_in = (uInt)num_bytes; |
| 39 |
|
26688 |
defstream.next_in = (Bytef*)data_ptr; |
| 40 |
|
|
|
| 41 |
|
|
// Compression can technically result in a larger output, although it is not |
| 42 |
|
|
// likely except for possibly very small input vectors. There is no |
| 43 |
|
|
// deterministic value for the maximum number of bytes after decompression, |
| 44 |
|
|
// but we can choose a very safe minimum. |
| 45 |
|
26688 |
auto max_bytes_after = num_bytes * 2; |
| 46 |
2/2
✓ Branch 5 → 6 taken 5 times.
✓ Branch 5 → 7 taken 26683 times.
|
26688 |
if (max_bytes_after < 1000) |
| 47 |
|
|
{ |
| 48 |
|
5 |
max_bytes_after = 1000; |
| 49 |
|
|
} |
| 50 |
1/1
✓ Branch 7 → 8 taken 26688 times.
|
26688 |
out.resize(max_bytes_after); |
| 51 |
|
|
|
| 52 |
|
26688 |
defstream.avail_out = (uInt)(out.size()); |
| 53 |
|
26688 |
defstream.next_out = (Bytef*)(out.data()); |
| 54 |
|
|
|
| 55 |
1/1
✓ Branch 10 → 11 taken 26688 times.
|
26688 |
deflateInit(&defstream, compression_level); |
| 56 |
1/1
✓ Branch 11 → 12 taken 26688 times.
|
26688 |
deflate(&defstream, Z_FINISH); |
| 57 |
1/1
✓ Branch 12 → 13 taken 26688 times.
|
26688 |
deflateEnd(&defstream); |
| 58 |
|
|
|
| 59 |
|
26688 |
auto num_bytes_after = (int)defstream.total_out; |
| 60 |
1/1
✓ Branch 13 → 14 taken 26688 times.
|
26688 |
out.resize(num_bytes_after); |
| 61 |
|
|
} |
| 62 |
|
|
|
| 63 |
|
|
/// Perform zlib compression. |
| 64 |
|
|
inline void compressData(const void* data_ptr, size_t num_bytes, std::vector<char>& out, |
| 65 |
|
|
CompressionLevel compression_level = CompressionLevel::DEFAULT) |
| 66 |
|
|
{ |
| 67 |
|
|
compressData(data_ptr, num_bytes, out, static_cast<int>(compression_level)); |
| 68 |
|
|
} |
| 69 |
|
|
|
| 70 |
|
|
/// Perform zlib compression on a vector. |
| 71 |
|
|
template <typename T> |
| 72 |
|
26689 |
inline void compressData(const std::vector<T>& in, std::vector<char>& out, const int compression_level) |
| 73 |
|
|
{ |
| 74 |
|
26689 |
const void* data_ptr = in.data(); |
| 75 |
|
26689 |
size_t num_bytes = in.size() * sizeof(T); |
| 76 |
|
26689 |
compressData(data_ptr, num_bytes, out, compression_level); |
| 77 |
|
26689 |
} |
| 78 |
|
|
|
| 79 |
|
|
/// Perform zlib compression on a vector. |
| 80 |
|
|
template <typename T> |
| 81 |
|
1001 |
inline void compressData(const std::vector<T>& in, std::vector<char>& out, |
| 82 |
|
|
CompressionLevel compression_level = CompressionLevel::DEFAULT) |
| 83 |
|
|
{ |
| 84 |
|
1001 |
compressData(in, out, static_cast<int>(compression_level)); |
| 85 |
|
1001 |
} |
| 86 |
|
|
|
| 87 |
|
|
/// Perform zlib decompression. |
| 88 |
|
21192 |
template <typename T> inline void decompressData(const std::vector<char>& in, std::vector<T>& out) |
| 89 |
|
|
{ |
| 90 |
3/4
void simdb::decompressData<char>(std::vector<char, std::allocator<char> > const&, std::vector<char, std::allocator<char> >&):
✗ Branch 3 → 4 not taken.
✓ Branch 3 → 6 taken 12679 times.
void simdb::decompressData<double>(std::vector<char, std::allocator<char> > const&, std::vector<double, std::allocator<double> >&):
✓ Branch 3 → 4 taken 1 time.
✓ Branch 3 → 6 taken 8512 times.
|
21192 |
if (in.empty()) |
| 91 |
|
|
{ |
| 92 |
|
1 |
out.clear(); |
| 93 |
|
1 |
return; |
| 94 |
|
|
} |
| 95 |
|
|
|
| 96 |
|
21191 |
constexpr size_t CHUNK_SIZE = 1024 * 64; |
| 97 |
|
21191 |
std::vector<char> decompressed_buffer; |
| 98 |
2/2
void simdb::decompressData<char>(std::vector<char, std::allocator<char> > const&, std::vector<char, std::allocator<char> >&):
✓ Branch 7 → 8 taken 12679 times.
void simdb::decompressData<double>(std::vector<char, std::allocator<char> > const&, std::vector<double, std::allocator<double> >&):
✓ Branch 7 → 8 taken 8512 times.
|
21191 |
decompressed_buffer.reserve(CHUNK_SIZE); |
| 99 |
|
|
|
| 100 |
|
21191 |
z_stream stream{}; |
| 101 |
|
21191 |
stream.next_in = reinterpret_cast<Bytef*>(const_cast<char*>(in.data())); |
| 102 |
|
21191 |
stream.avail_in = static_cast<uInt>(in.size()); |
| 103 |
|
|
|
| 104 |
4/26
void simdb::decompressData<char>(std::vector<char, std::allocator<char> > const&, std::vector<char, std::allocator<char> >&):
✓ Branch 10 → 11 taken 12679 times.
✗ Branch 11 → 12 not taken.
✓ Branch 11 → 30 taken 12679 times.
✗ Branch 14 → 15 not taken.
✗ Branch 15 → 16 not taken.
✗ Branch 17 → 18 not taken.
✗ Branch 21 → 22 not taken.
✗ Branch 22 → 23 not taken.
✗ Branch 23 → 24 not taken.
✗ Branch 24 → 25 not taken.
✗ Branch 25 → 26 not taken.
✗ Branch 26 → 27 not taken.
✗ Branch 28 → 29 not taken.
void simdb::decompressData<double>(std::vector<char, std::allocator<char> > const&, std::vector<double, std::allocator<double> >&):
✓ Branch 10 → 11 taken 8512 times.
✗ Branch 11 → 12 not taken.
✓ Branch 11 → 30 taken 8512 times.
✗ Branch 14 → 15 not taken.
✗ Branch 15 → 16 not taken.
✗ Branch 17 → 18 not taken.
✗ Branch 21 → 22 not taken.
✗ Branch 22 → 23 not taken.
✗ Branch 23 → 24 not taken.
✗ Branch 24 → 25 not taken.
✗ Branch 25 → 26 not taken.
✗ Branch 26 → 27 not taken.
✗ Branch 28 → 29 not taken.
|
21191 |
simdb_assert(inflateInit(&stream) == Z_OK, "Failed to initialize zlib inflate stream."); |
| 105 |
|
|
|
| 106 |
|
|
do |
| 107 |
|
|
{ |
| 108 |
|
21191 |
size_t current_size = decompressed_buffer.size(); |
| 109 |
2/2
void simdb::decompressData<char>(std::vector<char, std::allocator<char> > const&, std::vector<char, std::allocator<char> >&):
✓ Branch 31 → 32 taken 12679 times.
void simdb::decompressData<double>(std::vector<char, std::allocator<char> > const&, std::vector<double, std::allocator<double> >&):
✓ Branch 31 → 32 taken 8512 times.
|
21191 |
decompressed_buffer.resize(current_size + CHUNK_SIZE); |
| 110 |
|
21191 |
stream.next_out = reinterpret_cast<Bytef*>(&decompressed_buffer[current_size]); |
| 111 |
|
21191 |
stream.avail_out = CHUNK_SIZE; |
| 112 |
|
|
|
| 113 |
2/2
void simdb::decompressData<char>(std::vector<char, std::allocator<char> > const&, std::vector<char, std::allocator<char> >&):
✓ Branch 33 → 34 taken 12679 times.
void simdb::decompressData<double>(std::vector<char, std::allocator<char> > const&, std::vector<double, std::allocator<double> >&):
✓ Branch 33 → 34 taken 8512 times.
|
21191 |
int ret = inflate(&stream, Z_NO_FLUSH); |
| 114 |
|
|
|
| 115 |
4/8
void simdb::decompressData<char>(std::vector<char, std::allocator<char> > const&, std::vector<char, std::allocator<char> >&):
✓ Branch 34 → 35 taken 12679 times.
✗ Branch 34 → 37 not taken.
✗ Branch 35 → 36 not taken.
✓ Branch 35 → 37 taken 12679 times.
void simdb::decompressData<double>(std::vector<char, std::allocator<char> > const&, std::vector<double, std::allocator<double> >&):
✓ Branch 34 → 35 taken 8512 times.
✗ Branch 34 → 37 not taken.
✗ Branch 35 → 36 not taken.
✓ Branch 35 → 37 taken 8512 times.
|
21191 |
if (ret != Z_OK && ret != Z_STREAM_END) |
| 116 |
|
|
{ |
| 117 |
0/2
void simdb::decompressData<char>(std::vector<char, std::allocator<char> > const&, std::vector<char, std::allocator<char> >&):
✗ Branch 36 → 37 not taken.
void simdb::decompressData<double>(std::vector<char, std::allocator<char> > const&, std::vector<double, std::allocator<double> >&):
✗ Branch 36 → 37 not taken.
|
✗ |
inflateEnd(&stream); |
| 118 |
|
|
} |
| 119 |
6/34
void simdb::decompressData<char>(std::vector<char, std::allocator<char> > const&, std::vector<char, std::allocator<char> >&):
✓ Branch 37 → 38 taken 12679 times.
✗ Branch 37 → 40 not taken.
✗ Branch 38 → 39 not taken.
✓ Branch 38 → 40 taken 12679 times.
✗ Branch 41 → 42 not taken.
✓ Branch 41 → 64 taken 12679 times.
✗ Branch 44 → 45 not taken.
✗ Branch 45 → 46 not taken.
✗ Branch 47 → 48 not taken.
✗ Branch 52 → 53 not taken.
✗ Branch 53 → 54 not taken.
✗ Branch 56 → 57 not taken.
✗ Branch 57 → 58 not taken.
✗ Branch 58 → 59 not taken.
✗ Branch 59 → 60 not taken.
✗ Branch 60 → 61 not taken.
✗ Branch 62 → 63 not taken.
void simdb::decompressData<double>(std::vector<char, std::allocator<char> > const&, std::vector<double, std::allocator<double> >&):
✓ Branch 37 → 38 taken 8512 times.
✗ Branch 37 → 40 not taken.
✗ Branch 38 → 39 not taken.
✓ Branch 38 → 40 taken 8512 times.
✗ Branch 41 → 42 not taken.
✓ Branch 41 → 64 taken 8512 times.
✗ Branch 44 → 45 not taken.
✗ Branch 45 → 46 not taken.
✗ Branch 47 → 48 not taken.
✗ Branch 52 → 53 not taken.
✗ Branch 53 → 54 not taken.
✗ Branch 56 → 57 not taken.
✗ Branch 57 → 58 not taken.
✗ Branch 58 → 59 not taken.
✗ Branch 59 → 60 not taken.
✗ Branch 60 → 61 not taken.
✗ Branch 62 → 63 not taken.
|
21191 |
simdb_assert(ret == Z_OK || ret == Z_STREAM_END, |
| 120 |
|
|
"Decompression failed with zlib error code: " + std::to_string(ret)); |
| 121 |
2/4
void simdb::decompressData<char>(std::vector<char, std::allocator<char> > const&, std::vector<char, std::allocator<char> >&):
✗ Branch 64 → 30 not taken.
✓ Branch 64 → 65 taken 12679 times.
void simdb::decompressData<double>(std::vector<char, std::allocator<char> > const&, std::vector<double, std::allocator<double> >&):
✗ Branch 64 → 30 not taken.
✓ Branch 64 → 65 taken 8512 times.
|
21191 |
} while (stream.avail_out == 0); |
| 122 |
|
|
|
| 123 |
|
|
// Adjust actual used size |
| 124 |
|
21191 |
size_t current_size = decompressed_buffer.size(); |
| 125 |
2/2
void simdb::decompressData<char>(std::vector<char, std::allocator<char> > const&, std::vector<char, std::allocator<char> >&):
✓ Branch 66 → 67 taken 12679 times.
void simdb::decompressData<double>(std::vector<char, std::allocator<char> > const&, std::vector<double, std::allocator<double> >&):
✓ Branch 66 → 67 taken 8512 times.
|
21191 |
decompressed_buffer.resize(current_size - stream.avail_out); |
| 126 |
2/2
void simdb::decompressData<char>(std::vector<char, std::allocator<char> > const&, std::vector<char, std::allocator<char> >&):
✓ Branch 67 → 68 taken 12679 times.
void simdb::decompressData<double>(std::vector<char, std::allocator<char> > const&, std::vector<double, std::allocator<double> >&):
✓ Branch 67 → 68 taken 8512 times.
|
21191 |
inflateEnd(&stream); |
| 127 |
|
|
|
| 128 |
|
|
// Convert decompressed bytes to std::vector<T> |
| 129 |
|
21191 |
size_t byte_count = decompressed_buffer.size(); |
| 130 |
1/12
✗ Branch 69 → 70 not taken.
✓ Branch 69 → 88 taken 8512 times.
✗ Branch 72 → 73 not taken.
✗ Branch 73 → 74 not taken.
✗ Branch 75 → 76 not taken.
✗ Branch 79 → 80 not taken.
✗ Branch 80 → 81 not taken.
✗ Branch 81 → 82 not taken.
✗ Branch 82 → 83 not taken.
✗ Branch 83 → 84 not taken.
✗ Branch 84 → 85 not taken.
✗ Branch 86 → 87 not taken.
|
8512 |
simdb_assert(byte_count % sizeof(T) == 0, "Decompressed data size is not aligned with type T."); |
| 131 |
|
|
|
| 132 |
|
21191 |
size_t elem_count = byte_count / sizeof(T); |
| 133 |
2/2
void simdb::decompressData<char>(std::vector<char, std::allocator<char> > const&, std::vector<char, std::allocator<char> >&):
✓ Branch 69 → 70 taken 12679 times.
void simdb::decompressData<double>(std::vector<char, std::allocator<char> > const&, std::vector<double, std::allocator<double> >&):
✓ Branch 88 → 89 taken 8512 times.
|
21191 |
out.resize(elem_count); |
| 134 |
|
21191 |
std::memcpy(out.data(), decompressed_buffer.data(), byte_count); |
| 135 |
|
21191 |
} |
| 136 |
|
|
|
| 137 |
|
|
} // namespace simdb |
| 138 |
|
|
|