123 free(strings); |
123 free(strings); |
124 |
124 |
125 return result; |
125 return result; |
126 } |
126 } |
127 |
127 |
128 |
128 cxstring cx_strsubs( |
129 |
129 cxstring string, |
|
130 size_t start |
|
131 ) { |
|
132 return cx_strsubsl(string, start, string.length - start); |
|
133 } |
|
134 |
|
135 cxmutstr cx_strsubs_m( |
|
136 cxmutstr string, |
|
137 size_t start |
|
138 ) { |
|
139 return cx_strsubsl_m(string, start, string.length - start); |
|
140 } |
|
141 |
|
142 cxstring cx_strsubsl( |
|
143 cxstring string, |
|
144 size_t start, |
|
145 size_t length |
|
146 ) { |
|
147 if (start > string.length) { |
|
148 return (cxstring) {NULL, 0}; |
|
149 } |
|
150 |
|
151 size_t rem_len = string.length - start; |
|
152 if (length > rem_len) { |
|
153 length = rem_len; |
|
154 } |
|
155 |
|
156 return (cxstring) {string.ptr + start, length}; |
|
157 } |
|
158 |
|
159 cxmutstr cx_strsubsl_m( |
|
160 cxmutstr string, |
|
161 size_t start, |
|
162 size_t length |
|
163 ) { |
|
164 cxstring result = cx_strsubsl(cx_strcast(string), start, length); |
|
165 return (cxmutstr) {(char *) result.ptr, result.length}; |
|
166 } |
|
167 |
|
168 cxstring cx_strchr( |
|
169 cxstring string, |
|
170 int chr |
|
171 ) { |
|
172 chr = 0xFF & chr; |
|
173 // TODO: improve by comparing multiple bytes at once |
|
174 cx_for_n(i, string.length) { |
|
175 if (string.ptr[i] == chr) { |
|
176 return cx_strsubs(string, i); |
|
177 } |
|
178 } |
|
179 return (cxstring) {NULL, 0}; |
|
180 } |
|
181 |
|
182 cxmutstr cx_strchr_m( |
|
183 cxmutstr string, |
|
184 int chr |
|
185 ) { |
|
186 cxstring result = cx_strchr(cx_strcast(string), chr); |
|
187 return (cxmutstr) {(char *) result.ptr, result.length}; |
|
188 } |
|
189 |
|
190 cxstring cx_strrchr( |
|
191 cxstring string, |
|
192 int chr |
|
193 ) { |
|
194 chr = 0xFF & chr; |
|
195 size_t i = string.length; |
|
196 while (i > 0) { |
|
197 i--; |
|
198 // TODO: improve by comparing multiple bytes at once |
|
199 if (string.ptr[i] == chr) { |
|
200 return cx_strsubs(string, i); |
|
201 } |
|
202 } |
|
203 return (cxstring) {NULL, 0}; |
|
204 } |
|
205 |
|
206 cxmutstr cx_strrchr_m( |
|
207 cxmutstr string, |
|
208 int chr |
|
209 ) { |
|
210 cxstring result = cx_strrchr(cx_strcast(string), chr); |
|
211 return (cxmutstr) {(char *) result.ptr, result.length}; |
|
212 } |
|
213 |
|
214 #define ptable_r(dest, useheap, ptable, index) (dest = useheap ? \ |
|
215 ((size_t*)ptable)[index] : (size_t) ((uint8_t*)ptable)[index]) |
|
216 |
|
217 #define ptable_w(useheap, ptable, index, src) do {\ |
|
218 if (!useheap) ((uint8_t*)ptable)[index] = (uint8_t) src;\ |
|
219 else ((size_t*)ptable)[index] = src;\ |
|
220 } while (0) |
|
221 |
|
222 |
|
223 cxstring cx_strstr( |
|
224 cxstring haystack, |
|
225 cxstring needle |
|
226 ) { |
|
227 if (needle.length == 0) { |
|
228 return haystack; |
|
229 } |
|
230 |
|
231 /* |
|
232 * IMPORTANT: |
|
233 * Our prefix table contains the prefix length PLUS ONE |
|
234 * this is our decision, because we want to use the full range of size_t. |
|
235 * The original algorithm needs a (-1) at one single place, |
|
236 * and we want to avoid that. |
|
237 */ |
|
238 |
|
239 /* static prefix table */ |
|
240 static uint8_t s_prefix_table[512]; |
|
241 |
|
242 /* check pattern length and use appropriate prefix table */ |
|
243 /* if the pattern exceeds static prefix table, allocate on the heap */ |
|
244 register int useheap = needle.length >= 512; |
|
245 register void *ptable = useheap ? calloc(needle.length + 1, |
|
246 sizeof(size_t)) : s_prefix_table; |
|
247 |
|
248 /* keep counter in registers */ |
|
249 register size_t i, j; |
|
250 |
|
251 /* fill prefix table */ |
|
252 i = 0; |
|
253 j = 0; |
|
254 ptable_w(useheap, ptable, i, j); |
|
255 while (i < needle.length) { |
|
256 while (j >= 1 && needle.ptr[j - 1] != needle.ptr[i]) { |
|
257 ptable_r(j, useheap, ptable, j - 1); |
|
258 } |
|
259 i++; |
|
260 j++; |
|
261 ptable_w(useheap, ptable, i, j); |
|
262 } |
|
263 |
|
264 /* search */ |
|
265 cxstring result = {NULL, 0}; |
|
266 i = 0; |
|
267 j = 1; |
|
268 while (i < haystack.length) { |
|
269 while (j >= 1 && haystack.ptr[i] != needle.ptr[j - 1]) { |
|
270 ptable_r(j, useheap, ptable, j - 1); |
|
271 } |
|
272 i++; |
|
273 j++; |
|
274 if (j - 1 == needle.length) { |
|
275 size_t start = i - needle.length; |
|
276 result.ptr = haystack.ptr + start; |
|
277 result.length = haystack.length - start; |
|
278 break; |
|
279 } |
|
280 } |
|
281 |
|
282 /* if prefix table was allocated on the heap, free it */ |
|
283 if (ptable != s_prefix_table) { |
|
284 free(ptable); |
|
285 } |
|
286 |
|
287 return result; |
|
288 } |
|
289 |
|
290 cxmutstr cx_strstr_m( |
|
291 cxmutstr haystack, |
|
292 cxstring needle |
|
293 ) { |
|
294 cxstring result = cx_strstr(cx_strcast(haystack), needle); |
|
295 return (cxmutstr) {(char *) result.ptr, result.length}; |
|
296 } |
|
297 |
|
298 size_t cx_strsplit( |
|
299 cxstring string, |
|
300 cxstring delim, |
|
301 size_t limit, |
|
302 cxstring *output |
|
303 ) { |
|
304 // TODO: implement |
|
305 return 0; |
|
306 } |
|
307 |
|
308 size_t cx_strsplit_a( |
|
309 CxAllocator *allocator, |
|
310 cxstring string, |
|
311 cxstring delim, |
|
312 size_t limit, |
|
313 cxstring **output |
|
314 ) { |
|
315 // TODO: implement |
|
316 return 0; |
|
317 } |
|
318 |
|
319 size_t cx_strsplit_m( |
|
320 cxmutstr string, |
|
321 cxstring delim, |
|
322 size_t limit, |
|
323 cxmutstr *output |
|
324 ) { |
|
325 return cx_strsplit(cx_strcast(string), |
|
326 delim, limit, (cxstring *) output); |
|
327 } |
|
328 |
|
329 size_t cx_strsplit_ma( |
|
330 CxAllocator *allocator, |
|
331 cxmutstr string, |
|
332 cxstring delim, |
|
333 size_t limit, |
|
334 cxmutstr **output |
|
335 ) { |
|
336 return cx_strsplit_a(allocator, cx_strcast(string), |
|
337 delim, limit, (cxstring **) output); |
|
338 } |