| 80 | }; |
| 81 | |
| 82 | class FirstTimeBitmapWriter { |
| 83 | // Like BitmapWriter, but any bit values *following* the bits written |
| 84 | // might be clobbered. It is hence faster than BitmapWriter, and can |
| 85 | // also avoid false positives with Valgrind. |
| 86 | |
| 87 | public: |
| 88 | FirstTimeBitmapWriter(uint8_t* bitmap, int64_t start_offset, int64_t length) |
| 89 | : bitmap_(bitmap), position_(0), length_(length) { |
| 90 | current_byte_ = 0; |
| 91 | byte_offset_ = start_offset / 8; |
| 92 | bit_mask_ = bit_util::kBitmask[start_offset % 8]; |
| 93 | if (length > 0) { |
| 94 | current_byte_ = |
| 95 | bitmap[byte_offset_] & bit_util::kPrecedingBitmask[start_offset % 8]; |
| 96 | } else { |
| 97 | current_byte_ = 0; |
| 98 | } |
| 99 | } |
| 100 | |
| 101 | /// Appends number_of_bits from word to valid_bits and valid_bits_offset. |
| 102 | /// |
| 103 | /// \param[in] word The LSB bitmap to append. Any bits past number_of_bits are assumed |
| 104 | /// to be unset (i.e. 0). |
| 105 | /// \param[in] number_of_bits The number of bits to append from word. |
| 106 | void AppendWord(uint64_t word, int64_t number_of_bits) { |
| 107 | if (ARROW_PREDICT_FALSE(number_of_bits == 0)) { |
| 108 | return; |
| 109 | } |
| 110 | |
| 111 | // Location that the first byte needs to be written to. |
| 112 | uint8_t* append_position = bitmap_ + byte_offset_; |
| 113 | |
| 114 | // Update state variables except for current_byte_ here. |
| 115 | position_ += number_of_bits; |
| 116 | int64_t bit_offset = std::countr_zero(static_cast<uint32_t>(bit_mask_)); |
| 117 | bit_mask_ = bit_util::kBitmask[(bit_offset + number_of_bits) % 8]; |
| 118 | byte_offset_ += (bit_offset + number_of_bits) / 8; |
| 119 | |
| 120 | if (bit_offset != 0) { |
| 121 | // We are in the middle of the byte. This code updates the byte and shifts |
| 122 | // bits appropriately within word so it can be memcpy'd below. |
| 123 | int64_t bits_to_carry = 8 - bit_offset; |
| 124 | // Carry over bits from word to current_byte_. We assume any extra bits in word |
| 125 | // unset so no additional accounting is needed for when number_of_bits < |
| 126 | // bits_to_carry. |
| 127 | current_byte_ |= (word & bit_util::kPrecedingBitmask[bits_to_carry]) << bit_offset; |
| 128 | // Check if everything is transferred into current_byte_. |
| 129 | if (ARROW_PREDICT_FALSE(number_of_bits < bits_to_carry)) { |
| 130 | return; |
| 131 | } |
| 132 | *append_position = current_byte_; |
| 133 | append_position++; |
| 134 | // Move the carry bits off of word. |
| 135 | word = word >> bits_to_carry; |
| 136 | number_of_bits -= bits_to_carry; |
| 137 | } |
| 138 | word = bit_util::ToLittleEndian(word); |
| 139 | int64_t bytes_for_word = ::arrow::bit_util::BytesForBits(number_of_bits); |