1#include "include/pw.h"
 2#include "src/types/string/string_internal.h"
 3
 4bool _pw_strstr(PwValuePtr str, PwValuePtr substr, unsigned start_pos, unsigned* pos)
 5{
 6    pw_assert_string(str);
 7    pw_assert_string(substr);
 8
 9    uint8_t  substr_char_size = substr->char_size;
10    uint8_t* substr_end_ptr;
11    uint8_t* substr_start_ptr = _pw_string_start_end(substr, &substr_end_ptr);
12    if (_pw_unlikely(substr_start_ptr >= substr_end_ptr)) {
13        // empty substring
14        return false;
15    }
16
17    uint8_t  str_char_size = str->char_size;
18    uint8_t* str_end_ptr;
19    uint8_t* str_start_ptr = _pw_string_start_end(str, &str_end_ptr);
20    str_start_ptr += start_pos * str_char_size;
21
22    char32_t start_codepoint = _pw_get_char(substr_start_ptr, substr_char_size);
23    if (_pw_unlikely(start_codepoint >= (1ULL << (8 * str_char_size)))) {
24        return false;
25    }
26
27    StrChr   fn_strchr   = _pw_strchr_variants[str_char_size];
28    SubstrEq fn_substreq = _pw_substreq_variants[str_char_size][substr_char_size];
29
30    str_end_ptr -= substr_end_ptr - substr_start_ptr - 1;  // reduce by strlen(substr) - 1
31    for (uint8_t* str_ptr = str_start_ptr; str_start_ptr < str_end_ptr; ) {
32
33        uint8_t* maybe_substr = fn_strchr(str_ptr, str_end_ptr, start_codepoint);
34        if (!maybe_substr) {
35            break;
36        }
37        if (fn_substreq(maybe_substr, substr_start_ptr, substr_end_ptr)) {
38            if (pos) {
39                *pos = start_pos + (maybe_substr - str_start_ptr) / str_char_size;
40            }
41            return true;
42        }
43        str_ptr = maybe_substr + str_char_size;
44    }
45    return false;
46}