| 41 | // Like VisitBits(), but unrolls its main loop for better performance. |
| 42 | template <class Visitor> |
| 43 | void VisitBitsUnrolled(const uint8_t* bitmap, int64_t start_offset, int64_t length, |
| 44 | Visitor&& visit) { |
| 45 | if (length == 0) { |
| 46 | return; |
| 47 | } |
| 48 | |
| 49 | // Start by visiting any bits preceding the first full byte. |
| 50 | int64_t num_bits_before_full_bytes = |
| 51 | bit_util::RoundUpToMultipleOf8(start_offset) - start_offset; |
| 52 | // Truncate num_bits_before_full_bytes if it is greater than length. |
| 53 | if (num_bits_before_full_bytes > length) { |
| 54 | num_bits_before_full_bytes = length; |
| 55 | } |
| 56 | // Use the non loop-unrolled VisitBits since we don't want to add branches |
| 57 | VisitBits<Visitor>(bitmap, start_offset, num_bits_before_full_bytes, visit); |
| 58 | |
| 59 | // Shift the start pointer to the first full byte and compute the |
| 60 | // number of full bytes to be read. |
| 61 | const uint8_t* first_full_byte = bitmap + bit_util::CeilDiv(start_offset, 8); |
| 62 | const int64_t num_full_bytes = (length - num_bits_before_full_bytes) / 8; |
| 63 | |
| 64 | // Iterate over each full byte of the input bitmap and call the visitor in |
| 65 | // a loop-unrolled manner. |
| 66 | for (int64_t byte_index = 0; byte_index < num_full_bytes; ++byte_index) { |
| 67 | // Get the current bit-packed byte value from the bitmap. |
| 68 | const uint8_t byte = *(first_full_byte + byte_index); |
| 69 | |
| 70 | // Execute the visitor function on each bit of the current byte. |
| 71 | visit(bit_util::GetBitFromByte(byte, 0)); |
| 72 | visit(bit_util::GetBitFromByte(byte, 1)); |
| 73 | visit(bit_util::GetBitFromByte(byte, 2)); |
| 74 | visit(bit_util::GetBitFromByte(byte, 3)); |
| 75 | visit(bit_util::GetBitFromByte(byte, 4)); |
| 76 | visit(bit_util::GetBitFromByte(byte, 5)); |
| 77 | visit(bit_util::GetBitFromByte(byte, 6)); |
| 78 | visit(bit_util::GetBitFromByte(byte, 7)); |
| 79 | } |
| 80 | |
| 81 | // Write any leftover bits in the last byte. |
| 82 | const int64_t num_bits_after_full_bytes = (length - num_bits_before_full_bytes) % 8; |
| 83 | VisitBits<Visitor>(first_full_byte + num_full_bytes, 0, num_bits_after_full_bytes, |
| 84 | visit); |
| 85 | } |
| 86 | |
| 87 | } // namespace internal |
| 88 | } // namespace arrow |