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