Returns a new BitRun containing the number of contiguous bits with the same value. length == 0 indicates the end of the bitmap.
| 90 | /// bits with the same value. length == 0 indicates the |
| 91 | /// end of the bitmap. |
| 92 | BitRun NextRun() { |
| 93 | if (ARROW_PREDICT_FALSE(position_ >= length_)) { |
| 94 | return {/*length=*/0, false}; |
| 95 | } |
| 96 | // This implementation relies on a efficient implementations of |
| 97 | // std::countr_zero and assumes that runs are more often then |
| 98 | // not. The logic is to incrementally find the next bit change |
| 99 | // from the current position. This is done by zeroing all |
| 100 | // bits in word_ up to position_ and using the TrailingZeroCount |
| 101 | // to find the index of the next set bit. |
| 102 | |
| 103 | // The runs alternate on each call, so flip the bit. |
| 104 | current_run_bit_set_ = !current_run_bit_set_; |
| 105 | |
| 106 | int64_t start_position = position_; |
| 107 | int64_t start_bit_offset = start_position & 63; |
| 108 | // Invert the word for proper use of std::countr_zero and |
| 109 | // clear bits so std::countr_zero can do it magic. |
| 110 | word_ = ~word_ & ~bit_util::LeastSignificantBitMask<uint64_t>(start_bit_offset); |
| 111 | |
| 112 | // Go forward until the next change from unset to set. |
| 113 | int64_t new_bits = std::countr_zero(word_) - start_bit_offset; |
| 114 | position_ += new_bits; |
| 115 | |
| 116 | if (ARROW_PREDICT_FALSE(bit_util::IsMultipleOf64(position_)) && |
| 117 | ARROW_PREDICT_TRUE(position_ < length_)) { |
| 118 | // Continue extending position while we can advance an entire word. |
| 119 | // (updates position_ accordingly). |
| 120 | AdvanceUntilChange(); |
| 121 | } |
| 122 | |
| 123 | return {/*length=*/position_ - start_position, current_run_bit_set_}; |
| 124 | } |
| 125 | |
| 126 | private: |
| 127 | void AdvanceUntilChange() { |
nothing calls this directly
no test coverage detected