1#include "include/pw.h"
 2#include "src/types/string/string_internal.h"
 3
 4#define is_ascii_digit(c) ('0' <= (c) && (c) <= '9')
 5
 6static bool is_digit_1(uint8_t* start_ptr, uint8_t* end_ptr)
 7{
 8    while (start_ptr < end_ptr) {
 9        uint8_t c = *start_ptr++;
10        if (!is_ascii_digit(c)) {
11            return false;
12        }
13    }
14    return true;
15}
16
17#define IS_DIGIT(CHAR_TYPE, CHAR_SIZE)  \
18    static bool is_digit_##CHAR_SIZE(uint8_t* start_ptr, uint8_t* end_ptr)  \
19    {  \
20        while (start_ptr < end_ptr) {  \
21            char32_t c = *(CHAR_TYPE*) start_ptr;  \
22            if (!pw_isdigit(c)) {  \
23                return false;  \
24            }  \
25            start_ptr += CHAR_SIZE;  \
26        }  \
27        return true;  \
28    }
29IS_DIGIT(uint16_t, 2)
30IS_DIGIT(char32_t, 4)
31
32static bool is_digit_3(uint8_t* start_ptr, uint8_t* end_ptr)
33{
34    while (start_ptr < end_ptr) {
35        char32_t c = *start_ptr++;
36        c |= (*start_ptr++) << 8;
37        c |= (*start_ptr++) << 16;
38        if (!pw_isdigit(c)) {
39            return false;
40        }
41    }
42    return true;
43}
44
45typedef bool (*StrIsDigit)(uint8_t* start_ptr, uint8_t* end_ptr);
46
47static StrIsDigit is_digit_variants[5] = {
48    nullptr,
49    is_digit_1,
50    is_digit_2,
51    is_digit_3,
52    is_digit_4
53};
54
55bool pw_string_isdigit(PwValuePtr str)
56{
57    pw_assert_string(str);
58    uint8_t* end_ptr;
59    uint8_t* start_ptr = _pw_string_start_end(str, &end_ptr);
60    if (_pw_unlikely(start_ptr == end_ptr)) {
61        return false;
62    }
63    StrIsDigit fn_is_digit = is_digit_variants[str->char_size];
64    return fn_is_digit(start_ptr, end_ptr);
65}