1#define _GNU_SOURCE // for memrchr
2#include <string.h>
3
4#include "include/pw.h"
5#include "src/types/string/string_internal.h"
6
7
8static uint8_t* strrchr2_1(uint8_t* start_ptr, uint8_t* end_ptr, char32_t codepoint, uint8_t* char_size)
9{
10 *char_size = 1;
11 return memrchr(start_ptr, (uint8_t) codepoint, end_ptr - start_ptr);
12}
13
14static uint8_t* strrchr2_2(uint8_t* start_ptr, uint8_t* end_ptr, char32_t codepoint, uint8_t* char_size)
15{
16 char32_t width = 0;
17 while (start_ptr < end_ptr) {
18 end_ptr -= 2;
19 char32_t c = *(uint16_t*) end_ptr;
20 width |= c;
21 if (c == codepoint) {
22 *char_size = calc_char_size(width);
23 return end_ptr;
24 }
25 }
26 *char_size = calc_char_size(width);
27 return nullptr;
28}
29
30static uint8_t* strrchr2_3(uint8_t* start_ptr, uint8_t* end_ptr, char32_t codepoint, uint8_t* char_size)
31{
32 char32_t width = 0;
33 while (start_ptr < end_ptr) {
34 end_ptr -= 3;
35 char32_t c = *end_ptr++;
36 c |= (*end_ptr++) << 8;
37 c |= (*end_ptr++) << 16;
38 end_ptr -= 3;
39 width |= c;
40 if (c == codepoint) {
41 *char_size = calc_char_size(width);
42 return end_ptr;
43 }
44 }
45 *char_size = calc_char_size(width);
46 return nullptr;
47}
48
49static uint8_t* strrchr2_4(uint8_t* start_ptr, uint8_t* end_ptr, char32_t codepoint, uint8_t* char_size)
50{
51 char32_t width = 0;
52 while (start_ptr < end_ptr) {
53 end_ptr -= 4;
54 char32_t c = *(char32_t*) end_ptr;
55 width |= c;
56 if (c == codepoint) {
57 *char_size = calc_char_size(width);
58 return end_ptr;
59 }
60 }
61 *char_size = calc_char_size(width);
62 return nullptr;
63}
64
65StrRChr2 _pw_strrchr2_variants[5] = {
66 nullptr,
67 strrchr2_1,
68 strrchr2_2,
69 strrchr2_3,
70 strrchr2_4
71};
72
73[[nodiscard]] bool pw_strrchr2(PwValuePtr str, char32_t chr, unsigned end_pos, unsigned* result, uint8_t* max_char_size)
74{
75 pw_assert(pw_is_string(str));
76 uint8_t char_size = str->str_params.char_size;
77 if (_pw_unlikely(char_size < calc_char_size(chr))) {
78 return false;
79 }
80 unsigned length;
81 uint8_t* start_ptr = _pw_string_start_length(str, &length);
82
83 if (_pw_unlikely(length == 0)) {
84 *max_char_size = 1;
85 return false;
86 }
87 if (end_pos > length) {
88 end_pos = length;
89 }
90 uint8_t* end_ptr = start_ptr + end_pos * char_size;
91 StrChr2 fn_strrchr2 = _pw_strrchr2_variants[char_size];
92 uint8_t* char_ptr = fn_strrchr2(start_ptr, end_ptr, chr, max_char_size);
93 if (_pw_unlikely(!char_ptr)) {
94 return false;
95 }
96 if (result) {
97 *result = (char_ptr - start_ptr) / char_size;
98 }
99 return true;
100}