| 160 | |
| 161 | template<typename T> |
| 162 | void test_compression(CompressionAlg& alg, std::vector<T> src, bool force_offset_zero = true) { |
| 163 | if (force_offset_zero) { |
| 164 | // Force offset of 0 for bitpacking |
| 165 | src[0] = 0; |
| 166 | } |
| 167 | auto pageSize = 4096; |
| 168 | std::vector<uint8_t> dest(pageSize); |
| 169 | |
| 170 | const auto& [min, max] = std::minmax_element(src.begin(), src.end()); |
| 171 | auto metadata = |
| 172 | CompressionMetadata(StorageValue(*min), StorageValue(*max), alg.getCompressionType()); |
| 173 | // For simplicity, we'll ignore the possibility of it requiring multiple pages |
| 174 | // That's tested separately |
| 175 | |
| 176 | auto numValuesRemaining = src.size(); |
| 177 | const uint8_t* srcCursor = (uint8_t*)src.data(); |
| 178 | alg.compressNextPage(srcCursor, numValuesRemaining, dest.data(), pageSize, metadata); |
| 179 | std::vector<T> decompressed(src.size()); |
| 180 | alg.decompressFromPage(dest.data(), 0 /*srcOffset*/, (uint8_t*)decompressed.data(), |
| 181 | 0 /*dstOffset*/, src.size(), metadata); |
| 182 | EXPECT_EQ(src, decompressed); |
| 183 | // works with all bit widths (but not all offsets) |
| 184 | T value = 0; |
| 185 | if (!force_offset_zero) { |
| 186 | // make sure we can update in place to not fail runtime assertions |
| 187 | value = *std::min_element(src.begin(), src.end()); |
| 188 | } |
| 189 | |
| 190 | alg.setValuesFromUncompressed((uint8_t*)&value, 0 /*srcOffset*/, (uint8_t*)dest.data(), |
| 191 | 1 /*dstOffset*/, 1 /*numValues*/, metadata, nullptr /*nullMask*/); |
| 192 | alg.decompressFromPage(dest.data(), 0 /*srcOffset*/, (uint8_t*)decompressed.data(), |
| 193 | 0 /*dstOffset*/, src.size(), metadata); |
| 194 | src[1] = value; |
| 195 | EXPECT_EQ(decompressed, src); |
| 196 | EXPECT_EQ(decompressed[1], value); |
| 197 | |
| 198 | for (auto i = 0u; i < src.size(); i++) { |
| 199 | alg.decompressFromPage(dest.data(), i, (uint8_t*)decompressed.data(), i, 1 /*numValues*/, |
| 200 | metadata); |
| 201 | EXPECT_EQ(decompressed[i], src[i]); |
| 202 | } |
| 203 | EXPECT_EQ(decompressed, src); |
| 204 | |
| 205 | // Decompress part of a page |
| 206 | decompressed.clear(); |
| 207 | decompressed.resize(src.size() / 2); |
| 208 | alg.decompressFromPage(dest.data(), src.size() / 3 /*srcOffset*/, (uint8_t*)decompressed.data(), |
| 209 | 0 /*dstOffset*/, src.size() / 2 /*numValues*/, metadata); |
| 210 | auto expected = std::vector(src); |
| 211 | expected.erase(expected.begin(), expected.begin() + src.size() / 3); |
| 212 | expected.resize(src.size() / 2); |
| 213 | EXPECT_EQ(decompressed, expected); |
| 214 | |
| 215 | decompressed.clear(); |
| 216 | decompressed.resize(src.size() / 2); |
| 217 | alg.decompressFromPage(dest.data(), src.size() / 7 /*srcOffset*/, (uint8_t*)decompressed.data(), |
| 218 | 0 /*dstOffset*/, src.size() / 2 /*numValues*/, metadata); |
| 219 | expected = std::vector(src); |
no test coverage detected