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