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};