1#include "include/pw.h"
2#include "include/pwlib/ctype.h"
3#include "src/types/string/string_internal.h"
4
5#define SUBSTREQI(CHAR_TYPE, CHAR_SIZE) \
6 static uint8_t* strchri_##CHAR_SIZE(uint8_t* start_ptr, uint8_t* end_ptr, char32_t codepoint) \
7 { \
8 while (start_ptr < end_ptr) { \
9 if (codepoint == (char32_t) pw_char_lower(*((CHAR_TYPE*) start_ptr))) { \
10 return start_ptr; \
11 } \
12 start_ptr += CHAR_SIZE; \
13 } \
14 return nullptr; \
15 }
16SUBSTREQI(uint8_t, 1)
17SUBSTREQI(uint16_t, 2)
18SUBSTREQI(char32_t, 4)
19
20static uint8_t* strchri_3(uint8_t* start_ptr, uint8_t* end_ptr, char32_t codepoint)
21{
22 while (start_ptr < end_ptr) {
23 char32_t c = *start_ptr++;
24 c |= (*start_ptr++) << 8;
25 c |= (*start_ptr++) << 16;
26
27 if (codepoint == (char32_t) pw_char_lower(c)) {
28 return start_ptr - 3;
29 }
30 }
31 return nullptr;
32}
33
34StrChr _pw_strchri_variants[5] = {
35 nullptr,
36 strchri_1,
37 strchri_2,
38 strchri_3,
39 strchri_4
40};
41
42[[nodiscard]] bool pw_strchri(PwValuePtr str, char32_t chr, unsigned start_pos, unsigned* result)
43{
44 pw_assert(pw_is_string(str));
45 uint8_t char_size = str->str_params.char_size;
46 if (_pw_unlikely(char_size < calc_char_size(chr))) {
47 return false;
48 }
49 uint8_t* end_ptr;
50 uint8_t* start_ptr = _pw_string_start_end(str, &end_ptr) + start_pos * char_size;
51 if (_pw_unlikely(start_ptr >= end_ptr)) {
52 return false;
53 }
54 StrChr fn_strchri = _pw_strchri_variants[char_size];
55 uint8_t* char_ptr = fn_strchri(start_ptr, end_ptr, pw_char_lower(chr));
56 if (_pw_unlikely(!char_ptr)) {
57 return false;
58 }
59 if (result) {
60 *result = start_pos + (char_ptr - start_ptr) / char_size;
61 }
62 return true;
63}