1#include "include/pw.h"
  2#include "src/types/string/string_internal.h"
  3
  4/*
  5 * strput variants with no dest expansion
  6 */
  7#define STRPUT_NOEXPAND_NN(DEST_CHAR_SIZE, SRC_CHAR_SIZE)  \
  8    [[nodiscard]] static bool strput_##DEST_CHAR_SIZE##_##SRC_CHAR_SIZE(  \
  9        PwValuePtr dest, unsigned dest_pos, uint8_t* src_start_ptr, uint8_t* src_end_ptr)  \
 10    {  \
 11        _pw_strcopy_n_n(_pw_string_char_ptr(dest, dest_pos), src_start_ptr, src_end_ptr);  \
 12        return true;  \
 13    }
 14STRPUT_NOEXPAND_NN(1, 1)
 15STRPUT_NOEXPAND_NN(2, 2)
 16STRPUT_NOEXPAND_NN(3, 3)
 17STRPUT_NOEXPAND_NN(4, 4)
 18
 19#define STRPUT_NOEXPAND(DEST_CHAR_SIZE, SRC_CHAR_SIZE)  \
 20    [[nodiscard]] static bool strput_##DEST_CHAR_SIZE##_##SRC_CHAR_SIZE(  \
 21        PwValuePtr dest, unsigned dest_pos, uint8_t* src_start_ptr, uint8_t* src_end_ptr)  \
 22    {  \
 23        _pw_strcopy_##DEST_CHAR_SIZE##_##SRC_CHAR_SIZE(_pw_string_char_ptr(dest, dest_pos), src_start_ptr, src_end_ptr);  \
 24        return true;  \
 25    }
 26STRPUT_NOEXPAND(2, 1)
 27STRPUT_NOEXPAND(3, 1)
 28STRPUT_NOEXPAND(3, 2)
 29STRPUT_NOEXPAND(4, 1)
 30STRPUT_NOEXPAND(4, 2)
 31STRPUT_NOEXPAND(4, 3)
 32
 33
 34/*
 35 * strput variants with dest expansion for char_size 1, 2, and 4
 36 */
 37#define STRPUT_EXPAND(DEST_CHAR_TYPE, DEST_CHAR_SIZE, SRC_CHAR_TYPE, SRC_CHAR_SIZE)  \
 38    [[nodiscard]] static bool strput_##DEST_CHAR_SIZE##_##SRC_CHAR_SIZE(  \
 39        PwValuePtr dest, unsigned dest_pos, uint8_t* src_start_ptr, uint8_t* src_end_ptr)  \
 40    {  \
 41        uint8_t* dest_ptr = _pw_string_char_ptr(dest, dest_pos);  \
 42        while (src_start_ptr < src_end_ptr) {  \
 43            char32_t c = *((SRC_CHAR_TYPE*) src_start_ptr);  \
 44            uint8_t char_size = calc_char_size(c);  \
 45            if (_pw_unlikely(char_size > DEST_CHAR_SIZE)) {  \
 46                if (!_pw_expand_string(dest, 0, char_size)) {  \
 47                    return false;  \
 48                }  \
 49                StrPut fn_strput = _pw_strput_variants[char_size][SRC_CHAR_SIZE];  \
 50                return fn_strput(dest, dest_pos, src_start_ptr, src_end_ptr);  \
 51            }  \
 52            *((DEST_CHAR_TYPE*) dest_ptr) = (DEST_CHAR_TYPE) c;  \
 53            dest_ptr += DEST_CHAR_SIZE;  \
 54            src_start_ptr += SRC_CHAR_SIZE;  \
 55            dest_pos++;  \
 56        }  \
 57        return true;  \
 58    }
 59STRPUT_EXPAND(uint8_t,  1, uint16_t, 2)
 60STRPUT_EXPAND(uint8_t,  1, char32_t, 4)
 61STRPUT_EXPAND(uint16_t, 2, char32_t, 4)
 62
 63/*
 64 * strput variants with dest expansion for source char_size 3
 65 */
 66#define STRPUT_EXPAND_N_3(DEST_CHAR_TYPE, DEST_CHAR_SIZE)  \
 67    [[nodiscard]] static bool strput_##DEST_CHAR_SIZE##_3(  \
 68        PwValuePtr dest, unsigned dest_pos, uint8_t* src_start_ptr, uint8_t* src_end_ptr)  \
 69    {  \
 70        uint8_t* dest_ptr = _pw_string_char_ptr(dest, dest_pos);  \
 71        while (src_start_ptr < src_end_ptr) {  \
 72            char32_t c = *src_start_ptr++;  \
 73            c |= (*src_start_ptr++) << 8;  \
 74            c |= (*src_start_ptr++) << 16;  \
 75            uint8_t char_size = calc_char_size(c);  \
 76            if (_pw_unlikely(char_size > DEST_CHAR_SIZE)) {  \
 77                if (!_pw_expand_string(dest, 0, char_size)) {  \
 78                    return false;  \
 79                }  \
 80                StrPut fn_strput = _pw_strput_variants[char_size][3];  \
 81                return fn_strput(dest, dest_pos, src_start_ptr - 3, src_end_ptr);  \
 82            }  \
 83            *((DEST_CHAR_TYPE*) dest_ptr) = (DEST_CHAR_TYPE) c;  \
 84            dest_ptr += DEST_CHAR_SIZE;  \
 85            dest_pos++;  \
 86        }  \
 87        return true;  \
 88    }
 89STRPUT_EXPAND_N_3(uint8_t,  1)
 90STRPUT_EXPAND_N_3(uint16_t, 2)
 91
 92/*
 93 * strput variant with dest expansion for source char_size 4 and dest char_size 3
 94 */
 95[[nodiscard]] static bool strput_3_4(PwValuePtr dest, unsigned dest_pos, uint8_t* src_start_ptr, uint8_t* src_end_ptr)
 96{
 97    uint8_t* dest_ptr = _pw_string_char_ptr(dest, dest_pos);
 98    while (src_start_ptr < src_end_ptr) {
 99        char32_t c = *((char32_t*) src_start_ptr);
100        uint8_t char_size = calc_char_size(c);
101        if (_pw_unlikely(char_size > 3)) {
102            if (!_pw_expand_string(dest, 0, char_size)) {
103                return false;
104            }
105            StrPut fn_strput = _pw_strput_variants[char_size][0];
106            return fn_strput(dest, dest_pos, src_start_ptr, src_end_ptr);
107        }
108        *dest_ptr++ = (uint8_t) c; c >>= 8;
109        *dest_ptr++ = (uint8_t) c; c >>= 8;
110        *dest_ptr++ = (uint8_t) c;
111        src_start_ptr += 4;
112        dest_pos++;
113    }
114    return true;
115}
116
117/*
118 * strput variants with dest expansion for UTF-8 source and dest char_size 1, 2, and 4
119 */
120#define STRPUT_UTF8(DEST_CHAR_TYPE, DEST_CHAR_SIZE)  \
121    [[nodiscard]] static bool strput_##DEST_CHAR_SIZE##_0(  \
122        PwValuePtr dest, unsigned dest_pos, uint8_t* src_start_ptr, uint8_t* src_end_ptr)  \
123    {  \
124        uint8_t* dest_ptr = _pw_string_char_ptr(dest, dest_pos);  \
125        while (src_start_ptr < src_end_ptr) {  \
126            uint8_t* current_ptr = src_start_ptr;  \
127            char32_t c = _pw_decode_utf8_char(&src_start_ptr);  \
128            uint8_t char_size = calc_char_size(c);  \
129            if (_pw_unlikely(char_size > DEST_CHAR_SIZE)) {  \
130                if (!_pw_expand_string(dest, 0, char_size)) {  \
131                    return false;  \
132                }  \
133                StrPut fn_strput = _pw_strput_variants[char_size][0];  \
134                return fn_strput(dest, dest_pos, current_ptr, src_end_ptr);  \
135            }  \
136            *((DEST_CHAR_TYPE*) dest_ptr) = (DEST_CHAR_TYPE) c;  \
137            dest_ptr += DEST_CHAR_SIZE;  \
138            dest_pos++;  \
139        }  \
140        return true;  \
141    }
142STRPUT_UTF8(uint8_t,  1)
143STRPUT_UTF8(uint16_t, 2)
144STRPUT_UTF8(char32_t, 4)
145
146[[nodiscard]] static bool strput_3_0(PwValuePtr dest, unsigned dest_pos, uint8_t* src_start_ptr, uint8_t* src_end_ptr)
147{
148    uint8_t* dest_ptr = _pw_string_char_ptr(dest, dest_pos);
149    while (src_start_ptr < src_end_ptr) {
150        uint8_t* current_ptr = src_start_ptr;
151        char32_t c = _pw_decode_utf8_char(&src_start_ptr);
152        uint8_t char_size = calc_char_size(c);
153        if (_pw_unlikely(char_size > 3)) {
154            if (!_pw_expand_string(dest, 0, char_size)) {
155                return false;
156            }
157            StrPut fn_strput = _pw_strput_variants[char_size][0];
158            return fn_strput(dest, dest_pos, current_ptr, src_end_ptr);
159        }
160        *dest_ptr++ = (uint8_t) c; c >>= 8;
161        *dest_ptr++ = (uint8_t) c; c >>= 8;
162        *dest_ptr++ = (uint8_t) c;
163        dest_pos++;
164    }
165    return true;
166}
167
168StrPut _pw_strput_variants[5][5] = {
169    {
170        nullptr,
171        nullptr,
172        nullptr,
173        nullptr,
174        nullptr
175    },
176    {
177        strput_1_0,
178        strput_1_1,
179        strput_1_2,
180        strput_1_3,
181        strput_1_4
182    },
183    {
184        strput_2_0,
185        strput_2_1,
186        strput_2_2,
187        strput_2_3,
188        strput_2_4
189    },
190    {
191        strput_3_0,
192        strput_3_1,
193        strput_3_2,
194        strput_3_3,
195        strput_3_4
196    },
197    {
198        strput_4_0,
199        strput_4_1,
200        strput_4_2,
201        strput_4_3,
202        strput_4_4
203    }
204};