| 377 | |
| 378 | template <typename INT_T, typename ParquetType> |
| 379 | void RandomUnpackAndDeltaDecodeTest() { |
| 380 | constexpr int MAX_BITWIDTH = std::min<int>(BitPacking::MAX_BITWIDTH, |
| 381 | sizeof(INT_T) * 8); |
| 382 | for (int bit_width = 0; bit_width <= MAX_BITWIDTH; ++bit_width) { |
| 383 | const INT_T max_delta = bit_width == 0 ? 0 : (1UL << (bit_width - 1)) - 1; |
| 384 | const INT_T min_delta = bit_width == 0 ? 0 : -max_delta - 1; |
| 385 | |
| 386 | const std::vector<ParquetType> delta_data = GenerateRandomInput<ParquetType>( |
| 387 | NUM_IN_VALUES, min_delta, max_delta); |
| 388 | |
| 389 | const std::vector<int> lengths = GetLengths(); |
| 390 | |
| 391 | for (int length : lengths) { |
| 392 | std::vector<ParquetType> in_data; |
| 393 | |
| 394 | std::partial_sum(delta_data.begin(), delta_data.begin() + length, |
| 395 | std::back_inserter(in_data), |
| 396 | /// We add the elements as unsigned to have defined overflow. |
| 397 | ArithmeticUtil::AsUnsigned<std::plus, ParquetType>); |
| 398 | |
| 399 | /// Convert the input values to INT_T to compare them with the output. |
| 400 | const std::vector<INT_T> in_data_as_int_t(in_data.begin(), in_data.end()); |
| 401 | |
| 402 | DeltaData<ParquetType> encoded = DeltaEncode<ParquetType>(in_data, bit_width); |
| 403 | |
| 404 | const std::vector<int> strides = {sizeof(INT_T), sizeof(INT_T) + 5, |
| 405 | 2 * sizeof(INT_T) + 5}; |
| 406 | |
| 407 | for (int stride : strides) { |
| 408 | bool decode_error = false; |
| 409 | std::vector<uint8_t> out(in_data.size() * stride); |
| 410 | |
| 411 | uint8_t* out_ptr = nullptr; |
| 412 | if (in_data.empty()) { |
| 413 | /// We do not copy anything and do not increment the pointer if we do not have |
| 414 | /// any elements. |
| 415 | out_ptr = out.data(); |
| 416 | } else { |
| 417 | /// If we have elements, copy the base value to the beginning so the vector |
| 418 | /// after unpacking can be compared directly to the vector of input numbers. |
| 419 | memcpy(out.data(), &encoded.base_value, sizeof(INT_T)); |
| 420 | out_ptr = out.data() + stride; |
| 421 | } |
| 422 | |
| 423 | /// Converting to ParquetType. |
| 424 | ParquetType base_value = encoded.base_value; |
| 425 | ParquetType delta_offset = encoded.delta_offset; |
| 426 | |
| 427 | std::pair<const uint8_t*, int64_t> res |
| 428 | = BitPacking::UnpackAndDeltaDecodeValues<INT_T, ParquetType>( |
| 429 | bit_width, encoded.packed_deltas.data(), encoded.packed_deltas.size(), |
| 430 | &base_value, delta_offset, encoded.num_values, |
| 431 | reinterpret_cast<INT_T*>(out_ptr), stride, &decode_error); |
| 432 | |
| 433 | EXPECT_FALSE(decode_error); |
| 434 | EXPECT_EQ(in_data_as_int_t.size(), res.second + (length == 0 ? 0 : 1)); |
| 435 | ExpectEqualsWithStride<INT_T>(in_data_as_int_t.data(), in_data_as_int_t.size(), |
| 436 | out.data(), out.size(), stride); |