15#include <catch_amalgamated.hpp>
25std::vector<uint8_t> bigEndian(std::vector<T>
const&
values)
29 w.
put(std::bit_cast<std::conditional_t<
sizeof(T) == 4, uint32_t, std::conditional_t<
sizeof(T) == 8, uint64_t, std::conditional_t<
sizeof(T) == 2, uint16_t, uint8_t>>>>(
v));
36 std::vector<uint8_t>
file = std::vector<uint8_t>(100, 0);
39 BranchBuilder(
char leafClass,
int fixedLen = 1)
48 void add(
Algo algo, std::vector<uint8_t>
const&
values, int32_t
nEntries,
size_t tail = 0,
size_t chunkSize = 0xffffff)
52 file.insert(
file.end(), basket.begin(), basket.end());
56 void addEmbedded(std::vector<uint8_t>
const&
values, int32_t
nEntries)
66 std::vector<uint8_t>
v{1, 2, 3, 4, 5, 6, 7, 8};
68 CHECK(
v == std::vector<uint8_t>{4, 3, 2, 1, 8, 7, 6, 5});
70 CHECK(
v == std::vector<uint8_t>{5, 6, 7, 8, 1, 2, 3, 4});
72 CHECK(
v == std::vector<uint8_t>{6, 5, 8, 7, 2, 1, 4, 3});
75TEST_CASE(
"float values across codecs, uncompressed and embedded baskets")
80 for (
auto algo : {Algo::ZSTD, Algo::None, Algo::ZLIB, Algo::LZMA, Algo::LZ4}) {
82 for (
int i = 0;
i < 1000; ++
i) {
89 std::vector<float> tail{-1.f, -2.f, -3.f};
90 b.addEmbedded(bigEndian(tail), tail.size());
93 for (
bool mappable : {
true,
false}) {
94 for (
int threads : {1, 4}) {
97 options.threads = threads;
99 std::vector<float> out(
expected.size(), 42.f);
100 decoder.decodeValues(
b.branch, (uint8_t*)out.data(), out.size() *
sizeof(
float));
106TEST_CASE(
"decoding stops exactly at the value region for every codec")
111 for (
auto algo : {Algo::ZSTD, Algo::ZLIB, Algo::LZMA, Algo::LZ4, Algo::None}) {
112 for (
size_t chunkSize : {size_t(100000), size_t(0xffffff)}) {
113 INFO(
"algorithm " << (
int)algo <<
", chunk size " << chunkSize);
114 BranchBuilder
b{
'D'};
115 std::vector<double>
values(70001);
116 for (
size_t i = 0;
i <
values.size(); ++
i) {
122 std::vector<double> out(
values.size() + 16, 1e300);
123 decoder.decodeValues(
b.branch, (uint8_t*)out.data(),
values.size() *
sizeof(
double));
125 CHECK(std::all_of(out.begin() +
values.size(), out.end(), [](
double v) { return v == 1e300; }));
130TEST_CASE(
"fixed-size arrays and wrong destination sizes")
132 BranchBuilder
b{
'S', 3};
133 std::vector<int16_t>
values{1, 2, 3, -4, -5, -6};
134 b.add(Algo::ZSTD, bigEndian(
values), 2);
137 std::vector<int16_t> out(6);
138 decoder.decodeValues(
b.branch, (uint8_t*)out.data(), 12);
140 CHECK_THROWS_AS(decoder.decodeValues(
b.branch, (uint8_t*)out.data(), 10),
FormatError);
143TEST_CASE(
"booleans are packed across basket and window boundaries")
147 BranchBuilder
b{
'O'};
150 std::vector<uint8_t>
bytes;
151 for (
int i = 0;
i <
size; ++
i) {
152 bool v = ((
expected.size() * 7) % 3) == 0;
155 bytes.push_back(
v ? (
i % 2 ? 1 : 0x80) : 0);
161 std::vector<uint8_t> bitmap((
expected.size() + 7) / 8, 0xFF);
162 decoder.decodeBooleans(
b.branch, bitmap.data(), bitmap.size());
168 for (
size_t i =
expected.size();
i < bitmap.size() * 8; ++
i) {
169 CHECK(((bitmap[
i / 8] >> (
i % 8)) & 1) == 0);
175 BranchBuilder
sizes{
'I'};
176 sizes.branch.name =
"fY_size";
177 std::vector<int32_t>
s1{2, 0, 3}, s2{1};
178 sizes.add(Algo::ZLIB, bigEndian(
s1), 3);
179 sizes.add(Algo::None, bigEndian(s2), 1);
182 BranchBuilder
values{
'D'};
183 values.branch.name =
"fY";
184 values.branch.countBranch =
"fY_size";
185 std::vector<double>
v1{1.5, 2.5},
v2{3.5, 4.5, 5.5, 6.5};
186 values.add(Algo::LZ4, bigEndian(
v1), 2);
187 values.add(Algo::ZSTD, bigEndian(
v2), 2);
189 std::vector<uint8_t> file =
sizes.file;
191 auto shift = file.size() - 100;
192 file.insert(file.end(),
values.file.begin() + 100,
values.file.end());
193 for (
auto& basket :
values.branch.baskets) {
194 basket.seek += shift;
201 std::vector<double> out(6);
202 decoder.decodeVLAValues(
values.branch,
offsets, (uint8_t*)out.data(), out.size() *
sizeof(
double));
203 CHECK(out == std::vector<double>{1.5, 2.5, 3.5, 4.5, 5.5, 6.5});
208 BranchBuilder
b{
'I'};
209 std::vector<int32_t>
values{1, 2, 3};
210 b.add(Algo::ZSTD, bigEndian(
values), 3);
213 std::vector<int32_t> out(3);
215 SECTION(
"entry count in the header differs from the TBranch")
217 auto branch =
b.branch;
218 branch.
baskets[0].nEntries = 2;
220 CHECK_THROWS_AS(decoder.decodeValues(branch, (uint8_t*)out.data(), 8),
CorruptData);
222 SECTION(
"baskets do not cover the entries")
224 auto branch =
b.branch;
226 std::vector<int32_t> big(4);
227 CHECK_THROWS_AS(decoder.decodeValues(branch, (uint8_t*)big.data(), 16),
CorruptData);
229 SECTION(
"basket size differs from the TBranch")
231 auto branch =
b.branch;
233 CHECK_THROWS_AS(decoder.decodeValues(branch, (uint8_t*)out.data(), 12),
CorruptData);
235 SECTION(
"basket location past the end of the file")
237 auto branch =
b.branch;
238 branch.
baskets[0].seek =
b.file.size();
241 CHECK_THROWS_AS(d2.decodeValues(branch, (uint8_t*)out.data(), 12),
CorruptData);
static constexpr size_t kBooleanWindow
Size of the boolean window, the only decode-side scratch memory.
A file made of concatenated in-memory buffers.
GLuint GLsizei const GLuint const GLintptr * offsets
GLuint GLsizei const GLuint const GLintptr const GLsizeiptr * sizes
GLuint GLfloat GLfloat GLfloat GLfloat GLfloat GLfloat GLfloat GLfloat s1
GLboolean GLboolean GLboolean b
GLsizei GLsizei GLchar * source
GLenum GLsizei GLsizei GLint * values
GLubyte GLubyte GLubyte GLubyte w
GLfloat GLfloat GLfloat v2
std::vector< uint8_t > makeBasket(Algo algo, std::span< const uint8_t > values, int32_t nevbuf, size_t tailBytes=0, size_t chunkSize=0xffffff)
void byteswapInPlace(uint8_t *data, size_t count, size_t typeSize)
Byteswaps count big-endian values of typeSize bytes in place.
int32_t const char * file
std::vector< BasketRef > baskets
std::map< std::string, ID > expected
TEST_CASE("byteswapInPlace")