rapidyaml 0.14.0
parse and emit YAML, and do it fast
Loading...
Searching...
No Matches
filter_processor.hpp
Go to the documentation of this file.
1#ifndef _C4_YML_FILTER_PROCESSOR_HPP_
2#define _C4_YML_FILTER_PROCESSOR_HPP_
3
4#ifndef _C4_YML_ERROR_HPP_
5#include "./error.hpp"
6#endif
7
8#ifdef RYML_DBG
9#include "c4/charconv.hpp"
10#include "c4/yml/detail/dbgprint.hpp"
11#endif
12
13namespace c4 {
14namespace yml {
15
16/** @defgroup doc_filter_processors Scalar filter processors
17 *
18 * These are internal utilities used by @ref ParseEngine to parse the
19 * scalars; normally there is no reason for a user to be manually
20 * using these classes.
21 *
22 * @ingroup doc_parse */
23/** @{ */
24
25
26//-----------------------------------------------------------------------------
27//-----------------------------------------------------------------------------
28//-----------------------------------------------------------------------------
29
30/** Abstracts the fact that a scalar filter result may not fit in the
31 * intended memory. */
33{
34 C4_ALWAYS_INLINE bool valid() const noexcept { return str.str != nullptr; }
35 C4_ALWAYS_INLINE size_t required_len() const noexcept { return str.len; }
36 C4_ALWAYS_INLINE csubstr get() const { _RYML_ASSERT_BASIC(valid()); return str; }
38};
39/** Abstracts the fact that a scalar filter result may not fit in the
40 * intended memory. */
42{
43 C4_ALWAYS_INLINE bool valid() const noexcept { return str.str != nullptr; }
44 C4_ALWAYS_INLINE size_t required_len() const noexcept { return reqlen; }
45 C4_ALWAYS_INLINE csubstr get() const { _RYML_ASSERT_BASIC(valid()); return str; }
47 size_t reqlen;
48};
49
50
51//-----------------------------------------------------------------------------
52
53/** Filters an input string into a different output string */
55{
58 size_t rpos; ///< read position
59 size_t wpos; ///< write position
60
61 C4_ALWAYS_INLINE FilterProcessorSrcDst(csubstr src_, substr dst_) noexcept
62 : src(src_)
63 , dst(dst_)
64 , rpos(0)
65 , wpos(0)
66 {
67 _RYML_ASSERT_BASIC(!dst.overlaps(src));
68 }
69
70 C4_ALWAYS_INLINE void setwpos(size_t wpos_) noexcept { wpos = wpos_; }
71 C4_ALWAYS_INLINE void setpos(size_t rpos_, size_t wpos_) noexcept { rpos = rpos_; wpos = wpos_; }
72 C4_ALWAYS_INLINE void set_at_end() noexcept { skip(src.len - rpos); }
73
74 C4_ALWAYS_INLINE bool has_more_chars() const noexcept { return rpos < src.len; }
75 C4_ALWAYS_INLINE bool has_more_chars(size_t maxpos) const noexcept { _RYML_ASSERT_BASIC(maxpos <= src.len); return rpos < maxpos; }
76
77 C4_ALWAYS_INLINE csubstr rem() const noexcept { return src.sub(rpos); }
78 C4_ALWAYS_INLINE csubstr sofar() const noexcept { return csubstr(dst.str, wpos <= dst.len ? wpos : dst.len); }
79 C4_ALWAYS_INLINE FilterResult result() const noexcept
80 {
81 FilterResult ret;
82 ret.str.str = wpos <= dst.len ? dst.str : nullptr;
83 ret.str.len = wpos;
84 return ret;
85 }
86
87 C4_ALWAYS_INLINE char curr() const noexcept { _RYML_ASSERT_BASIC(rpos < src.len); return src[rpos]; }
88 C4_ALWAYS_INLINE char next() const noexcept { return rpos+1 < src.len ? src[rpos+1] : '\0'; }
89 C4_ALWAYS_INLINE bool skipped_chars() const noexcept { return wpos != rpos; }
90
91 C4_ALWAYS_INLINE void skip() noexcept { ++rpos; }
92 C4_ALWAYS_INLINE void skip(size_t num) noexcept { rpos += num; }
93
94 C4_ALWAYS_INLINE void set_at(size_t pos, char c) noexcept // NOLINT(readability-make-member-function-const)
95 {
96 _RYML_ASSERT_BASIC(pos < wpos);
97 dst.str[pos] = c;
98 }
99 C4_ALWAYS_INLINE void set(char c) noexcept
100 {
101 if(wpos < dst.len)
102 dst.str[wpos] = c;
103 ++wpos;
104 }
105 C4_ALWAYS_INLINE void set(char c, size_t num) noexcept
106 {
107 _RYML_ASSERT_BASIC(num > 0);
108 if(wpos + num <= dst.len)
109 memset(dst.str + wpos, c, num);
110 wpos += num;
111 }
112
113 C4_ALWAYS_INLINE void copy() noexcept
114 {
115 _RYML_ASSERT_BASIC(rpos < src.len);
116 if(wpos < dst.len)
117 dst.str[wpos] = src.str[rpos];
118 ++wpos;
119 ++rpos;
120 }
121 C4_ALWAYS_INLINE void copy(size_t num) noexcept
122 {
123 _RYML_ASSERT_BASIC(num);
124 _RYML_ASSERT_BASIC(rpos+num <= src.len);
125 if(wpos + num <= dst.len)
126 memcpy(dst.str + wpos, src.str + rpos, num);
127 wpos += num;
128 rpos += num;
129 }
130
131 C4_ALWAYS_INLINE void translate_esc(char c) noexcept
132 {
133 if(wpos < dst.len)
134 dst.str[wpos] = c;
135 ++wpos;
136 rpos += 2;
137 }
138 C4_ALWAYS_INLINE void translate_esc_bulk(const char *C4_RESTRICT s, size_t nw, size_t nr) noexcept
139 {
140 _RYML_ASSERT_BASIC(nw > 0);
141 _RYML_ASSERT_BASIC(nr > 0);
142 _RYML_ASSERT_BASIC(rpos+nr <= src.len);
143 if(wpos+nw <= dst.len)
144 memcpy(dst.str + wpos, s, nw);
145 wpos += nw;
146 rpos += 1 + nr;
147 }
148 C4_ALWAYS_INLINE void translate_esc_extending(const char *C4_RESTRICT s, size_t nw, size_t nr) noexcept
149 {
150 translate_esc_bulk(s, nw, nr);
151 }
152};
153
154
155//-----------------------------------------------------------------------------
156// filter in place
157
158// debugging scaffold
159/** @cond dev */
160#if defined(RYML_DBG) && 0
161#define _c4dbgip(...) _c4dbgpf(__VA_ARGS__)
162#else
163#define _c4dbgip(...)
164#endif
165/** @endcond */
166
167/** Filters in place. While the result may be larger than the source,
168 * any extending happens only at the end of the string. Consequently,
169 * it's impossible for characters to be left unfiltered.
170 *
171 * @see FilterProcessorInplaceMidExtending */
173{
174 substr src; ///< the subject string
175 size_t wcap; ///< write capacity - the capacity of the subject string's buffer
176 size_t rpos; ///< read position
177 size_t wpos; ///< write position
178
179 C4_ALWAYS_INLINE FilterProcessorInplaceEndExtending(substr src_, size_t wcap_) noexcept
180 : src(src_)
181 , wcap(wcap_)
182 , rpos(0)
183 , wpos(0)
184 {
185 _RYML_ASSERT_BASIC(wcap >= src.len);
186 }
187
188 C4_ALWAYS_INLINE void setwpos(size_t wpos_) noexcept { wpos = wpos_; }
189 C4_ALWAYS_INLINE void setpos(size_t rpos_, size_t wpos_) noexcept { rpos = rpos_; wpos = wpos_; }
190 C4_ALWAYS_INLINE void set_at_end() noexcept { skip(src.len - rpos); }
191
192 C4_ALWAYS_INLINE bool has_more_chars() const noexcept { return rpos < src.len; }
193 C4_ALWAYS_INLINE bool has_more_chars(size_t maxpos) const noexcept { _RYML_ASSERT_BASIC(maxpos <= src.len); return rpos < maxpos; }
194
195 C4_ALWAYS_INLINE FilterResult result() const noexcept
196 {
197 _c4dbgip("inplace: wpos={} wcap={} small={}", wpos, wcap, wpos > rpos);
198 FilterResult ret;
199 ret.str.str = (wpos <= wcap) ? src.str : nullptr;
200 ret.str.len = wpos;
201 return ret;
202 }
203 C4_ALWAYS_INLINE csubstr sofar() const noexcept { return csubstr(src.str, wpos <= wcap ? wpos : wcap); }
204 C4_ALWAYS_INLINE csubstr rem() const noexcept { return src.sub(rpos); }
205
206 C4_ALWAYS_INLINE char curr() const noexcept { _RYML_ASSERT_BASIC(rpos < src.len); return src[rpos]; }
207 C4_ALWAYS_INLINE char next() const noexcept { return rpos+1 < src.len ? src[rpos+1] : '\0'; }
208
209 C4_ALWAYS_INLINE void skip() noexcept { ++rpos; }
210 C4_ALWAYS_INLINE void skip(size_t num) noexcept { rpos += num; }
211
212 void set_at(size_t pos, char c) noexcept
213 {
214 _RYML_ASSERT_BASIC(pos < wpos);
215 const size_t save = wpos;
216 wpos = pos;
217 set(c);
218 wpos = save;
219 }
220 void set(char c) noexcept
221 {
222 if(wpos < wcap) // respect write-capacity
223 src.str[wpos] = c;
224 ++wpos;
225 }
226 void set(char c, size_t num) noexcept
227 {
228 _RYML_ASSERT_BASIC(num);
229 if(wpos + num <= wcap) // respect write-capacity
230 memset(src.str + wpos, c, num);
231 wpos += num;
232 }
233
234 void copy() noexcept
235 {
236 _RYML_ASSERT_BASIC(wpos <= rpos);
237 _RYML_ASSERT_BASIC(rpos < src.len);
238 if(wpos < wcap) // respect write-capacity
239 src.str[wpos] = src.str[rpos];
240 ++rpos;
241 ++wpos;
242 }
243 void copy(size_t num) noexcept
244 {
245 _RYML_ASSERT_BASIC(num);
246 _RYML_ASSERT_BASIC(rpos+num <= src.len);
247 _RYML_ASSERT_BASIC(wpos <= rpos);
248 if(wpos + num <= wcap) // respect write-capacity
249 {
250 if(wpos + num <= rpos) // there is no overlap
251 memcpy(src.str + wpos, src.str + rpos, num);
252 else // there is overlap
253 memmove(src.str + wpos, src.str + rpos, num);
254 }
255 rpos += num;
256 wpos += num;
257 }
258
259 void translate_esc(char c) noexcept
260 {
261 _RYML_ASSERT_BASIC(rpos + 2 <= src.len);
262 _RYML_ASSERT_BASIC(wpos <= rpos);
263 if(wpos < wcap) // respect write-capacity
264 src.str[wpos] = c;
265 rpos += 2; // add 1u to account for the escape character
266 ++wpos;
267 }
268
269 void translate_esc_bulk(const char *C4_RESTRICT s, size_t nw, size_t nr) noexcept
270 {
271 _RYML_ASSERT_BASIC(nw > 0);
272 _RYML_ASSERT_BASIC(nr > 0);
273 _RYML_ASSERT_BASIC(nw <= nr + 1u);
274 _RYML_ASSERT_BASIC(rpos+nr <= src.len);
275 _RYML_ASSERT_BASIC(wpos <= rpos);
276 const size_t wpos_next = wpos + nw;
277 const size_t rpos_next = rpos + nr + 1u; // add 1u to account for the escape character
278 _RYML_ASSERT_BASIC(wpos_next <= rpos_next);
279 if(wpos_next <= wcap)
280 memcpy(src.str + wpos, s, nw);
281 rpos = rpos_next;
282 wpos = wpos_next;
283 }
284
285 C4_ALWAYS_INLINE void translate_esc_extending(const char *C4_RESTRICT s, size_t nw, size_t nr) noexcept
286 {
287 translate_esc_bulk(s, nw, nr);
288 }
289};
290
291
292//-----------------------------------------------------------------------------
293//-----------------------------------------------------------------------------
294//-----------------------------------------------------------------------------
295
296/** Filters in place. The result may be larger than the source, and
297 * extending may happen anywhere. As a result some characters may be
298 * left unfiltered when there is no slack in the buffer and the
299 * write-position would overlap the read-position. Consequently, it's
300 * possible for characters to be left unfiltered. In YAML, this
301 * happens only with double-quoted strings, and only with a small
302 * number of escape sequences such as `\L` which is substituted by three
303 * bytes. These escape sequences cause a call to translate_esc_extending()
304 * which is the only entry point to this unfiltered situation.
305 *
306 * @see FilterProcessorInplaceMidExtending */
308{
309 substr src; ///< the subject string
310 size_t wcap; ///< write capacity - the capacity of the subject string's buffer
311 size_t rpos; ///< read position
312 size_t wpos; ///< write position
313 size_t maxcap; ///< the max capacity needed for filtering the string. This may be larger than the final string size.
314 bool unfiltered_chars; ///< number of characters that were not added to wpos from lack of capacity
315
316 C4_ALWAYS_INLINE FilterProcessorInplaceMidExtending(substr src_, size_t wcap_) noexcept
317 : src(src_)
318 , wcap(wcap_)
319 , rpos(0)
320 , wpos(0)
321 , maxcap(src.len)
322 , unfiltered_chars(false)
323 {
324 _RYML_ASSERT_BASIC(wcap >= src.len);
325 }
326
327 C4_ALWAYS_INLINE void setwpos(size_t wpos_) noexcept { wpos = wpos_; }
328 C4_ALWAYS_INLINE void setpos(size_t rpos_, size_t wpos_) noexcept { rpos = rpos_; wpos = wpos_; }
329 C4_ALWAYS_INLINE void set_at_end() noexcept { skip(src.len - rpos); }
330
331 C4_ALWAYS_INLINE bool has_more_chars() const noexcept { return rpos < src.len; }
332 C4_ALWAYS_INLINE bool has_more_chars(size_t maxpos) const noexcept { _RYML_ASSERT_BASIC(maxpos <= src.len); return rpos < maxpos; }
333
334 C4_ALWAYS_INLINE FilterResultExtending result() const noexcept
335 {
336 _c4dbgip("inplace: wpos={} wcap={} unfiltered={} maxcap={}", this->wpos, this->wcap, this->unfiltered_chars, this->maxcap);
338 ret.str.str = (wpos <= wcap && !unfiltered_chars) ? src.str : nullptr;
339 ret.str.len = wpos;
340 ret.reqlen = maxcap;
341 return ret;
342 }
343 C4_ALWAYS_INLINE csubstr sofar() const noexcept { return csubstr(src.str, wpos <= wcap ? wpos : wcap); }
344 C4_ALWAYS_INLINE csubstr rem() const noexcept { return src.sub(rpos); }
345
346 C4_ALWAYS_INLINE char curr() const noexcept { _RYML_ASSERT_BASIC(rpos < src.len); return src[rpos]; }
347 C4_ALWAYS_INLINE char next() const noexcept { return rpos+1 < src.len ? src[rpos+1] : '\0'; }
348
349 C4_ALWAYS_INLINE void skip() noexcept { ++rpos; }
350 C4_ALWAYS_INLINE void skip(size_t num) noexcept { rpos += num; }
351
352 void set_at(size_t pos, char c) noexcept
353 {
354 _RYML_ASSERT_BASIC(pos < wpos);
355 const size_t save = wpos;
356 wpos = pos;
357 set(c);
358 wpos = save;
359 }
360 void set(char c) noexcept
361 {
362 if(wpos < wcap) // respect write-capacity
363 {
364 if((wpos <= rpos) && !unfiltered_chars)
365 src.str[wpos] = c;
366 }
367 else
368 {
369 _c4dbgip("inplace: add unwritten {}->{} maxcap={}->{}!", unfiltered_chars, true, maxcap, (wpos+1u > maxcap ? wpos+1u : maxcap));
370 unfiltered_chars = true;
371 }
372 ++wpos;
373 maxcap = wpos > maxcap ? wpos : maxcap;
374 }
375 void set(char c, size_t num) noexcept
376 {
377 _RYML_ASSERT_BASIC(num);
378 if(wpos + num <= wcap) // respect write-capacity
379 {
380 if((wpos <= rpos) && !unfiltered_chars)
381 memset(src.str + wpos, c, num);
382 }
383 else
384 {
385 _c4dbgip("inplace: add unwritten {}->{} maxcap={}->{}!", unfiltered_chars, true, maxcap, (wpos+num > maxcap ? wpos+num : maxcap));
386 unfiltered_chars = true;
387 }
388 wpos += num;
389 maxcap = wpos > maxcap ? wpos : maxcap;
390 }
391
392 void copy() noexcept
393 {
394 _RYML_ASSERT_BASIC(rpos < src.len);
395 if(wpos < wcap) // respect write-capacity
396 {
397 if((wpos < rpos) && !unfiltered_chars) // write only if wpos is behind rpos
398 src.str[wpos] = src.str[rpos];
399 }
400 else
401 {
402 _c4dbgip("inplace: add unwritten {}->{} (wpos={}!=rpos={})={} (wpos={}<wcap={}) maxcap={}->{}!", unfiltered_chars, true, wpos, rpos, wpos!=rpos, wpos, wcap, wpos<wcap, maxcap, (wpos+1u > maxcap ? wpos+1u : maxcap));
403 unfiltered_chars = true;
404 }
405 ++rpos;
406 ++wpos;
407 maxcap = wpos > maxcap ? wpos : maxcap;
408 }
409 void copy(size_t num) noexcept
410 {
411 _RYML_ASSERT_BASIC(num);
412 _RYML_ASSERT_BASIC(rpos+num <= src.len);
413 if(wpos + num <= wcap) // respect write-capacity
414 {
415 if((wpos < rpos) && !unfiltered_chars) // write only if wpos is behind rpos
416 {
417 if(wpos + num <= rpos) // there is no overlap
418 memcpy(src.str + wpos, src.str + rpos, num);
419 else // there is overlap
420 memmove(src.str + wpos, src.str + rpos, num);
421 }
422 }
423 else
424 {
425 _c4dbgip("inplace: add unwritten {}->{} (wpos={}!=rpos={})={} (wpos={}<wcap={}) maxcap={}->{}!", unfiltered_chars, true, wpos, rpos, wpos!=rpos, wpos, wcap, wpos<wcap);
426 unfiltered_chars = true;
427 }
428 rpos += num;
429 wpos += num;
430 maxcap = wpos > maxcap ? wpos : maxcap;
431 }
432
433 void translate_esc(char c) noexcept
434 {
435 _RYML_ASSERT_BASIC(rpos + 2 <= src.len);
436 if(wpos < wcap) // respect write-capacity
437 {
438 if((wpos <= rpos) && !unfiltered_chars)
439 src.str[wpos] = c;
440 }
441 else
442 {
443 _c4dbgip("inplace: add unfiltered {}->{} maxcap={}->{}!", unfiltered_chars, true, maxcap, (wpos+1u > maxcap ? wpos+1u : maxcap));
444 unfiltered_chars = true;
445 }
446 rpos += 2;
447 ++wpos;
448 maxcap = wpos > maxcap ? wpos : maxcap;
449 }
450
451 C4_NO_INLINE void translate_esc_bulk(const char *C4_RESTRICT s, size_t nw, size_t nr) noexcept
452 {
453 _RYML_ASSERT_BASIC(nw > 0);
454 _RYML_ASSERT_BASIC(nr > 0);
455 _RYML_ASSERT_BASIC(nr+1u >= nw);
456 const size_t wpos_next = wpos + nw;
457 const size_t rpos_next = rpos + nr + 1u; // add 1u to account for the escape character
458 if(wpos_next <= wcap) // respect write-capacity
459 {
460 if((wpos <= rpos) && !unfiltered_chars) // write only if wpos is behind rpos
461 memcpy(src.str + wpos, s, nw);
462 }
463 else
464 {
465 _c4dbgip("inplace: add unwritten {}->{} (wpos={}!=rpos={})={} (wpos={}<wcap={}) maxcap={}->{}!", unfiltered_chars, true, wpos, rpos, wpos!=rpos, wpos, wcap, wpos<wcap);
466 unfiltered_chars = true;
467 }
468 rpos = rpos_next;
469 wpos = wpos_next;
470 maxcap = wpos > maxcap ? wpos : maxcap;
471 }
472
473 C4_NO_INLINE void translate_esc_extending(const char *C4_RESTRICT s, size_t nw, size_t nr) noexcept
474 {
475 _RYML_ASSERT_BASIC(nw > 0);
476 _RYML_ASSERT_BASIC(nr > 0);
477 _RYML_ASSERT_BASIC(rpos+nr <= src.len);
478 const size_t wpos_next = wpos + nw;
479 const size_t rpos_next = rpos + nr + 1u; // add 1u to account for the escape character
480 if(wpos_next <= rpos_next) // read and write do not overlap. just do a vanilla copy.
481 {
482 if((wpos_next <= wcap) && !unfiltered_chars)
483 memcpy(src.str + wpos, s, nw);
484 rpos = rpos_next;
485 wpos = wpos_next;
486 maxcap = wpos > maxcap ? wpos : maxcap;
487 }
488 else // there is overlap. move the (to-be-read) string to the right.
489 {
490 const size_t excess = wpos_next - rpos_next;
491 _RYML_ASSERT_BASIC(wpos_next > rpos_next);
492 if(src.len + excess <= wcap) // ensure we do not go past the end
493 {
494 _RYML_ASSERT_BASIC(rpos+nr+excess <= src.len);
495 if(wpos_next <= wcap)
496 {
498 {
499 memmove(src.str + wpos_next, src.str + rpos_next, src.len - rpos_next);
500 memcpy(src.str + wpos, s, nw);
501 }
502 rpos = wpos_next; // wpos, not rpos
503 }
504 else
505 {
506 rpos = rpos_next;
507 //const size_t unw = nw > (nr + 1u) ? nw - (nr + 1u) : 0;
508 _c4dbgip("inplace: add unfiltered {}->{} maxcap={}->{}!", unfiltered_chars, true);
509 unfiltered_chars = true;
510 }
511 wpos = wpos_next;
512 // extend the string up to capacity
513 src.len += excess;
514 maxcap = wpos > maxcap ? wpos : maxcap;
515 }
516 else
517 {
518 //const size_t unw = nw > (nr + 1u) ? nw - (nr + 1u) : 0;
519 _RYML_ASSERT_BASIC(rpos_next <= src.len);
520 const size_t required_size = wpos_next + (src.len - rpos_next);
521 _c4dbgip("inplace: add unfiltered {}->{} maxcap={}->{}!", unfiltered_chars, true, maxcap, required_size > maxcap ? required_size : maxcap);
522 _RYML_ASSERT_BASIC(required_size > wcap);
523 unfiltered_chars = true;
524 maxcap = required_size > maxcap ? required_size : maxcap;
525 wpos = wpos_next;
526 rpos = rpos_next;
527 }
528 }
529 }
530};
531
532#undef _c4dbgip
533
534
535/** @} */
536
537} // namespace yml
538} // namespace c4
539
540#endif /* _C4_YML_FILTER_PROCESSOR_HPP_ */
Lightweight generic type-safe wrappers for converting individual values to/from strings.
Error utilities used by ryml.
basic_substring< char > substr
a mutable string view
Definition substr.hpp:2356
basic_substring< const char > csubstr
an immutable string view
Definition substr.hpp:2357
(Undefined by default) Use shorter error message from checks/asserts: do not show the check condition...
Definition common.cpp:14
size_t len
the length of the substring
Definition substr.hpp:218
C * str
a restricted pointer to the first character of the substring
Definition substr.hpp:216
FilterProcessorInplaceEndExtending(substr src_, size_t wcap_) noexcept
size_t wcap
write capacity - the capacity of the subject string's buffer
void setpos(size_t rpos_, size_t wpos_) noexcept
void translate_esc_extending(const char *s, size_t nw, size_t nr) noexcept
void set(char c, size_t num) noexcept
void translate_esc_bulk(const char *s, size_t nw, size_t nr) noexcept
bool has_more_chars(size_t maxpos) const noexcept
void set_at(size_t pos, char c) noexcept
FilterResultExtending result() const noexcept
void translate_esc_extending(const char *s, size_t nw, size_t nr) noexcept
void translate_esc_bulk(const char *s, size_t nw, size_t nr) noexcept
FilterProcessorInplaceMidExtending(substr src_, size_t wcap_) noexcept
size_t maxcap
the max capacity needed for filtering the string. This may be larger than the final string size.
bool has_more_chars(size_t maxpos) const noexcept
void setpos(size_t rpos_, size_t wpos_) noexcept
void set_at(size_t pos, char c) noexcept
size_t wcap
write capacity - the capacity of the subject string's buffer
bool unfiltered_chars
number of characters that were not added to wpos from lack of capacity
void set(char c, size_t num) noexcept
void translate_esc_bulk(const char *s, size_t nw, size_t nr) noexcept
void set_at(size_t pos, char c) noexcept
void setpos(size_t rpos_, size_t wpos_) noexcept
void copy(size_t num) noexcept
csubstr rem() const noexcept
FilterResult result() const noexcept
void skip(size_t num) noexcept
FilterProcessorSrcDst(csubstr src_, substr dst_) noexcept
void setwpos(size_t wpos_) noexcept
bool has_more_chars() const noexcept
void translate_esc(char c) noexcept
bool skipped_chars() const noexcept
csubstr sofar() const noexcept
void translate_esc_extending(const char *s, size_t nw, size_t nr) noexcept
void set(char c, size_t num) noexcept
bool has_more_chars(size_t maxpos) const noexcept
Abstracts the fact that a scalar filter result may not fit in the intended memory.
size_t required_len() const noexcept
Abstracts the fact that a scalar filter result may not fit in the intended memory.
size_t required_len() const noexcept
bool valid() const noexcept