| 170 | |
| 171 | template <typename DType> |
| 172 | struct TypedFuzzEncoding { |
| 173 | static constexpr Type::type kType = DType::type_num; |
| 174 | |
| 175 | using c_type = |
| 176 | std::conditional_t<kType == Type::BOOLEAN, BooleanSlot, typename DType::c_type>; |
| 177 | using EncoderType = typename EncodingTraits<DType>::Encoder; |
| 178 | using DecoderType = typename EncodingTraits<DType>::Decoder; |
| 179 | using Accumulator = typename EncodingTraits<DType>::Accumulator; |
| 180 | |
| 181 | TypedFuzzEncoding(Encoding::type source_encoding, Encoding::type roundtrip_encoding, |
| 182 | const ColumnDescriptor* descr, int num_values, |
| 183 | std::span<const uint8_t> encoded_data) |
| 184 | : source_encoding_(source_encoding), |
| 185 | roundtrip_encoding_(roundtrip_encoding), |
| 186 | descr_(descr), |
| 187 | num_values_(num_values), |
| 188 | encoded_data_(encoded_data) {} |
| 189 | |
| 190 | // Decoders of string-like types return pointers into the |
| 191 | // decoder's internal scratch space, which get invalidated on the |
| 192 | // following decoder call. We circumvent the issue by executing a |
| 193 | // functor on each decoded chunk before moving to the next one. |
| 194 | Status RunOnDecodedChunks( |
| 195 | Encoding::type encoding, std::span<const uint8_t> encoded_data, int chunk_size, |
| 196 | std::function<Status(int offset, std::span<const c_type>)> func) { |
| 197 | BEGIN_PARQUET_CATCH_EXCEPTIONS |
| 198 | int total_values = 0; |
| 199 | auto decoder = MakeDecoder(encoding); |
| 200 | // NOTE: In real API usage, the `num_values` given to SetData() is read from |
| 201 | // the data page header and can include a number of nulls, so it's merely an |
| 202 | // upper bound for the number of physical values. |
| 203 | // However, Decode() calls are not supposed to ask more than the actual number |
| 204 | // of physical values. |
| 205 | decoder->SetData(num_values_, encoded_data.data(), |
| 206 | static_cast<int>(encoded_data.size())); |
| 207 | while (total_values < num_values_) { |
| 208 | const int read_size = std::min(num_values_ - total_values, chunk_size); |
| 209 | PoolVector<c_type> chunk_values(pool()); |
| 210 | BEGIN_CATCH_BAD_ALLOC |
| 211 | chunk_values.resize(read_size); |
| 212 | END_CATCH_BAD_ALLOC |
| 213 | int values_read; |
| 214 | if constexpr (kType == Type::BOOLEAN) { |
| 215 | values_read = |
| 216 | decoder->Decode(reinterpret_cast<bool*>(chunk_values.data()), read_size); |
| 217 | } else { |
| 218 | values_read = decoder->Decode(chunk_values.data(), read_size); |
| 219 | } |
| 220 | ARROW_CHECK_LE(values_read, read_size); |
| 221 | RETURN_NOT_OK(func(total_values, std::span(chunk_values).first(values_read))); |
| 222 | total_values += values_read; |
| 223 | if (values_read < chunk_size) { |
| 224 | break; |
| 225 | } |
| 226 | } |
| 227 | if (total_values < num_values_) { |
| 228 | return Status::Invalid("Read less values than expected"); |
| 229 | } |
nothing calls this directly
no test coverage detected