| 178 | template <int kPackedBitWidth, template <typename, int> typename Unpacker, |
| 179 | typename UnpackedUInt> |
| 180 | void unpack_width(const uint8_t* in, UnpackedUInt* out, int batch_size, int bit_offset, |
| 181 | int max_read_bytes) { |
| 182 | if constexpr (kPackedBitWidth == 0) { |
| 183 | // Easy case to handle, simply setting memory to zero. |
| 184 | return unpack_null(in, out, batch_size); |
| 185 | } else { |
| 186 | // Number of bytes to read according to batch_size. |
| 187 | const int bytes_batch = static_cast<int>( |
| 188 | bit_util::BytesForBits(batch_size * kPackedBitWidth + bit_offset)); |
| 189 | // If specified, max_read_bytes must be greater that the bytes needed to extract the |
| 190 | // number of desired values. |
| 191 | ARROW_DCHECK(max_read_bytes < 0 || bytes_batch <= max_read_bytes); |
| 192 | const uint8_t* in_end = in + (max_read_bytes >= 0 ? max_read_bytes : bytes_batch); |
| 193 | |
| 194 | // In case of misalignment, we need to run the prolog until aligned. |
| 195 | int extracted = unpack_exact<kPackedBitWidth, true>(in, out, batch_size, bit_offset); |
| 196 | // We either extracted everything or found a alignment |
| 197 | const int start_bit = extracted * kPackedBitWidth + bit_offset; |
| 198 | ARROW_DCHECK((extracted == batch_size) || ((start_bit) % 8 == 0)); |
| 199 | batch_size -= extracted; |
| 200 | ARROW_DCHECK_GE(batch_size, 0); |
| 201 | in += start_bit / 8; |
| 202 | out += extracted; |
| 203 | |
| 204 | if constexpr (kPackedBitWidth == 8 * sizeof(UnpackedUInt)) { |
| 205 | // Only memcpy / static_cast |
| 206 | return unpack_full(in, out, batch_size); |
| 207 | } else { |
| 208 | using UnpackerForWidth = Unpacker<UnpackedUInt, kPackedBitWidth>; |
| 209 | // Number of values extracted by one iteration of the kernel |
| 210 | constexpr auto kValuesUnpacked = UnpackerForWidth::kValuesUnpacked; |
| 211 | // Number of bytes read, but not necessarily unpacked, by one iteration of the |
| 212 | // kernel. This constant prevent reading past buffer end. |
| 213 | constexpr auto kBytesRead = UnpackerForWidth::kBytesRead; |
| 214 | |
| 215 | if constexpr (kValuesUnpacked > 0) { |
| 216 | const uint8_t* in_last = in_end - kBytesRead; |
| 217 | // Running the optimized kernel for batch extraction |
| 218 | while ((batch_size >= kValuesUnpacked) && (in <= in_last)) { |
| 219 | in = UnpackerForWidth::unpack(in, out); |
| 220 | out += kValuesUnpacked; |
| 221 | batch_size -= kValuesUnpacked; |
| 222 | } |
| 223 | |
| 224 | // Performance check making sure we ran the kernel loop as much as possible: |
| 225 | // Either we ran out because we could not pack enough values, or because we would |
| 226 | // overread. |
| 227 | ARROW_DCHECK((batch_size < kValuesUnpacked) || (in_end - in) < kBytesRead); |
| 228 | } |
| 229 | |
| 230 | // Running the epilog for the remaining values that don't fit in a kernel |
| 231 | ARROW_DCHECK_GE(batch_size, 0); |
| 232 | ARROW_COMPILER_ASSUME(batch_size >= 0); |
| 233 | unpack_exact<kPackedBitWidth, false>(in, out, batch_size, /* bit_offset= */ 0); |
| 234 | } |
| 235 | } |
| 236 | } |
| 237 |
nothing calls this directly
no test coverage detected