include/simdb/
Coverage:
low: ≥ 0%
medium: ≥ 75.0%
high: ≥ 90.0%
Lines:
90 / 94
95.7%
Branches:
41 / 111
36.9%
Functions:
7 / 7
100.0%

utils/Compress.hpp
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