| 658 | enum ArrayType { ALL_UINT8, ALL_INT16, ALL_FLOATS, GENERIC_ARRAY }; |
| 659 | |
| 660 | ArrayType classify_array(const json_array& arr) { |
| 661 | if (arr.empty()) return GENERIC_ARRAY; |
| 662 | |
| 663 | bool all_numeric = true; |
| 664 | i64 min_val = fl::numeric_limits<i64>::max(); |
| 665 | i64 max_val = fl::numeric_limits<i64>::min(); |
| 666 | bool has_float = false; |
| 667 | bool has_float_beyond_precision = false; |
| 668 | |
| 669 | for (const auto& elem : arr) { |
| 670 | if (!elem) { |
| 671 | all_numeric = false; |
| 672 | break; |
| 673 | } |
| 674 | |
| 675 | if (elem->is_int()) { |
| 676 | auto val = elem->as_int(); |
| 677 | if (val) { |
| 678 | i64 v = *val; |
| 679 | min_val = (v < min_val) ? v : min_val; |
| 680 | max_val = (v > max_val) ? v : max_val; |
| 681 | } else { |
| 682 | all_numeric = false; |
| 683 | break; |
| 684 | } |
| 685 | } else if (elem->is_float()) { |
| 686 | has_float = true; |
| 687 | auto val = elem->as_float(); |
| 688 | if (!val) { |
| 689 | all_numeric = false; |
| 690 | break; |
| 691 | } |
| 692 | // Check if float is beyond integer precision (>2^24 or <-2^24). |
| 693 | // Integer biased-exp comparison -- no FP arithmetic (#3022 phase 2). |
| 694 | const u32 fbits = fl::bit_cast<u32>(*val); |
| 695 | if (float_bits_magnitude_exceeds_2_24(fbits)) { |
| 696 | has_float_beyond_precision = true; |
| 697 | } |
| 698 | } else { |
| 699 | all_numeric = false; |
| 700 | break; |
| 701 | } |
| 702 | } |
| 703 | |
| 704 | if (!all_numeric) return GENERIC_ARRAY; |
| 705 | |
| 706 | // Classification |
| 707 | if (has_float) { |
| 708 | // If floats are beyond integer precision, don't optimize |
| 709 | if (has_float_beyond_precision) { |
| 710 | return GENERIC_ARRAY; |
| 711 | } |
| 712 | return ALL_FLOATS; |
| 713 | } |
| 714 | |
| 715 | // Integer arrays |
| 716 | if (min_val >= 0 && max_val <= 255) { |
| 717 | return ALL_UINT8; |
no test coverage detected