Branch data Line data Source code
1 : : // Copyright 2019-2026 David Robillard <d@drobilla.net> 2 : : // SPDX-License-Identifier: ISC 3 : : 4 : : #include "parse_decimal.h" 5 : : 6 : : #include "big_decimal.h" 7 : : #include "char_utils.h" 8 : : #include "macros.h" 9 : : #include "number_utils.h" 10 : : #include "result.h" 11 : : 12 : : #include <exess/exess.h> 13 : : 14 : : #include <stdbool.h> 15 : : #include <stdint.h> 16 : : 17 : : #define BIG_DECIMAL_MAX_DIGITS 255U 18 : : 19 : : typedef struct { 20 : : int expt; // Running power of 10 exponent 21 : : bool after_point; // True if we're past the decimal point 22 : : } ParseState; 23 : : 24 : : static size_t 25 : 30894 : skip_leading_zeros(const char* const str, ParseState* const out) 26 : : { 27 : 30894 : out->after_point = false; 28 : : 29 : 174559 : for (size_t i = 0;; ++i) { 30 [ + + + + ]: 174559 : if (str[i] == '.' && !out->after_point) { 31 : 2064 : out->after_point = true; 32 [ + + ]: 172495 : } else if (str[i] == '0') { 33 : 141601 : out->expt -= out->after_point; 34 : : } else { 35 : 30894 : return i; 36 : : } 37 : : } 38 : : } 39 : : 40 : : EXESS_NONBLOCKING ExessResult 41 : 30894 : parse_decimal(const char* const str, 42 : : BigDecimal* const out, 43 : : const size_t digits_size, 44 : : char* const digits) 45 : : { 46 : : // Read leading sign if present 47 : 30894 : int sign = 0; 48 : 30894 : size_t i = read_sign(&sign, str); 49 : : 50 : : // Skip any leading zeros (before and after decimal point) 51 : 30894 : ParseState state = {0, false}; 52 : 30894 : i += skip_leading_zeros(&str[i], &state); 53 : : 54 : : // Check that the first character is valid 55 [ + + + + ]: 30894 : if (!state.after_point && !is_digit(str[i])) { 56 : 20 : return RESULT(EXESS_EXPECTED_DIGIT, i); 57 : : } 58 : : 59 : : // Read significant digits of the mantissa 60 : 30874 : const size_t max_n_digits = MIN(digits_size, BIG_DECIMAL_MAX_DIGITS); 61 : 30874 : bool approximate = false; 62 : 580465 : for (;; ++i) { 63 [ + + ]: 611339 : if (is_digit(str[i])) { 64 : 551676 : const bool significant = (out->n_digits < max_n_digits); 65 : 551676 : state.expt += !state.after_point; 66 [ + + ]: 551676 : if (significant) { 67 : 406219 : digits[out->n_digits++] = str[i]; 68 [ + + ]: 145457 : } else if (str[i] != '0') { 69 : 6 : approximate = true; 70 : : } 71 [ + + + + ]: 59663 : } else if (str[i] == '.' && !state.after_point) { 72 : 28789 : state.after_point = true; 73 : : } else { 74 : : break; 75 : : } 76 : : } 77 : : 78 [ + + ]: 30874 : out->expt = (int16_t)(out->n_digits ? state.expt : 0); 79 [ + + ]: 61748 : out->kind = (sign < 0) 80 [ + + ]: 189 : ? (out->n_digits ? EXESS_NEGATIVE : EXESS_NEGATIVE_ZERO) 81 [ + + ]: 30685 : : (out->n_digits ? EXESS_POSITIVE : EXESS_POSITIVE_ZERO); 82 : : 83 : 30874 : return RESULT(approximate ? EXESS_LOSS : EXESS_SUCCESS, i); 84 : : }