rapidyaml  0.12.1
parse and emit YAML, and do it fast
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 
13 namespace c4 {
14 namespace 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; }
37  csubstr 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; }
46  csubstr str;
47  size_t reqlen;
48 };
49 
50 
51 //-----------------------------------------------------------------------------
52 
53 /** Filters an input string into a different output string */
55 {
56  csubstr src;
57  substr dst;
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  {
497  if(!unfiltered_chars)
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.
(Undefined by default) Use shorter error message from checks/asserts: do not show the check condition...
Definition: common.cpp:14
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
Filters an input string into a different output string.
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