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}