| 593 | |
| 594 | template <typename InType, typename CType = typename InType::c_type> |
| 595 | Status IntegersInRange(const ArraySpan& values, CType bound_lower, CType bound_upper) { |
| 596 | if (std::numeric_limits<CType>::lowest() >= bound_lower && |
| 597 | std::numeric_limits<CType>::max() <= bound_upper) { |
| 598 | return Status::OK(); |
| 599 | } |
| 600 | |
| 601 | auto IsOutOfBounds = [&](CType val) -> bool { |
| 602 | return val < bound_lower || val > bound_upper; |
| 603 | }; |
| 604 | auto IsOutOfBoundsMaybeNull = [&](CType val, bool is_valid) -> bool { |
| 605 | return is_valid && (val < bound_lower || val > bound_upper); |
| 606 | }; |
| 607 | auto GetErrorMessage = [&](CType val) { |
| 608 | return Status::Invalid("Integer value ", ToChars(val), |
| 609 | " not in range: ", ToChars(bound_lower), " to ", |
| 610 | ToChars(bound_upper)); |
| 611 | }; |
| 612 | |
| 613 | const CType* values_data = values.GetValues<CType>(1); |
| 614 | const uint8_t* bitmap = values.buffers[0].data; |
| 615 | OptionalBitBlockCounter values_bit_counter(bitmap, values.offset, values.length); |
| 616 | int64_t position = 0; |
| 617 | int64_t offset_position = values.offset; |
| 618 | while (position < values.length) { |
| 619 | BitBlockCount block = values_bit_counter.NextBlock(); |
| 620 | bool block_out_of_bounds = false; |
| 621 | if (block.popcount == block.length) { |
| 622 | // Fast path: branchless |
| 623 | int64_t i = 0; |
| 624 | for (int64_t chunk = 0; chunk < block.length / 8; ++chunk) { |
| 625 | // Let the compiler unroll this |
| 626 | for (int j = 0; j < 8; ++j) { |
| 627 | block_out_of_bounds |= IsOutOfBounds(values_data[i++]); |
| 628 | } |
| 629 | } |
| 630 | for (; i < block.length; ++i) { |
| 631 | block_out_of_bounds |= IsOutOfBounds(values_data[i]); |
| 632 | } |
| 633 | } else if (block.popcount > 0) { |
| 634 | // Values have nulls, must only boundscheck non-null values |
| 635 | int64_t i = 0; |
| 636 | for (int64_t chunk = 0; chunk < block.length / 8; ++chunk) { |
| 637 | // Let the compiler unroll this |
| 638 | for (int j = 0; j < 8; ++j) { |
| 639 | block_out_of_bounds |= IsOutOfBoundsMaybeNull( |
| 640 | values_data[i], bit_util::GetBit(bitmap, offset_position + i)); |
| 641 | ++i; |
| 642 | } |
| 643 | } |
| 644 | for (; i < block.length; ++i) { |
| 645 | block_out_of_bounds |= IsOutOfBoundsMaybeNull( |
| 646 | values_data[i], bit_util::GetBit(bitmap, offset_position + i)); |
| 647 | } |
| 648 | } |
| 649 | if (ARROW_PREDICT_FALSE(block_out_of_bounds)) { |
| 650 | if (values.GetNullCount() > 0) { |
| 651 | for (int64_t i = 0; i < block.length; ++i) { |
| 652 | if (IsOutOfBoundsMaybeNull(values_data[i], |