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