@@ -110,9 +110,8 @@ class RunToBitMapDecoderMixin {
110110 const auto n_vals = derived ()->GetBatchFast (out, batch_size);
111111
112112 // TRAILER: Writing inside the last byte if caller asked for non multiple of 8 values
113- const auto n_last_vals = batch_size - n_vals;
114- if (ARROW_PREDICT_FALSE (derived ()->remaining () > 0 && n_last_vals > 0 )) {
115- ARROW_DCHECK_GT (n_last_vals, 0 );
113+ const auto n_last_vals = std::min (batch_size - n_vals, derived ()->remaining ());
114+ if (ARROW_PREDICT_FALSE (n_last_vals > 0 )) {
116115 ARROW_DCHECK_LT (n_last_vals, 8 );
117116 out = out.NewStartingAt (n_vals);
118117 return n_vals + derived ()->GetBatchFirstByte (out, n_last_vals);
@@ -323,4 +322,109 @@ class BitPackedRunToBitMapDecoder
323322 }
324323};
325324
325+ // / A specialized decoder class to extract RLE+bitpacked booleans.
326+ // /
327+ // / In some cases, such as when reading definition levels for nullable values (with
328+ // / no repetition and no nesting), we know values to be decoded will end up in an
329+ // / Arrow validity bitmap. In such cases, decoding values to a ``int16`` before
330+ // / encoding them again in overly wasteful.
331+ class RleBitPackedToBitMapDecoder {
332+ public:
333+ RleBitPackedToBitMapDecoder () noexcept = default ;
334+
335+ // / Create a decoder object.
336+ // /
337+ // / data and data_size are the raw bytes to decode.
338+ RleBitPackedToBitMapDecoder (const uint8_t * data, rle_size_t data_size) noexcept {
339+ Reset (data, data_size);
340+ }
341+
342+ void Reset (const uint8_t * data, rle_size_t data_size) noexcept {
343+ parser_.Reset (data, data_size, /* value_bit_width= */ 1 );
344+ decoder_ = {};
345+ }
346+
347+ // / Whether there is still runs to iterate over.
348+ bool exhausted () const { return (run_remaining () == 0 ) && parser_.exhausted (); }
349+
350+ // / Get a batch of values return the number of decoded elements.
351+ // / May write fewer elements to the output than requested if there are not enough
352+ // / values left or if an error occurred.
353+ [[nodiscard]] rle_size_t GetBatch (BitmapSpanMut out, rle_size_t batch_size);
354+
355+ private:
356+ // / Utility to map a run type to the associate decoder.
357+ template <typename Run>
358+ struct get_decoder ;
359+ template <>
360+ struct get_decoder <RleRun> {
361+ using type = RleRunToBitMapDecoder;
362+ };
363+ template <>
364+ struct get_decoder <BitPackedRun> {
365+ using type = BitPackedRunToBitMapDecoder;
366+ };
367+ template <typename Run>
368+ using get_decoder_t = get_decoder<Run>::type;
369+
370+ RleBitPackedParser parser_ = {};
371+ std::variant<RleRunToBitMapDecoder, BitPackedRunToBitMapDecoder> decoder_ = {};
372+
373+ // / Return the number of values that are remaining in the current run.
374+ rle_size_t run_remaining () const {
375+ return std::visit ([](const auto & dec) { return dec.remaining (); }, decoder_);
376+ }
377+
378+ // / Get a batch of values from the current run and return the number elements read.
379+ [[nodiscard]] rle_size_t RunGetBatch (BitmapSpanMut out, rle_size_t batch_size) {
380+ return std::visit ([&](auto & dec) { return dec.GetBatch (out, batch_size); }, decoder_);
381+ }
382+ };
383+
384+ /* ***********************************************
385+ * RleBitPackedToBitMapDecoder implementation *
386+ ************************************************/
387+
388+ inline auto RleBitPackedToBitMapDecoder::GetBatch (BitmapSpanMut out,
389+ rle_size_t batch_size) -> rle_size_t {
390+ using ControlFlow = RleBitPackedParser::ControlFlow;
391+
392+ rle_size_t values_read = 0 ;
393+
394+ // Remaining from a previous call that would have left some unread data from a run.
395+ if (ARROW_PREDICT_FALSE (run_remaining () > 0 )) {
396+ const auto read = RunGetBatch (out, batch_size);
397+ values_read += read;
398+
399+ // Either we fulfilled all the batch to be read or we finished remaining run.
400+ if (ARROW_PREDICT_FALSE (values_read == batch_size)) {
401+ return values_read;
402+ }
403+ ARROW_DCHECK (run_remaining () == 0 );
404+ }
405+
406+ parser_.ParseWithCallable ([&](auto run) {
407+ using RunDecoder = get_decoder_t <decltype (run)>;
408+
409+ ARROW_DCHECK_LT (values_read, batch_size);
410+ RunDecoder decoder (run);
411+ // The output span carries its own bit offset, so advancing it past the values
412+ // already written keeps successive runs correctly aligned in the bitmap.
413+ const auto read =
414+ decoder.GetBatch (out.NewStartingAt (values_read), batch_size - values_read);
415+ ARROW_DCHECK_LE (read, batch_size - values_read);
416+ values_read += read;
417+
418+ // Stop reading and store remaining decoder
419+ if (ARROW_PREDICT_FALSE (values_read == batch_size || read == 0 )) {
420+ decoder_ = std::move (decoder);
421+ return ControlFlow::Break;
422+ }
423+
424+ return ControlFlow::Continue;
425+ });
426+
427+ return values_read;
428+ }
429+
326430} // namespace arrow::util
0 commit comments