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