@@ -92,6 +92,12 @@ using rle_size_t = int32_t;
9292template <typename T>
9393class RleRunDecoder ;
9494
95+ // / A Single Run Length Encoded run.
96+ // /
97+ // / Consist of a single value repeated multiple times.
98+ // / A previous version of this class also stored the value bit width to be self contain,
99+ // / removing it and passing it explicitly when needed proved to speed up decoding up to
100+ // / 10 % on some benchmarks.
95101class RleRun {
96102 public:
97103 // / The decoder class used to decode a single run in the given type.
@@ -102,24 +108,21 @@ class RleRun {
102108
103109 explicit RleRun (const uint8_t * data, rle_size_t values_count,
104110 rle_size_t value_bit_width) noexcept
105- : values_count_(values_count), value_bit_width_(value_bit_width) {
111+ : values_count_(values_count) {
106112 ARROW_DCHECK_GE (value_bit_width, 0 );
107113 ARROW_DCHECK_GE (values_count, 0 );
108- std::copy (data, data + raw_data_size (), data_.begin ());
114+ std::copy (data, data + raw_data_size (value_bit_width ), data_.begin ());
109115 }
110116
111117 // / The number of repeated values in this run.
112118 constexpr rle_size_t values_count () const noexcept { return values_count_; }
113119
114- // / The size in bits of each encoded value.
115- constexpr rle_size_t values_bit_width () const noexcept { return value_bit_width_; }
116-
117120 // / A pointer to the repeated value raw bytes.
118121 constexpr const uint8_t * raw_data_ptr () const noexcept { return data_.data (); }
119122
120123 // / The number of bytes used for the raw repeated value.
121- constexpr rle_size_t raw_data_size () const noexcept {
122- auto out = bit_util::BytesForBits (value_bit_width_ );
124+ constexpr rle_size_t raw_data_size (rle_size_t value_bit_width ) const noexcept {
125+ auto out = bit_util::BytesForBits (value_bit_width );
123126 ARROW_DCHECK_LE (out, std::numeric_limits<rle_size_t >::max ());
124127 return static_cast <rle_size_t >(out);
125128 }
@@ -130,13 +133,19 @@ class RleRun {
130133 std::array<uint8_t , 8 > data_ = {};
131134 // / The number of time the value is repeated.
132135 rle_size_t values_count_ = 0 ;
133- // / The size in bit of a packed value in the run.
134- rle_size_t value_bit_width_ = 0 ;
135136};
136137
137138template <typename T>
138139class BitPackedRunDecoder ;
139140
141+ // / A single bit packed run.
142+ // /
143+ // / Consist of a view on a buffer of bytes that encode integers on ``value_bit_width``
144+ // / bits (that is the numbers are small enough that high order bits are all zeros and can
145+ // / be omitted).
146+ // / A previous version of this class also stored the value bit width to be self contain,
147+ // / removing it and passing it explicitly when needed proved to speed up decoding up to
148+ // / 10 % on some benchmarks.
140149class BitPackedRun {
141150 public:
142151 // / The decoder class used to decode a single run in the given type.
@@ -147,20 +156,17 @@ class BitPackedRun {
147156
148157 constexpr BitPackedRun (const uint8_t * data, rle_size_t values_count,
149158 rle_size_t value_bit_width) noexcept
150- : data_(data), values_count_(values_count), value_bit_width_(value_bit_width) {
151- ARROW_CHECK_GE (value_bit_width_ , 0 );
159+ : data_(data), values_count_(values_count) {
160+ ARROW_CHECK_GE (value_bit_width , 0 );
152161 ARROW_CHECK_GE (values_count_, 0 );
153162 }
154163
155164 constexpr rle_size_t values_count () const noexcept { return values_count_; }
156165
157- // / The size in bits of each encoded value.
158- constexpr rle_size_t values_bit_width () const noexcept { return value_bit_width_; }
159-
160166 constexpr const uint8_t * raw_data_ptr () const noexcept { return data_; }
161167
162- constexpr rle_size_t raw_data_size () const noexcept {
163- auto out = bit_util::BytesForBits (static_cast <int64_t >(value_bit_width_ ) *
168+ constexpr rle_size_t raw_data_size (rle_size_t value_bit_width ) const noexcept {
169+ auto out = bit_util::BytesForBits (static_cast <int64_t >(value_bit_width ) *
164170 static_cast <int64_t >(values_count_));
165171 ARROW_CHECK_LE (out, std::numeric_limits<rle_size_t >::max ());
166172 return static_cast <rle_size_t >(out);
@@ -171,8 +177,6 @@ class BitPackedRun {
171177 const uint8_t * data_ = nullptr ;
172178 // / Number of values in this run.
173179 rle_size_t values_count_ = 0 ;
174- // / The size in bit of a packed value in the run
175- rle_size_t value_bit_width_ = 0 ;
176180};
177181
178182// / A parser that emits either a ``BitPackedRun`` or a ``RleRun``.
@@ -249,9 +253,11 @@ class RleRunDecoder {
249253
250254 constexpr RleRunDecoder () noexcept = default;
251255
252- explicit RleRunDecoder (const RunType& run) noexcept { Reset (run); }
256+ explicit RleRunDecoder (const RunType& run, rle_size_t value_bit_width) noexcept {
257+ Reset (run, value_bit_width);
258+ }
253259
254- void Reset (const RunType& run) noexcept {
260+ void Reset (const RunType& run, rle_size_t value_bit_width ) noexcept {
255261 remaining_count_ = run.values_count ();
256262 if constexpr (std::is_same_v<value_type, bool >) {
257263 // ARROW-18031: just check the LSB of the next byte and move on.
@@ -261,7 +267,7 @@ class RleRunDecoder {
261267 } else {
262268 // Memcopy is required to avoid undefined behavior.
263269 value_ = {};
264- std::memcpy (&value_, run.raw_data_ptr (), run.raw_data_size ());
270+ std::memcpy (&value_, run.raw_data_ptr (), run.raw_data_size (value_bit_width ));
265271 value_ = ::arrow::bit_util::FromLittleEndian (value_);
266272 }
267273 }
@@ -275,21 +281,22 @@ class RleRunDecoder {
275281 // / Try to advance by as many values as provided.
276282 // / Return the number of values skipped.
277283 // / May advance by less than asked for if there are not enough values left.
278- [[nodiscard]] rle_size_t Advance (rle_size_t batch_size) {
284+ [[nodiscard]] rle_size_t Advance (rle_size_t batch_size, rle_size_t value_bit_width ) {
279285 const auto steps = std::min (batch_size, remaining_count_);
280286 remaining_count_ -= steps;
281287 return steps;
282288 }
283289
284290 // / Get the next value and return false if there are no more.
285- [[nodiscard]] constexpr bool Get (value_type* out_value) {
286- return GetBatch (out_value, 1 ) == 1 ;
291+ [[nodiscard]] constexpr bool Get (value_type* out_value, rle_size_t value_bit_width ) {
292+ return GetBatch (out_value, 1 , value_bit_width ) == 1 ;
287293 }
288294
289295 // / Get a batch of values return the number of decoded elements.
290296 // / May write fewer elements to the output than requested if there are not enough values
291297 // / left.
292- [[nodiscard]] rle_size_t GetBatch (value_type* out, rle_size_t batch_size) {
298+ [[nodiscard]] rle_size_t GetBatch (value_type* out, rle_size_t batch_size,
299+ rle_size_t value_bit_width) {
293300 if (ARROW_PREDICT_FALSE (remaining_count_ == 0 )) {
294301 return 0 ;
295302 }
@@ -319,47 +326,48 @@ class BitPackedRunDecoder {
319326
320327 BitPackedRunDecoder () noexcept = default ;
321328
322- explicit BitPackedRunDecoder (const RunType& run) noexcept { Reset (run); }
329+ explicit BitPackedRunDecoder (const RunType& run, rle_size_t value_bit_width) noexcept {
330+ Reset (run, value_bit_width);
331+ }
323332
324- void Reset (const RunType& run) noexcept {
325- value_bit_width_ = run.values_bit_width ();
333+ void Reset (const RunType& run, rle_size_t value_bit_width) noexcept {
326334 remaining_count_ = run.values_count ();
327- ARROW_DCHECK_GE (value_bit_width_ , 0 );
328- ARROW_DCHECK_LE (value_bit_width_ , 64 );
329- bit_reader_.Reset (run.raw_data_ptr (), run.raw_data_size ());
335+ ARROW_DCHECK_GE (value_bit_width , 0 );
336+ ARROW_DCHECK_LE (value_bit_width , 64 );
337+ bit_reader_.Reset (run.raw_data_ptr (), run.raw_data_size (value_bit_width ));
330338 }
331339
332340 // / Return the number of values that can be advanced.
333341 constexpr rle_size_t remaining () const { return remaining_count_; }
334342
335- // / Return the size in bit in which each encoded value is written.
336- constexpr rle_size_t value_bit_width () const { return value_bit_width_; }
337-
338343 // / Try to advance by as many values as provided.
339344 // / Return the number of values skipped or 0 if it fail to advance.
340345 // / May advance by less than asked for if there are not enough values left.
341- [[nodiscard]] rle_size_t Advance (rle_size_t batch_size) {
346+ [[nodiscard]] rle_size_t Advance (rle_size_t batch_size, rle_size_t value_bit_width ) {
342347 const auto steps = std::min (batch_size, remaining_count_);
343- if (bit_reader_.Advance (steps * value_bit_width_ )) {
348+ if (bit_reader_.Advance (steps * value_bit_width )) {
344349 remaining_count_ -= steps;
345350 return steps;
346351 }
347352 return 0 ;
348353 }
349354
350355 // / Get the next value and return false if there are no more or an error occurred.
351- [[nodiscard]] bool Get (value_type* out_value) { return GetBatch (out_value, 1 ) == 1 ; }
356+ [[nodiscard]] constexpr bool Get (value_type* out_value, rle_size_t value_bit_width) {
357+ return GetBatch (out_value, 1 , value_bit_width) == 1 ;
358+ }
352359
353360 // / Get a batch of values return the number of decoded elements.
354361 // / May write fewer elements to the output than requested if there are not enough values
355362 // / left or if an error occurred.
356- [[nodiscard]] rle_size_t GetBatch (value_type* out, rle_size_t batch_size) {
363+ [[nodiscard]] rle_size_t GetBatch (value_type* out, rle_size_t batch_size,
364+ rle_size_t value_bit_width) {
357365 if (ARROW_PREDICT_FALSE (remaining_count_ == 0 )) {
358366 return 0 ;
359367 }
360368
361369 const auto to_read = std::min (remaining_count_, batch_size);
362- const auto actual_read = bit_reader_.GetBatch (value_bit_width_ , out, to_read);
370+ const auto actual_read = bit_reader_.GetBatch (value_bit_width , out, to_read);
363371 // There should not be any reason why the actual read would be different
364372 // but this is error resistant.
365373 remaining_count_ -= actual_read;
@@ -368,7 +376,6 @@ class BitPackedRunDecoder {
368376
369377 private:
370378 ::arrow::bit_util::BitReader bit_reader_ = {};
371- rle_size_t value_bit_width_ = 0 ;
372379 rle_size_t remaining_count_ = 0 ;
373380
374381 static_assert (std::is_integral_v<value_type>,
@@ -400,6 +407,7 @@ class RleBitPackedDecoder {
400407 ARROW_DCHECK_LE (value_bit_width, 64 );
401408 parser_.Reset (data, data_size, value_bit_width);
402409 decoder_ = {};
410+ value_bit_width_ = value_bit_width;
403411 }
404412
405413 // / Whether there is still runs to iterate over.
@@ -454,6 +462,7 @@ class RleBitPackedDecoder {
454462 private:
455463 RleBitPackedParser parser_ = {};
456464 std::variant<RleRunDecoder<value_type>, BitPackedRunDecoder<value_type>> decoder_ = {};
465+ rle_size_t value_bit_width_;
457466
458467 // / Return the number of values that are remaining in the current run.
459468 rle_size_t run_remaining () const {
@@ -462,7 +471,9 @@ class RleBitPackedDecoder {
462471
463472 // / Get a batch of values from the current run and return the number elements read.
464473 [[nodiscard]] rle_size_t RunGetBatch (value_type* out, rle_size_t batch_size) {
465- return std::visit ([&](auto & dec) { return dec.GetBatch (out, batch_size); }, decoder_);
474+ return std::visit (
475+ [&](auto & dec) { return dec.GetBatch (out, batch_size, value_bit_width_); },
476+ decoder_);
466477 }
467478
468479 // / Call the parser with a single callable for all event types.
@@ -734,8 +745,8 @@ auto RleBitPackedDecoder<T>::GetBatch(value_type* out, rle_size_t batch_size)
734745 using RunDecoder = typename decltype (run)::template DecoderType<value_type>;
735746
736747 ARROW_DCHECK_LT (values_read, batch_size);
737- RunDecoder decoder (run);
738- const auto read = decoder.GetBatch (out, batch_size - values_read);
748+ RunDecoder decoder (run, value_bit_width_ );
749+ const auto read = decoder.GetBatch (out, batch_size - values_read, value_bit_width_ );
739750 ARROW_DCHECK_LE (read, batch_size - values_read);
740751 values_read += read;
741752 out += read;
@@ -824,8 +835,9 @@ struct GetSpacedResult {
824835template <typename Converter, typename BitRunReader, typename BitRun, typename value_type>
825836auto RunGetSpaced (Converter* converter, typename Converter::out_type* out,
826837 rle_size_t batch_size, rle_size_t null_count,
827- BitRunReader* validity_reader, BitRun* validity_run,
828- RleRunDecoder<value_type>* decoder) -> GetSpacedResult<rle_size_t> {
838+ rle_size_t value_bit_width, BitRunReader* validity_reader,
839+ BitRun* validity_run, RleRunDecoder<value_type>* decoder)
840+ -> GetSpacedResult<rle_size_t> {
829841 ARROW_DCHECK_GT (batch_size, 0 );
830842 // The equality case is handled in the main loop in GetSpaced
831843 ARROW_DCHECK_LT (null_count, batch_size);
@@ -873,7 +885,7 @@ auto RunGetSpaced(Converter* converter, typename Converter::out_type* out,
873885 return {0 , 0 };
874886 }
875887 converter->WriteRepeated (out, out + batch.total_read (), value);
876- const auto actual_values_read = decoder->Advance (batch.values_read ());
888+ const auto actual_values_read = decoder->Advance (batch.values_read (), value_bit_width );
877889 // We always cropped the number of values_read by the remaining values in the run.
878890 // What's more the RLE decoder should not encounter any errors.
879891 ARROW_DCHECK_EQ (actual_values_read, batch.values_read ());
@@ -884,8 +896,8 @@ auto RunGetSpaced(Converter* converter, typename Converter::out_type* out,
884896template <typename Converter, typename BitRunReader, typename BitRun, typename value_type>
885897auto RunGetSpaced (Converter* converter, typename Converter::out_type* out,
886898 rle_size_t batch_size, rle_size_t null_count,
887- BitRunReader* validity_reader, BitRun* validity_run ,
888- BitPackedRunDecoder<value_type>* decoder)
899+ rle_size_t value_bit_width, BitRunReader* validity_reader ,
900+ BitRun* validity_run, BitPackedRunDecoder<value_type>* decoder)
889901 -> GetSpacedResult<rle_size_t> {
890902 ARROW_DCHECK_GT (batch_size, 0 );
891903 // The equality case is handled in the main loop in GetSpaced
@@ -920,7 +932,7 @@ auto RunGetSpaced(Converter* converter, typename Converter::out_type* out,
920932 // buffer_start is 0 at this point so size is end
921933 buffer_end = std::min (std::min (run_values_remaining (), batch.values_remaining ()),
922934 kBufferCapacity );
923- buffer_end = decoder->GetBatch (buffer.data (), buffer_size ());
935+ buffer_end = decoder->GetBatch (buffer.data (), buffer_size (), value_bit_width );
924936 ARROW_DCHECK_LE (buffer_size (), kBufferCapacity );
925937
926938 if (ARROW_PREDICT_FALSE (!converter->InputIsValid (buffer.data (), buffer_size ()))) {
@@ -972,14 +984,15 @@ auto RunGetSpaced(Converter* converter, typename Converter::out_type* out,
972984template <typename Converter, typename BitRunReader, typename BitRun, typename value_type>
973985auto RunGetSpaced (
974986 Converter* converter, typename Converter::out_type* out, rle_size_t batch_size,
975- rle_size_t null_count, BitRunReader* validity_reader, BitRun* validity_run,
987+ rle_size_t null_count, rle_size_t value_bit_width, BitRunReader* validity_reader,
988+ BitRun* validity_run,
976989 std::variant<RleRunDecoder<value_type>, BitPackedRunDecoder<value_type>>* decoder)
977990 -> GetSpacedResult<rle_size_t> {
978991 return std::visit (
979992 [&](auto & dec) {
980993 ARROW_DCHECK_GT (dec.remaining (), 0 );
981- return RunGetSpaced (converter, out, batch_size, null_count, validity_reader ,
982- validity_run, &dec);
994+ return RunGetSpaced (converter, out, batch_size, null_count, value_bit_width ,
995+ validity_reader, validity_run, &dec);
983996 },
984997 *decoder);
985998}
@@ -1023,8 +1036,8 @@ auto RleBitPackedDecoder<T>::GetSpaced(Converter converter,
10231036 // Remaining from a previous call that would have left some unread data from a run.
10241037 if (ARROW_PREDICT_FALSE (run_remaining () > 0 )) {
10251038 const auto read = internal::RunGetSpaced (&converter, out, batch.total_remaining (),
1026- batch.null_remaining (), &validity_reader ,
1027- &validity_run, &decoder_);
1039+ batch.null_remaining (), value_bit_width_ ,
1040+ &validity_reader, & validity_run, &decoder_);
10281041
10291042 batch.AccrueReadNulls (read.null_read );
10301043 batch.AccrueReadValues (read.values_read );
@@ -1044,11 +1057,11 @@ auto RleBitPackedDecoder<T>::GetSpaced(Converter converter,
10441057 ParseWithCallable ([&](auto run) {
10451058 using RunDecoder = typename decltype (run)::template DecoderType<value_type>;
10461059
1047- RunDecoder decoder (run);
1060+ RunDecoder decoder (run, value_bit_width_ );
10481061
10491062 const auto read = internal::RunGetSpaced (&converter, out, batch.total_remaining (),
1050- batch.null_remaining (), &validity_reader ,
1051- &validity_run, &decoder);
1063+ batch.null_remaining (), value_bit_width_ ,
1064+ &validity_reader, & validity_run, &decoder);
10521065
10531066 batch.AccrueReadNulls (read.null_read );
10541067 batch.AccrueReadValues (read.values_read );
@@ -1205,9 +1218,9 @@ auto RleBitPackedDecoder<T>::GetBatchWithDict(const V* dictionary,
12051218 };
12061219
12071220 if (ARROW_PREDICT_FALSE (run_remaining () > 0 )) {
1208- const auto read =
1209- internal::RunGetSpaced (&converter, out, batch_size, /* null_count= */ 0 ,
1210- &validity_reader, &validity_run, &decoder_);
1221+ const auto read = internal::RunGetSpaced (&converter, out, batch_size,
1222+ /* null_count= */ 0 , value_bit_width_ ,
1223+ &validity_reader, &validity_run, &decoder_);
12111224
12121225 ARROW_DCHECK_EQ (read.null_read , 0 );
12131226 values_read += read.values_read ;
@@ -1226,11 +1239,11 @@ auto RleBitPackedDecoder<T>::GetBatchWithDict(const V* dictionary,
12261239 ParseWithCallable ([&](auto run) {
12271240 using RunDecoder = typename decltype (run)::template DecoderType<value_type>;
12281241
1229- RunDecoder decoder (run);
1242+ RunDecoder decoder (run, value_bit_width_ );
12301243
12311244 const auto read = internal::RunGetSpaced (&converter, out, batch_values_remaining (),
1232- /* null_count= */ 0 , &validity_reader ,
1233- &validity_run, &decoder);
1245+ /* null_count= */ 0 , value_bit_width_ ,
1246+ &validity_reader, & validity_run, &decoder);
12341247
12351248 ARROW_DCHECK_EQ (read.null_read , 0 );
12361249 values_read += read.values_read ;
0 commit comments