1#include <string.h>
2
3#include "include/pw.h"
4#include "src/types/string/string_internal.h"
5
6
7static uint8_t* strchr_1(uint8_t* start_ptr, uint8_t* end_ptr, char32_t codepoint)
8{
9 return memchr(start_ptr, (uint8_t) codepoint, end_ptr - start_ptr);
10}
11
12static uint8_t* strchr_2(uint8_t* start_ptr, uint8_t* end_ptr, char32_t codepoint)
13{
14 while (start_ptr < end_ptr) {
15 if (codepoint == *((uint16_t*) start_ptr)) {
16 return start_ptr;
17 }
18 start_ptr += 2;
19 }
20 return nullptr;
21}
22
23static uint8_t* strchr_3(uint8_t* start_ptr, uint8_t* end_ptr, char32_t codepoint)
24{
25 while (start_ptr < end_ptr) {
26 char32_t c = *start_ptr++;
27 c |= (*start_ptr++) << 8;
28 c |= (*start_ptr++) << 16;
29
30 if (c == codepoint) {
31 return start_ptr - 3;
32 }
33 }
34 return nullptr;
35}
36
37static uint8_t* strchr_4(uint8_t* start_ptr, uint8_t* end_ptr, char32_t codepoint)
38{
39 while (start_ptr < end_ptr) {
40 if (codepoint == *((char32_t*) start_ptr)) {
41 return start_ptr;
42 }
43 start_ptr += 4;
44 }
45 return nullptr;
46}
47
48StrChr _pw_strchr_variants[5] = {
49 nullptr,
50 strchr_1,
51 strchr_2,
52 strchr_3,
53 strchr_4
54};
55
56[[nodiscard]] bool pw_strchr(PwValuePtr str, char32_t chr, unsigned start_pos, unsigned* result)
57{
58 pw_assert_string(str);
59 uint8_t char_size = str->char_size;
60 if (_pw_unlikely(char_size < calc_char_size(chr))) {
61 return false;
62 }
63 uint8_t* end_ptr;
64 uint8_t* start_ptr = _pw_string_start_end(str, &end_ptr) + start_pos * char_size;
65 if (_pw_unlikely(start_ptr >= end_ptr)) {
66 return false;
67 }
68 StrChr fn_strchr = _pw_strchr_variants[char_size];
69 uint8_t* char_ptr = fn_strchr(start_ptr, end_ptr, chr);
70 if (_pw_unlikely(!char_ptr)) {
71 return false;
72 }
73 if (result) {
74 *result = start_pos + (char_ptr - start_ptr) / char_size;
75 }
76 return true;
77}