| 144 | /// @see CheckDecoderValuesChunked |
| 145 | template <typename Decoder> |
| 146 | void CheckDecoderClobber(const typename Decoder::RunType& run, |
| 147 | const std::vector<bool>& expected, rle_size_t chunk_size = 1, |
| 148 | rle_size_t expected_skip = 0) { |
| 149 | ARROW_SCOPED_TRACE("chunk_size = ", chunk_size, ", expected_skip = ", expected_skip); |
| 150 | |
| 151 | const auto n_vals = static_cast<rle_size_t>(expected.size()); |
| 152 | ASSERT_LE(expected_skip, n_vals); |
| 153 | |
| 154 | Decoder decoder(run); |
| 155 | const auto advanced = decoder.Advance(expected_skip); |
| 156 | ASSERT_EQ(advanced, expected_skip); |
| 157 | const auto n_vals_to_decode = n_vals - expected_skip; |
| 158 | |
| 159 | // Output buffer with enough capacity to store a full chunk plus extra bytes as |
| 160 | // clobbers/guard to check for out of bounds write. |
| 161 | const auto n_bytes = static_cast<size_t>(bit_util::BytesForBits(chunk_size) + |
| 162 | bit_util::CeilDiv(n_vals, chunk_size) + 2); |
| 163 | // This seed is arbitrary and of little importance. We are simply trying to avoid an |
| 164 | // unlikely case where guards have the same pattern in all invocations. |
| 165 | const auto out_pattern = |
| 166 | MakeRandomBytes(n_bytes, /* seed= */ (chunk_size << 16) ^ expected_skip); |
| 167 | auto out = out_pattern; |
| 168 | |
| 169 | rle_size_t n_val_read = 0; |
| 170 | rle_size_t out_bit_start = 0; |
| 171 | while (n_val_read < n_vals_to_decode) { |
| 172 | // Clean output buffer |
| 173 | out = out_pattern; |
| 174 | const auto want = std::min(chunk_size, n_vals_to_decode - n_val_read); |
| 175 | const auto got = decoder.GetBatch(BitmapSpanMut(out.data(), out_bit_start), want); |
| 176 | ASSERT_GT(got, 0) << "at pos " << n_val_read; // break on failure |
| 177 | EXPECT_EQ(got, want) << "at pos " << n_val_read; |
| 178 | // Check that the leading bits have not been modified |
| 179 | CheckBitsEqual({.actual = out, .expected = out_pattern, .count = out_bit_start}); |
| 180 | // Check that the trailing bits have not been modified |
| 181 | CheckBitsEqual({ |
| 182 | .actual = out, |
| 183 | .expected = out_pattern, |
| 184 | .count = static_cast<rle_size_t>(8 * n_bytes) - (out_bit_start + want), |
| 185 | .actual_start_bit = out_bit_start + want, |
| 186 | .expected_start_bit = out_bit_start + want, |
| 187 | }); |
| 188 | // Check decoded bits are also correct |
| 189 | CheckDecodedBits({ |
| 190 | .actual = out, |
| 191 | .expected = expected, |
| 192 | .count = want, |
| 193 | .actual_start_bit = out_bit_start, |
| 194 | .expected_start_idx = expected_skip + n_val_read, |
| 195 | }); |
| 196 | |
| 197 | n_val_read += got; |
| 198 | ++out_bit_start; |
| 199 | EXPECT_EQ(decoder.remaining(), n_vals_to_decode - n_val_read); |
| 200 | } |
| 201 | } |
| 202 | |
| 203 | /// All the checks shared by both decoder types. |
nothing calls this directly
no test coverage detected