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