rapidyaml  0.16.0
parseandemitYAML,anddoitfast
event_handler_ints.hpp
Go to the documentation of this file.
1 #ifndef C4_YML_EXTRA_EVENT_HANDLER_INTS_HPP_
2 #define C4_YML_EXTRA_EVENT_HANDLER_INTS_HPP_
3 
4 /** @file event_handler_ints.hpp */
5 
6 #ifndef RYML_SINGLE_HEADER
7 #ifndef C4_YML_NODE_TYPE_HPP_
8 #include <c4/yml/node_type.hpp>
9 #endif
10 #ifndef C4_YML_EVENT_HANDLER_STACK_HPP_
12 #endif
13 #ifndef C4_YML_TAG_HPP_
14 #include <c4/yml/tag.hpp>
15 #endif
16 #ifndef C4_YML_DETAIL_DBGPRINT_HPP_
17 #include <c4/yml/detail/dbgprint.hpp>
18 #endif
19 #endif
20 
21 // NOLINTBEGIN(hicpp-signed-bitwise,*avoid-c-style-cast)
22 
23 namespace c4 {
24 namespace yml {
25 namespace extra {
26 
27 /** @addtogroup doc_event_handlers_ints
28  *
29  * An event handler used by @ref ParseEngine to creates an integer
30  * buffer with a very compact representation of the YAML tree in a
31  * source buffer. This feature is an extra and is not part of the main
32  * rapidyaml library.
33  *
34  * This is meant for use by other programming languages, and supports
35  * container keys (unlike the ryml tree). It parses faster than the ryml
36  * tree parser, because the resulting data structure is much simpler.
37  *
38  * The resulting integer buffer is a linear array of integers
39  * containing encoded YAML events (as a mask of @ref ievt::EventBits),
40  * which in some cases (eg scalars) are followed by an encoded string
41  * (encoded as an offset and length to the parsed source buffer).
42  *
43  * For example, parsing `[a, bb, ccc]` results in the following event
44  * buffer (grouped to highlight the event sequence structure):
45  *
46  * ```c++
47  * using namespace c4::yml::extra::ievt;
48  * const evt_bits arr[] = { // result of parsing: [a, bb, ccc]
49  * BSTR, // begin stream
50  * BDOC, // begin doc
51  * VAL_|BSEQ|FLOW, // begin seq as val, flow
52  * VAL_|SCLR|PLAI, 1, 1, // val scalar, plain style, "a" : string starts at offset 1 and has length 1
53  * VAL_|SCLR|PLAI|PSTR, 4, 2, // val scalar, plain style, "bb" : string starts at offset 4 and has length 2; preceded by a string event (PSTR)
54  * VAL_|SCLR|PLAI|PSTR, 8, 3, // val scalar, plain style, "ccc": string starts at offset 8 and has length 3; preceded by a string event (PSTR)
55  * ESEQ|PSTR, // end seq; preceded by a string event (PSTR)
56  * EDOC, // end doc
57  * ESTR, // end stream
58  * };
59  * ```
60  *
61  * Here is a sketch clarifying the meaning of this event sequence:
62  *
63 @code
64 source : [a, bb, ccc]
65  has a string........
66  | offset "a"
67  | | length "a"
68  | | |
69  event0 event1 event2 [ event3 "a"......|..|
70  | | | | | |
71 (start) +--------+-------+------------------+---------------+--+-----> (continued)
72 arr[i] : BSTR BDOC VAL_|BSEQ|FLOW VAL_|SCLR|PLAI..1..1
73 i : 0 1 2 3 4 5
74 
75 
76  has a string............. has a string.............
77  | offset "bb" | offset "ccc"
78  | | length "bb" | | length "ccc"
79  | | | | | |
80  event4 "bb"..........|..| event5 "ccc".........|..|
81  | | | | | |
82  (cont)--> -----+--------------------+--+--------------+--------------------+--+-----> (continued)
83 arr[i] : VAL_|SCLR|PLAI|PSTR..4..2 VAL_|SCLR|PLAI|PSTR..8..3
84 i : 6 | 7 8 9 | 10 11
85  | |
86  prev event has string prev event has string
87  (to get to prev, jump (to get to prev, jump
88  back 3 slots: ie 6->3) back 3 slots: ie 9->6)
89 
90 
91 
92  event6 ] event7 event8
93  | | |
94  (cont)--> -----+-------------+--------+-----| (end)
95 arr[i] : ESEQ|PSTR EDOC ESTR
96 i : 12 | 13 14
97  |
98  prev event has string
99  (to get to it, jump
100  back 3 slots: ie 12->9)
101 @endcode
102  *
103  * Note that the buffer contains both events and strings encoded as
104  * integer pairs. That is, events that have an associated string are
105  * immediately followed by two integers providing the offset and length
106  * of that string in the source buffer. (In the example above, this
107  * happens in the events for the strings `a`, `bb`, and `ccc` at
108  * positions 3, 6 and 9, respectively).
109  *
110  * The flag @ref ievt::PSTR and the mask @ref ievt::WSTR are provided to
111  * enable easier iteration over the array: you can use them to test for
112  * presence of a string when iterating over the array.
113  *
114  * The flag @ref ievt::PSTR announces that an event is *preceded* by a
115  * string. That is, the previous event has a string, so that when this
116  * flag is found while iterating right-to-left, a jump of -3 should be
117  * used to get at the bitmask of the previous event. (In the example
118  * above, this flag is present for the events for `bb` and `ccc`, but not
119  * `a` because it is not preceded by a string).
120  *
121  * Likewise, to signify that the current event is *followed* by a string,
122  * there is the mask @ref ievt::WSTR, which is a mask of all the flags of
123  * events that have a string: @ref ievt::SCLR, @ref ievt::ALIA, @ref
124  * ievt::ANCH and @ref ievt::TAG_. While iterating left-to-right in the
125  * array, presence of any of the bits in the mask @ref ievt::WSTR means
126  * that a jump of +3 should be employed to get at the bitmask of the next
127  * event.
128  *
129  * Here's another example with the result of parsing `a: bb`
130  * ```c++
131  * const evt_bits arr[] = { // result of parsing: `a: bb`
132  * BSTR, // begin stream
133  * BDOC, // begin doc
134  * VAL_|BMAP|BLCK, // begin map as val, block
135  * KEY_|SCLR|PLAI, 0, 1, // key scalar, plain style: "a" starts at offset 0 and has length 1
136  * VAL_|SCLR|PLAI|PSTR, 3, 2, // val scalar, plain style: "bb" starts at offset 3 and has length 2
137  * EMAP|PSTR, // end map
138  * EDOC, // end doc
139  * ESTR, // end stream
140  * };
141  * ```
142  *
143  * Typical code to iterate left-to-right over the array will look like
144  * this:
145  *
146  * ```c++
147  * // source buffer, modified in place during parsing (IMPORTANT!)
148  * substr src = ...;
149  * substr arena = ...; // arena used for scalars/tags that are extended during filtering
150  * // events resulting from parsing
151  * const int events[] = {...};
152  * int events_size = ...;
153  * for(int i = 0; i < events_size; ++i)
154  * {
155  * if(events[i] & ievt::WSTR) // this event has a string following it
156  * {
157  * size_t offset = (size_t)events[i+1];
158  * size_t length = (size_t)events[i+2];
159  * csubstr region = (events[i] & ievt::AREN) ? arena : src; // is the string in the arena?
160  * csubstr str = region.sub(offset, length); // get the string
161  * ...
162  * i += 2; // skip the two ints of the string
163  * // (the jump is three places; the loop adds the other place)
164  * }
165  * else // this is a single-int event
166  * {
167  * ...
168  * }
169  * }
170  * ```
171  *
172  * @{ */
173 
174 /** data type for integer events size. This is set to an int32_t integer
175  * to allow compatibility with a wide range of processing languages. */
176 using evt_size = int32_t;
177 
178 namespace ievt {
179 
180 
181 /** data type for integer events bits. This is set to an int32_t integer
182  * to allow compatibility with a wide range of processing languages. */
183 using evt_bits = int32_t;
184 
185 
186 /** enumeration of integer event bits. */
187 typedef enum : evt_bits { // NOLINT
188 
189  //-------------------------------------------------------------------------
190  // YAML flags
191 
192  // YAML structure flags
193  KEY_ = (1 << 0), ///< as key
194  VAL_ = (1 << 1), ///< as value
195 
196  // YAML event scopes
197  BEG_ = (1 << 2), ///< scope: begin
198  END_ = (1 << 3), ///< scope: end
199  SEQ_ = (1 << 4), ///< scope: seq
200  MAP_ = (1 << 5), ///< scope: map
201  DOC_ = (1 << 6), ///< scope: doc
202  EXPL = (1 << 7), ///< `---` (with BDOC) or `...` (with EDOC)
203  STRM = (1 << 8), ///< scope: stream
204  BSEQ = BEG_|SEQ_, ///< begin seq (+SEQ in test suite events)
205  ESEQ = END_|SEQ_, ///< end seq (-SEQ in test suite events)
206  BMAP = BEG_|MAP_, ///< begin map (+MAP in test suite events)
207  EMAP = END_|MAP_, ///< end map (-MAP in test suite events)
208  BSTR = BEG_|STRM, ///< begin stream (+STR in test suite events)
209  ESTR = END_|STRM, ///< end stream (-STR in test suite events)
210  BDOC = BEG_|DOC_, ///< begin doc (+DOC in test suite events)
211  EDOC = END_|DOC_, ///< end doc (-DOC in test suite events)
212 
213  // YAML string events
214  SCLR = (1 << 9), ///< scalar (=VAL in test suite events)
215  ALIA = (1 << 10), ///< *ref (reference)
216  ANCH = (1 << 11), ///< &anchor
217  TAG_ = (1 << 12), ///< !tag
218  // directives
219  YAML = (1 << 13), ///< yaml directive: `\%YAML <version>`
220  TAGH = (1 << 14), ///< tag directive, handle: `\%TAG <handle> ........`
221  TAGP = (1 << 15), ///< tag directive, prefix: `\%TAG ........ <prefix>`
222 
223  // YAML style flags
224  PLAI = (1 << 16), ///< scalar: plain
225  SQUO = (1 << 17), ///< scalar: single-quoted (')
226  DQUO = (1 << 18), ///< scalar: double-quoted ("")
227  LITL = (1 << 19), ///< scalar: block literal (|)
228  FOLD = (1 << 20), ///< scalar: block folded (>)
229  FLOW = (1 << 21), ///< container: flow: [] for seqs or {} for maps
230  BLCK = (1 << 22), ///< container: block
231 
232  /// Special flag to mark a scalar as unfiltered (when the parser
233  /// is set not to filter).
234  UNFILT = (1 << 23),
235 
236  //-------------------------------------------------------------------------
237  // NON-YAML FLAGS
238 
239  /// Special flag to mark events whose string was placed in the
240  /// arena. This happens when the filtered string is larger than
241  /// the original string in the YAML code (eg from tags that
242  /// resolve to a larger string, or from "\L" or "\P" in double
243  /// quotes, which expand from two to three bytes). Because of this
244  /// size expansion, the filtered string cannot be placed in the
245  /// original source and needs to be placed in the arena.
246  AREN = (1 << 24),
247 
248  /// WithSTRing: mask of all events that encode a string following
249  /// the event. For such events, the next two integers will provide
250  /// respectively the string's offset and length. See also @ref PSTR
252 
253  /// Special flag to enable look-back in the event array. It
254  /// signifies that the previous event has a string, meaning that
255  /// the jump back to that event is 3 positions. without this flag it
256  /// would be impossible to jump to the previous event.
257  /// see also @ref WSTR
258  PSTR = (1 << 25),
259 
260  /// unused: reserved for future use (to enable rope-like buffers)
261  JUMP = (1 << 26),
262  /// unused: reserved for future use (same purpose as @ref PSTR,
263  /// but for @ref JUMP)
264  PJUMP = (1 << 27),
265 
266  /// the last flag defined above
268 
269  /// a mask of all bits in this enumeration
270  MASK = (LAST << 1) - 1,
271 
272 } EventBits;
273 
274 /** @cond dev */
275 using DataType RYML_DEPRECATED("use evt_bits") = evt_bits;
276 using EventFlags RYML_DEPRECATED("use EventBits") = EventBits;
277 /** @endcond */
278 
279 } // namespace ievt
280 
281 /** @} */ // doc_event_handlers_ints
282 
283 } // namespace extra
284 } // namespace yml
285 } // namespace c4
286 
287 
288 //-----------------------------------------------------------------------------
289 //-----------------------------------------------------------------------------
290 //-----------------------------------------------------------------------------
291 
292 namespace c4 {
293 namespace yml {
294 namespace extra {
295 
296 /** @addtogroup doc_event_handlers_ints
297  * @{ */
298 
299 /** Read YAML source and, without undergoing a full parse, estimate
300  * the size of the integer buffer required for @ref
301  * EventHandlerInts. This estimation is meant to exceed the actual
302  * number of required events.
303  *
304  * @note This function must overpredict. It does so for every case in
305  * the hundreds/thousands of extensive tests of rapidyaml -- both for
306  * the YAML test suite and the internal cases. If you find a case
307  * where that does not hold, it is a bug. Please report it at
308  * https://github.com/biojppm/rapidyaml/issues! */
310 
311 /** @} */
312 
313 } // namespace extra
314 } // namespace yml
315 } // namespace c4
316 
317 
318 //-----------------------------------------------------------------------------
319 //-----------------------------------------------------------------------------
320 //-----------------------------------------------------------------------------
321 
322 C4_SUPPRESS_WARNING_GCC_CLANG_PUSH
323 C4_SUPPRESS_WARNING_GCC_CLANG("-Wold-style-cast")
324 C4_SUPPRESS_WARNING_GCC("-Wuseless-cast")
325 
326 namespace c4 {
327 namespace yml {
328 namespace extra {
329 
330 
331 /** @addtogroup doc_event_handlers_ints
332  * @{ */
333 
334 /** @cond dev */
335 struct EventHandlerIntsState : public c4::yml::ParserState
336 {
337  c4::yml::type_bits evt_type;
338  int32_t evt_id;
339 };
340 /** @endcond */
341 
342 
343 /** A parser event handler that creates a compact representation of
344  * the YAML tree in a contiguous buffer of integers. The integers are
345  * @ref ievt::EventBits containing masks (to represent events),
346  * interleaved with offset+length (to represent strings in the source
347  * buffer).
348  *
349  * For a description of the events, see @ref doc_event_handlers_ints
350  *
351  * This handler must be initialized with the input source buffer, the
352  * output arena, and the output event buffer. This handler will not take
353  * ownership nor attempt to resize the output buffer. If the size
354  * required for the output buffer or arena are larger than their actual
355  * size, parsing goes all way to the end, determining the required buffer
356  * sizes without writing anything past the end of the respective
357  * buffer. After parsing is finished, the user must ensure that the
358  * buffer size was enough to accomodate all the data that needs to be
359  * written into it, or react accordingly (eg, throw an error, or resize
360  * the buffer then retry the parse).
361  *
362  * A couple of functions will be helpful to do this. After parsing, @ref
363  * EventHandlerInts::fits_buffers() must be used to verify that the
364  * output buffers were enough to accomodate the results. Then, @ref
365  * EventHandlerInts::required_size_events() and @ref
366  * EventHandlerInts::required_size_arena() can be used to retrieve to
367  * necessary information. To get an estimation of the number of events
368  * before parsing, see @ref estimate_events_ints_size().
369  *
370  * Typical code to parse YAML with this handler will look like this:
371  *
372  * ```c++
373  * csubstr filename = ...;
374  * substr src = ...;
375  * // estimate the size required for the events buffer,
376  * // overpredicting it to be safe.
377  * int estimated_size = extra::estimate_events_ints_size(src);
378  * extra::EventHandlerInts handler;
379  * ParseEngine<extra::EventHandlerInts> parser(&handler);
380  * // example with a vector
381  * std::vector<int> evts;
382  * // ensure we have a fighting chance to acommodate the events
383  * evts.resize((size_t)estimated_size);
384  * // arena to place scalars/tags that may have been extended after filtering
385  * std::vector<char> arena;
386  * arena.resize(src.len); // this is generally enough
387  * // initialize the handler
388  * handler.reset(src, arena, evts.data(), (int)evts.size());
389  * // parse the YAML
390  * parser.parse_in_place_ev(filename, src);
391  * if(handler.fits_buffers()) // were the buffer sizes enough?
392  * {
393  * evts.resize((size_t)handler.required_size_events()); // trim the vector
394  * ...
395  * }
396  * else
397  * {
398  * // event size estimation underpredicted, or arena is too small!
399  * // for the first case, open an issue at
400  * // https://github.com/biojppm/rapidyaml/issues
401  * error("buffer could not accomodate all the events");
402  * // NOTE: see below for notes on doing a parse retry.
403  * }
404  * ```
405  *
406  * The result of @ref estimate_events_ints_size() (click to see more
407  * info) must be an overprediction: it overpredicts for every single
408  * case among the many hundreds covered in the unit tests. This is
409  * deliberate, and aims at ensuring that a retry parse is not
410  * needed. But conceivably, it may underpredict in some instances not
411  * found in the out tests. What to do then?
412  *
413  * First, [open an issue](https://github.com/biojppm/rapidyaml/issues) to
414  * allow the estimation to be improved! Second, there are two ways to
415  * handle this situation in code:
416  *
417  * 1) throw an error (as sketched above)
418  *
419  * 2) grow the buffer to the required size (see @ref
420  * EventHandlerInts::required_size_events()), and then parse
421  * again
422  *
423  * If your code must be able to handle any case including where the
424  * prediction undershoots before the estimate function is fixed (after
425  * you open the issue), that is, if you are considering a parse retry,
426  * there is something important that needs attention. The YAML source
427  * buffer is mutated in-place during the parse, and cannot be used to
428  * parse again. So if you want to retry, you need to keep a pristine
429  * copy of the source, and use it for the retry:
430  *
431  * ```c++
432  * const std::string src = ...; // the YAML code to be parsed
433  * std::string parsed_src = src; // this is where we will parse (filter during parsing)
434  * std::vector<int> evts((size_t)estimated_size); // ensure we have a fighting change to acommodate the events
435  * std::vector<char> arena(src.size()); // ensure we have a fighting change to acommodate the events
436  * ParseEngine<extra::EventHandlerInts> parser(&handler);
437  * handler.reset(to_substr(parsed_src), to_substr(arena), evts.data(), (int)evts.size());
438  * parser.parse_in_place_ev(filename, to_substr(parsed_src));
439  * if(handler.fits_buffers()) // were the buffer sizes enough?
440  * {
441  * evts.resize((size_t)handler.required_size()); // trim the vector
442  * ...
443  * }
444  * else
445  * {
446  * evts.resize((size_t)handler.required_size_events()); // buffer size was not enough.
447  * arena.resize(handler.required_size_arena()); // buffer size was not enough.
448  * // copy again
449  * parsed_src = src;
450  * // retry parse
451  * handler.reset(to_substr(parsed_src), to_substr(arena), evts.data(), (int)evts.size());
452  * parser.parse_in_place_ev(filename, to_substr(parsed_src));
453  * assert((size_t)handler.fits_buffers()); // must always be true
454  * }
455  * ```
456  *
457  * When bringing this to other programming languages, the semantics
458  * will be very similar to this.
459  */
460 struct EventHandlerInts : public c4::yml::EventHandlerStack<EventHandlerInts, EventHandlerIntsState>
461 {
462 
463  /** @name types
464  * @{ */
465 
467  using state = EventHandlerIntsState; // our internal state must inherit from parser state
468  enum { requires_strings_on_buffers = true }; // NOLINT
469 
470  /** @} */
471 
472 public:
473 
474  /** @cond dev */
475  ievt::evt_bits * m_evt;
476  evt_size m_evt_pos;
477  evt_size m_evt_prev;
478  evt_size m_evt_size;
479  substr m_arena;
480  size_t m_arena_pos;
481  id_type m_curr_doc;
482  TagDirectives m_tag_directives;
483  TagCache m_tag_cache;
484 
485  // undefined at the end
486  #define ryml_enable_(bits) enable_<bits>()
487  #define ryml_disable_(bits) disable_<bits>()
488  #define ryml_has_any_(bits) has_any_<bits>()
489  /** @endcond */
490 
491 public:
492 
493  /** @name construction and resetting
494  * @{ */
495 
497  : EventHandlerStack(cb)
498  {
499  reset(substr{}, substr{}, nullptr, 0);
500  }
501  EventHandlerInts() noexcept
502  : EventHandlerInts(c4::yml::get_callbacks())
503  {
504  }
505 
507  {
510  m_curr->evt_type = {};
511  m_curr->evt_id = 0;
512  m_arena = arena;
513  m_arena_pos = 0;
514  m_src = str;
515  m_evt = dst;
516  m_evt_size = dst_size;
517  m_evt_pos = 0;
518  m_evt_prev = 0;
519  m_curr_doc = 0;
520  m_tag_directives.clear();
521  m_tag_cache.clear();
522  }
523 
524  /** get the size needed for the event buffer from the previous parse
525  * @warning this is valid only until the next parse */
527  {
528  return m_evt_pos;
529  }
530 
531  /** get the size needed for the arena from the previous parse
532  * @warning this is valid only until the next parse */
533  size_t required_size_arena() const
534  {
535  return m_arena_pos;
536  }
537 
538  /** Predicate to test if the event and arena buffers successfully
539  * accomodated all the parse events.
540  *
541  * @warning this is valid only until the next parse */
542  bool fits_buffers() const
543  {
544  return m_evt_pos <= m_evt_size && m_arena_pos <= m_arena.len;
545  }
546 
547  void reserve_arena(int /*arena_size*/)
548  {
549  // does not apply here
550  }
551 
552  C4_ALWAYS_INLINE TagDirectives &tag_directives() { return m_tag_directives; }
553  C4_ALWAYS_INLINE TagCache &tag_cache() { return m_tag_cache; }
554 
555  /** @} */
556 
557 public:
558 
559  /** @name parse events
560  * @{ */
561 
562  void start_parse(const char* filename, substr src)
563  {
564  RYML_ASSERT_BASIC_CB_(m_stack.m_callbacks, src.str == m_src.str);
565  RYML_ASSERT_BASIC_CB_(m_stack.m_callbacks, src.len == m_src.len);
566  this->_stack_start_parse(filename, src);
567  }
568 
570  {
571  this->_stack_finish_parse();
572  }
573 
575  {
576  while(m_stack.size() > 1)
577  _pop();
578  }
579 
580  /** @} */
581 
582 public:
583 
584  /** @name YAML stream events */
585  /** @{ */
586 
588  {
590  }
591 
592  void end_stream()
593  {
595  }
596 
597  /** @} */
598 
599 public:
600 
601  /** @name YAML document events */
602  /** @{ */
603 
604  /** implicit doc start (without ---) */
605  void begin_doc()
606  {
607  _c4dbgpf("{}/{}: begin_doc", m_evt_pos, m_evt_size);
610  {
611  _c4dbgp("push!");
612  _push();
613  ryml_enable_(DOC);
614  }
615  }
616  /** implicit doc end (without ...) */
617  void end_doc()
618  {
619  _c4dbgpf("{}/{}: end_doc", m_evt_pos, m_evt_size);
622  {
623  _c4dbgp("pop!");
624  _pop();
625  }
626  ++m_curr_doc;
627  }
628 
629  /** explicit doc start, with --- */
631  {
632  _c4dbgpf("{}/{}: begin_doc_expl", m_evt_pos, m_evt_size);
634  _c4dbgp("push!");
635  _push();
636  ryml_enable_(DOC);
637  }
638  /** explicit doc end, with ... */
640  {
641  _c4dbgpf("{}/{}: end_doc_expl", m_evt_pos, m_evt_size);
644  {
645  _c4dbgp("pop!");
646  _pop();
647  }
648  ++m_curr_doc;
649  }
650 
651  /** @} */
652 
653 public:
654 
655  /** @name YAML map functions */
656  /** @{ */
657 
659  {
660  _c4dbgpf("{}/{}: bmap key flow", m_evt_pos, m_evt_size);
664  _push();
665  }
667  {
668  _c4dbgpf("{}/{}: bmap key block", m_evt_pos, m_evt_size);
672  _push();
673  }
674 
676  {
677  _c4dbgpf("{}/{}: bmap flow", m_evt_pos, m_evt_size);
680  ryml_enable_(c4::yml::MAP|c4::yml::FLOW_SL);
681  _push();
682  }
684  {
685  _c4dbgpf("{}/{}: bmap block", m_evt_pos, m_evt_size);
688  ryml_enable_(c4::yml::MAP|c4::yml::BLOCK);
689  _push();
690  }
691 
693  {
694  _pop();
696  }
697 
698  void end_map_flow(bool /*multiline*/, type_bits /*multiline_style*/=FLOW_ML1)
699  {
700  _pop();
702  }
703 
704  /** @} */
705 
706 public:
707 
708  /** @name YAML seq events */
709  /** @{ */
710 
712  {
713  _c4dbgpf("{}/{}: bseq key flow", m_evt_pos, m_evt_size);
717  _push();
718  }
720  {
721  _c4dbgpf("{}/{}: bseq key block", m_evt_pos, m_evt_size);
725  _push();
726  }
727 
729  {
730  _c4dbgpf("{}/{}: bseq flow", m_evt_pos, m_evt_size);
733  ryml_enable_(c4::yml::SEQ|c4::yml::FLOW_SL);
734  _push();
735  }
737  {
738  _c4dbgpf("{}/{}: bseq block", m_evt_pos, m_evt_size);
741  ryml_enable_(c4::yml::SEQ|c4::yml::BLOCK);
742  _push();
743  }
744 
746  {
747  _pop();
749  }
750 
751  void end_seq_flow(bool /*multiline*/, type_bits /*multiline_style*/=FLOW_ML1)
752  {
753  _pop();
755  }
756 
757  /** @} */
758 
759 public:
760 
761  /** @name YAML structure events */
762  /** @{ */
763 
764  void add_sibling()
765  {
766  RYML_ASSERT_BASIC_CB_(m_stack.m_callbacks, m_parent);
767  m_curr->evt_type = {};
768  }
769 
770  /** @} */
771 
772 public:
773 
774  /** @name YAML scalar events */
775  /** @{ */
776 
777 
778  C4_ALWAYS_INLINE void set_key_scalar_plain_empty()
779  {
780  _c4dbgpf("{}/{}: set_key_scalar_plain_empty", m_evt_pos, m_evt_size);
783  }
784  C4_ALWAYS_INLINE void set_val_scalar_plain_empty()
785  {
786  _c4dbgpf("{}/{}: set_val_scalar_plain_empty", m_evt_pos, m_evt_size);
789  }
790 
791 
792  C4_ALWAYS_INLINE void set_key_scalar_plain(csubstr scalar)
793  {
794  _c4dbgpf("{}/{}: set_key_scalar_plain: @{} [{}]~~~{}~~~", m_evt_pos, m_evt_size, scalar.str-m_src.str, scalar.len, scalar);
796  ryml_enable_(c4::yml::KEY|c4::yml::KEY_PLAIN);
797  }
798  C4_ALWAYS_INLINE void set_val_scalar_plain(csubstr scalar)
799  {
800  _c4dbgpf("{}/{}: set_val_scalar_plain: @{} [{}]~~~{}~~~", m_evt_pos, m_evt_size, scalar.str-m_src.str, scalar.len, scalar);
802  ryml_enable_(c4::yml::VAL|c4::yml::VAL_PLAIN);
803  }
804 
805 
806  C4_ALWAYS_INLINE void set_key_scalar_dquoted(csubstr scalar)
807  {
808  _c4dbgpf("{}/{}: set_key_scalar_dquo: @{} [{}]~~~{}~~~", m_evt_pos, m_evt_size, scalar.str?size_t(scalar.str-m_src.str):m_src.len, scalar.len, scalar.str?scalar:csubstr{});
810  ryml_enable_(c4::yml::KEY|c4::yml::KEY_DQUO);
811  }
812  C4_ALWAYS_INLINE void set_val_scalar_dquoted(csubstr scalar)
813  {
814  _c4dbgpf("{}/{}: set_val_scalar_dquo: @{} [{}]~~~{}~~~", m_evt_pos, m_evt_size, scalar.str?size_t(scalar.str-m_src.str):m_src.len, scalar.len, scalar.str?scalar:csubstr{});
816  ryml_enable_(c4::yml::VAL|c4::yml::VAL_DQUO);
817  }
818 
819 
820  C4_ALWAYS_INLINE void set_key_scalar_squoted(csubstr scalar)
821  {
822  _c4dbgpf("{}/{}: set_key_scalar_squo: @{} [{}]~~~{}~~~", m_evt_pos, m_evt_size, scalar.str-m_src.str, scalar.len, scalar);
824  ryml_enable_(c4::yml::KEY|c4::yml::KEY_SQUO);
825  }
826  C4_ALWAYS_INLINE void set_val_scalar_squoted(csubstr scalar)
827  {
828  _c4dbgpf("{}/{}: set_val_scalar_squo: @{} [{}]~~~{}~~~", m_evt_pos, m_evt_size, scalar.str-m_src.str, scalar.len, scalar);
830  ryml_enable_(c4::yml::VAL|c4::yml::VAL_SQUO);
831  }
832 
833 
834  C4_ALWAYS_INLINE void set_key_scalar_literal(csubstr scalar)
835  {
836  _c4dbgpf("{}/{}: set_key_scalar_literal: @{} [{}]~~~{}~~~", m_evt_pos, m_evt_size, scalar.str?size_t(scalar.str-m_src.str):m_src.len, scalar.len, scalar.str?scalar:csubstr{});
838  ryml_enable_(c4::yml::KEY|c4::yml::KEY_LITERAL);
839  }
840  C4_ALWAYS_INLINE void set_val_scalar_literal(csubstr scalar)
841  {
842  _c4dbgpf("{}/{}: set_val_scalar_literal: @{} [{}]~~~{}~~~", m_evt_pos, m_evt_size, scalar.str?size_t(scalar.str-m_src.str):m_src.len, scalar.len, scalar.str?scalar:csubstr{});
844  ryml_enable_(c4::yml::VAL|c4::yml::VAL_LITERAL);
845  }
846 
847 
848  C4_ALWAYS_INLINE void set_key_scalar_folded(csubstr scalar)
849  {
850  _c4dbgpf("{}/{}: set_key_scalar_folded: @{} [{}]~~~{}~~~", m_evt_pos, m_evt_size, scalar.str?size_t(scalar.str-m_src.str):m_src.len, scalar.len, scalar.str?scalar:csubstr{});
852  ryml_enable_(c4::yml::KEY|c4::yml::KEY_FOLDED);
853  }
854  C4_ALWAYS_INLINE void set_val_scalar_folded(csubstr scalar)
855  {
856  _c4dbgpf("{}/{}: set_val_scalar_folded: @{} [{}]~~~{}~~~", m_evt_pos, m_evt_size, scalar.str?size_t(scalar.str-m_src.str):m_src.len, scalar.len, scalar.str?scalar:csubstr{});
858  ryml_enable_(c4::yml::VAL|c4::yml::VAL_FOLDED);
859  }
860 
861 
862  C4_ALWAYS_INLINE void mark_key_scalar_unfiltered() // NOLINT
863  {
864  _c4dbgpf("{}/{}: mark_key_scalar_unfiltered", m_evt_pos, m_evt_size);
865  if(m_evt_pos < m_evt_size)
866  m_evt[m_evt_pos] |= ievt::UNFILT;
867  }
868  C4_ALWAYS_INLINE void mark_val_scalar_unfiltered() // NOLINT
869  {
870  _c4dbgpf("{}/{}: mark_val_scalar_unfiltered", m_evt_pos, m_evt_size);
871  if(m_evt_pos < m_evt_size)
872  m_evt[m_evt_pos] |= ievt::UNFILT;
873  }
874 
875  /** @} */
876 
877 private:
878 
879  /** @cond dev*/
880  #define _add_scalar_(i, scalar) \
881  _c4dbgpf("{}/{}: scalar!", i, m_evt_size); \
882  RYML_ASSERT_BASIC_CB_(m_stack.m_callbacks, _is_sub_(scalar)); \
883  RYML_ASSERT_BASIC_CB_(m_stack.m_callbacks, m_evt[i] & ievt::WSTR); \
884  RYML_ASSERT_BASIC_CB_(m_stack.m_callbacks, ((i) + 3) < m_evt_size); \
885  if C4_LIKELY((scalar).is_sub(m_src)) \
886  { \
887  m_evt[(i) + 1] = (ievt::evt_bits)((scalar).str - m_src.str); \
888  } \
889  else \
890  { \
891  m_evt[i] |= ievt::AREN; \
892  m_evt[(i) + 1] = (ievt::evt_bits)((scalar).str - m_arena.str); \
893  _c4dbgpf("{}/{}: arena! ->{}", i, m_evt_size, m_evt[(i)+1]); \
894  } \
895  m_evt[(i) + 2] = (ievt::evt_bits)(scalar).len; \
896  m_evt[(i) + 3] = ievt::PSTR
897  /** @endcond */
898 
899 public:
900 
901  /** @name YAML anchor/reference events */
902  /** @{ */
903 
904  void set_key_anchor(csubstr anchor)
905  {
906  _c4dbgpf("{}/{}: set_key_anchor: {}", m_evt_pos, m_evt_size, anchor);
907  RYML_ASSERT_BASIC_CB_(m_stack.m_callbacks, !ryml_has_any_(KEYREF));
908  ryml_enable_(c4::yml::KEYANCH);
909  if(m_evt_pos + 3 < m_evt_size)
910  {
911  m_evt[m_evt_pos] |= ievt::KEY_|ievt::ANCH;
912  _add_scalar_(m_evt_pos, anchor);
913  }
914  m_evt_prev = m_evt_pos;
915  m_evt_pos += 3;
916  }
917  void set_val_anchor(csubstr anchor)
918  {
919  _c4dbgpf("{}/{}: set_val_anchor: {}", m_evt_pos, m_evt_size, anchor);
920  RYML_ASSERT_BASIC_CB_(m_stack.m_callbacks, !ryml_has_any_(VALREF));
921  ryml_enable_(c4::yml::VALANCH);
922  if(m_evt_pos + 3 < m_evt_size)
923  {
924  m_evt[m_evt_pos] |= ievt::VAL_|ievt::ANCH;
925  _add_scalar_(m_evt_pos, anchor);
926  }
927  m_evt_prev = m_evt_pos;
928  m_evt_pos += 3;
929  }
930 
932  {
933  _c4dbgpf("{}/{}: set_key_ref: {}", m_evt_pos, m_evt_size, ref);
934  RYML_ASSERT_PARSE_CB_(m_stack.m_callbacks, ref.begins_with('*'), m_curr->pos);
935  RYML_ASSERT_PARSE_CB_(m_stack.m_callbacks, !ryml_has_any_(KEYANCH), m_curr->pos);
936  ryml_enable_(c4::yml::KEY|c4::yml::KEYREF);
937  _send_str_(ref.sub(1), ievt::KEY_|ievt::ALIA); // skip the leading *
938  }
940  {
941  _c4dbgpf("{}/{}: set_val_ref: {}", m_evt_pos, m_evt_size, ref);
942  RYML_ASSERT_PARSE_CB_(m_stack.m_callbacks, ref.begins_with('*'), m_curr->pos);
943  RYML_ASSERT_PARSE_CB_(m_stack.m_callbacks, !ryml_has_any_(VALANCH), m_curr->pos);
944  ryml_enable_(c4::yml::VAL|c4::yml::VALREF);
945  _send_str_(ref.sub(1), ievt::VAL_|ievt::ALIA); // skip the leading *
946  }
947 
948  /** @} */
949 
950 public:
951 
952  /** @name YAML tag events */
953  /** @{ */
954 
956  {
957  _c4dbgpf("{}/{}: set key tag [{}]~~~{}~~~", m_evt_pos, m_evt_size, tag.len, tag.str ? tag : csubstr("(arena full)"));
958  RYML_ASSERT_BASIC_CB_(m_stack.m_callbacks, _is_sub_(tag));
959  ryml_enable_(c4::yml::KEYTAG);
961  }
963  {
964  _c4dbgpf("{}/{}: set val tag [{}]~~~{}~~~", m_evt_pos, m_evt_size, tag.len, tag.str ? tag : csubstr("(arena full)"));
965  RYML_ASSERT_BASIC_CB_(m_stack.m_callbacks, _is_sub_(tag));
966  ryml_enable_(c4::yml::VALTAG);
968  }
969 
970  /** @} */
971 
972 public:
973 
974  /** @name YAML directive events */
975  /** @{ */
976 
977  void add_directive_yaml(csubstr yaml_version)
978  {
979  _c4dbgpf("{}/{}: %YAML directive! version={}", m_evt_pos, m_evt_size, yaml_version);
980  _send_str_(yaml_version, ievt::YAML);
981  }
982 
983  void add_directive_tag(csubstr handle, csubstr prefix)
984  {
985  _c4dbgpf("{}/{}: %TAG directive! handle={} prefix={} doc_id={}", m_evt_pos, m_evt_size, handle, prefix, m_curr_doc);
986  if C4_UNLIKELY(!m_tag_directives.add(handle, prefix, m_curr_doc))
987  RYML_ERR_PARSE_CB_(m_stack.m_callbacks, m_curr->pos, "too many %TAG directives");
988  _send_str_(handle, ievt::TAGH);
989  _send_str_(prefix, ievt::TAGP);
990  }
991 
992  /** @} */
993 
994 public:
995 
996  /** @name YAML structure events */
997  /** @{ */
998 
999  /** set the previous val as the first key of a new map, with flow style.
1000  *
1001  * See the documentation for @ref doc_event_handlers, which
1002  * has important notes about this event.
1003  */
1005  {
1006  _c4dbgpf("{}/{}: prev={} actually_val_is_first_key_of_new_map_flow", m_evt_pos, m_evt_size, m_evt_prev);
1007  RYML_ASSERT_BASIC_CB_(m_stack.m_callbacks, m_evt_pos > 2);
1008  RYML_ASSERT_BASIC_CB_(m_stack.m_callbacks, m_evt_prev > 0);
1009  // BEFORE
1010  // ... flag start len (free)
1011  // | |
1012  // prev curr
1013  // AFTER
1014  // ... BMAP flag start len (free)
1015  // | |
1016  // prev curr
1017  if(m_evt_pos < m_evt_size)
1018  {
1019  if(m_evt[m_evt_prev] & ievt::WSTR)
1020  {
1021  _c4dbgpf("{}/{}: WSTR", m_evt_pos, m_evt_size);
1022  RYML_ASSERT_BASIC_CB_(m_stack.m_callbacks, m_evt_prev > 0);
1024  if(m_evt_pos + 1 < m_evt_size)
1025  {
1026  for(evt_size i = pos; i <= m_evt_prev; i = _next(i))
1027  {
1028  m_evt[i] |= ievt::KEY_;
1029  m_evt[i] &= ~ievt::VAL_;
1030  }
1031  evt_size num_move = m_evt_pos + 1 - pos;
1032  RYML_ASSERT_BASIC_CB_(m_stack.m_callbacks, num_move > 0);
1033  memmove(m_evt + pos + 1, m_evt + pos, (size_t)num_move * sizeof(ievt::evt_bits));
1034  }
1035  m_evt[pos] = ievt::BMAP|ievt::FLOW|ievt::VAL_;
1036  // move PSTR to prev
1037  if(m_evt[pos + 1] & ievt::PSTR)
1038  {
1039  m_evt[pos ] |= ievt::PSTR;
1040  m_evt[pos + 1] &= ~ievt::PSTR;
1041  }
1042  }
1043  else
1044  {
1045  _c4dbgpf("{}/{}: container key", m_evt_pos, m_evt_size);
1046  RYML_ASSERT_BASIC_CB_(m_stack.m_callbacks, (m_evt[m_evt_prev] & (ievt::EMAP|ievt::ESEQ)));
1047  evt_size pos;
1048  _c4dbgpf("{}/{}: find matching open for {}", m_evt_pos, m_evt_size, m_evt_prev);
1049  if((m_evt[m_evt_prev] & ievt::EMAP) == ievt::EMAP)
1050  {
1051  pos = _find_matching_open(ievt::BMAP, ievt::EMAP, m_evt_prev);
1052  }
1053  else
1054  {
1055  RYML_ASSERT_BASIC_CB_(m_stack.m_callbacks, (m_evt[m_evt_prev] & ievt::ESEQ));
1056  pos = _find_matching_open(ievt::BSEQ, ievt::ESEQ, m_evt_prev);
1057  }
1058  _c4dbgpf("{}/{}: matching open for {}={}", m_evt_pos, m_evt_size, m_evt_prev, pos);
1059  RYML_CHECK_BASIC_CB_(m_stack.m_callbacks, pos >= 0); // internal error
1060  RYML_CHECK_BASIC_CB_(m_stack.m_callbacks, pos < m_evt_prev); // internal error
1061  RYML_ASSERT_BASIC_CB_(m_stack.m_callbacks, (m_evt[pos] & ievt::ESEQ) == (m_evt[m_evt_prev] & ievt::BSEQ));
1062  RYML_ASSERT_BASIC_CB_(m_stack.m_callbacks, (m_evt[pos] & ievt::EMAP) == (m_evt[m_evt_prev] & ievt::BMAP));
1063  // shift the array one position to the right, starting at pos
1064  evt_size posp1 = pos + 1;
1065  if(m_evt_pos + 1 < m_evt_size)
1066  {
1067  evt_size num_move = m_evt_pos + 1 - pos;
1068  RYML_ASSERT_BASIC_CB_(m_stack.m_callbacks, num_move > 0);
1069  memmove(m_evt + posp1, m_evt + pos, (size_t)num_move * sizeof(ievt::evt_bits));
1070  }
1071  RYML_ASSERT_BASIC_CB_(m_stack.m_callbacks, posp1 < m_evt_pos);
1072  // start the map
1073  m_evt[pos] = ievt::BMAP|ievt::FLOW|ievt::VAL_;
1074  // set next as key, not val
1075  m_evt[posp1] |= ievt::KEY_;
1076  m_evt[posp1] &= ~ievt::VAL_;
1077  // move PSTR to pos
1078  if(m_evt[posp1] & ievt::PSTR)
1079  {
1080  m_evt[pos] |= ievt::PSTR;
1081  m_evt[posp1] &= ~ievt::PSTR;
1082  }
1083  }
1084  }
1085  m_curr->evt_id = m_evt_pos - 2;
1086  ++m_evt_prev;
1087  ++m_evt_pos;
1088  ryml_enable_(c4::yml::MAP|c4::yml::FLOW_SL);
1089  _push();
1090  }
1091 
1092  /** like its flow counterpart, but this function can only be
1093  * called after the end of a flow-val at root or doc level.
1094  *
1095  * See the documentation for @ref doc_event_handlers, which has
1096  * important notes about this event.
1097  */
1099  {
1100  _c4dbgpf("{}/{}: prev={} actually_val_is_first_key_of_new_map_block", m_evt_pos, m_evt_size, m_evt_prev);
1101  if(m_evt_pos < m_evt_size)
1102  {
1103  // interpolate BMAP|VAL|BLCK after the last BDOC
1104  evt_size pos = _find_last_bdoc(m_evt_pos);
1105  if(pos >= 0)
1106  {
1107  RYML_ASSERT_BASIC_CB_(m_stack.m_callbacks, pos < m_evt_size);
1108  RYML_ASSERT_BASIC_CB_(m_stack.m_callbacks, pos < m_evt_pos);
1109  RYML_ASSERT_BASIC_CB_(m_stack.m_callbacks, (m_evt[pos] & ievt::BDOC) == ievt::BDOC);
1110  if(m_evt_pos < m_evt_size)
1111  {
1112  ++pos; // add 1 to write after BDOC
1113  evt_size num_move = m_evt_pos - pos;
1114  evt_size posp1 = pos + 1;
1115  RYML_ASSERT_BASIC_CB_(m_stack.m_callbacks, ((m_evt[pos] & ievt::BSEQ) == ievt::BSEQ) || ((m_evt[pos] & ievt::BMAP) == ievt::BMAP));
1116  RYML_ASSERT_BASIC_CB_(m_stack.m_callbacks, num_move > 0);
1117  RYML_ASSERT_BASIC_CB_(m_stack.m_callbacks, 0 == (m_evt[posp1] & ievt::PSTR));
1118  memmove(m_evt + posp1, m_evt + pos, (size_t)num_move * sizeof(ievt::evt_bits));
1119  m_evt[pos] = ievt::VAL_|ievt::BMAP|ievt::BLCK;
1120  m_evt[posp1] &= ~ievt::VAL_;
1121  m_evt[posp1] |= ievt::KEY_;
1122  }
1123  }
1124  }
1125  ++m_curr->evt_id;
1126  ++m_evt_prev;
1127  ++m_evt_pos;
1128  _push();
1129  }
1130 
1131  /** @} */
1132 
1133 public:
1134 
1135  /** @name arena events */
1136  /** @{ */
1137 
1139  {
1140  return m_arena.first(m_arena_pos < m_arena.len ? m_arena_pos : m_arena.len);
1141  }
1142  substr arena_rem() // NOLINT
1143  {
1144  return C4_EXPECT(m_arena_pos <= m_arena.len, 1) ? m_arena.sub(m_arena_pos) : m_arena.last(0);
1145  }
1146  /** this may fail, in which case an empty string is returned */
1147  substr alloc_arena(size_t len)
1148  {
1149  substr s = arena_rem();
1150  if C4_LIKELY(len <= s.len)
1151  s.len = len;
1152  else
1153  s.str = nullptr;
1154  m_arena_pos += len;
1155  return s;
1156  }
1157 
1158  /** @} */
1159 
1160 public:
1161 
1162  /** @name implementation helpers */
1163  /** @{ */
1164 
1165  /** push a new parent, add a child to the new parent, and set the
1166  * child as the current node */
1167  void _push()
1168  {
1169  _stack_push();
1170  m_curr->evt_type = {};
1171  }
1172 
1173  /** end the current scope */
1174  void _pop()
1175  {
1176  _stack_pop();
1177  }
1178 
1179  template<c4::yml::type_bits bits> C4_ALWAYS_INLINE void enable_() noexcept
1180  {
1181  m_curr->evt_type |= bits;
1182  }
1183  template<c4::yml::type_bits bits> C4_ALWAYS_INLINE void disable_() noexcept
1184  {
1185  m_curr->evt_type &= ~bits;
1186  }
1187  template<c4::yml::type_bits bits> C4_ALWAYS_INLINE bool has_any_() const noexcept
1188  {
1189  return (m_curr->evt_type & bits) != c4::yml::type_bits(0);
1190  }
1191 
1192  C4_ALWAYS_INLINE evt_size _next(evt_size pos) const noexcept
1193  {
1194  RYML_ASSERT_BASIC_CB_(m_stack.m_callbacks, pos < m_evt_size);
1195  return pos + ((m_evt[pos] & ievt::WSTR) ? 3 : 1);
1196  }
1197 
1198  C4_ALWAYS_INLINE evt_size _prev(evt_size pos) const noexcept
1199  {
1200  RYML_ASSERT_BASIC_CB_(m_stack.m_callbacks, pos < m_evt_size);
1201  return pos - ((m_evt[pos] & ievt::PSTR) ? 3 : 1);
1202  }
1203 
1204  C4_ALWAYS_INLINE bool _is_sub_(csubstr str) const noexcept
1205  {
1206  return (!str.str || str.is_sub(m_src) || str.is_sub(m_arena));
1207  }
1208 
1209  C4_ALWAYS_INLINE void _send_flag_only_(ievt::evt_bits flags)
1210  {
1211  _c4dbgpf("{}/{}: flag only", m_evt_pos, m_evt_size);
1212  if(m_evt_pos < m_evt_size)
1213  m_evt[m_evt_pos] |= flags;
1214  m_curr->evt_id = m_evt_pos;
1215  m_evt_prev = m_evt_pos;
1216  ++m_evt_pos;
1217  if(m_evt_pos < m_evt_size)
1218  m_evt[m_evt_pos] = {};
1219  }
1220 
1221  C4_ALWAYS_INLINE void _send_str_(csubstr scalar, ievt::evt_bits flags)
1222  {
1223  _c4dbgpf("{}/{}: send str", m_evt_pos, m_evt_size);
1224  if(m_evt_pos + 3 < m_evt_size)
1225  {
1226  m_evt[m_evt_pos] |= flags;
1227  _add_scalar_(m_evt_pos, scalar);
1228  }
1229  m_curr->evt_id = m_evt_pos;
1230  m_evt_prev = m_evt_pos;
1231  m_evt_pos += 3;
1232  }
1233 
1235  {
1236  if(m_parent)
1237  m_parent->has_children = true;
1238  }
1239 
1240  C4_ALWAYS_INLINE csubstr _get_latest_empty_scalar() const
1241  {
1242  // ideally we should search back in the latest event that has
1243  // a scalar, then select a zero-length scalar immediately
1244  // after that scalar. But this also works for now:
1245  return m_src.first(0);
1246  }
1247 
1249  {
1250  RYML_ASSERT_BASIC_CB_(m_stack.m_callbacks, pos < m_evt_size); // it's safe to read from the array
1251  while(pos >= 0)
1252  {
1253  ievt::evt_bits e = m_evt[pos];
1254  if((e & ievt::BDOC) == ievt::BDOC)
1255  return pos;
1256  pos -= (e & ievt::PSTR) ? 3 : 1;
1257  }
1258  return -1; // LCOV_EXCL_LINE
1259  }
1260 
1262  {
1263  _c4dbgpf("find_matching: start at {}", pos);
1264  RYML_ASSERT_BASIC_CB_(m_stack.m_callbacks, pos < m_evt_size);
1265  RYML_ASSERT_BASIC_CB_(m_stack.m_callbacks, (m_evt[pos] & close) == close);
1266  RYML_ASSERT_BASIC_CB_(m_stack.m_callbacks, (m_evt[pos] & open) == (close & ~ievt::END_));
1267  pos = _prev(pos); // don't count the starting close token
1268  uint32_t count = 0;
1269  while(pos >= 0)
1270  {
1271  ievt::evt_bits e = m_evt[pos];
1272  _c4dbgpf("find_matching: pos={} count={} e={}", pos, count, m_evt[pos]);
1273  if((e & close) == close)
1274  {
1275  _c4dbgpf(".............: pos={} close! count={} e={}", pos, count, m_evt[pos]);
1276  ++count;
1277  }
1278  else if((e & open) == open)
1279  {
1280  _c4dbgpf(".............: pos={} open! count={} e={}", pos, count, m_evt[pos]);
1281  if(!count)
1282  return pos;
1283  else
1284  --count;
1285  }
1286  pos = _prev(pos);
1287  }
1288  _c4dbgpf("find_matching: not found!", 0); // LCOV_EXCL_LINE
1289  return -1; // LCOV_EXCL_LINE
1290  }
1291 
1293  {
1294  RYML_ASSERT_BASIC_CB_(m_stack.m_callbacks, pos < m_evt_size);
1295  evt_size prev = _prev(pos);
1296  while((prev > 0) && (m_evt[prev] & (ievt::TAG_|ievt::ANCH)))
1297  {
1298  _c4dbgpf("{}/{}: {} is anchor/tag. extend to {}", m_evt_pos, m_evt_size, prev, prev);
1299  pos = prev;
1300  prev = _prev(prev);
1301  }
1302  return pos;
1303  }
1304 
1305  /** @} */
1306 
1307 #undef ryml_enable_
1308 #undef ryml_disable_
1309 #undef ryml_has_any_
1310 #undef _add_scalar_
1311 
1312 };
1313 
1314 /** @} */
1315 
1316 } // namespace extra
1317 } // namespace yml
1318 } // namespace c4
1319 
1320 
1321 // NOLINTEND(hicpp-signed-bitwise,*avoid-c-style-cast)
1322 C4_SUPPRESS_WARNING_GCC_CLANG_POP
1323 
1324 #endif /* C4_YML_EXTRA_EVENT_HANDLER_INTS_HPP_ */
begin doc (+DOC in test suite events)
void reset(substr str, substr arena, ievt::evt_bits *dst, evt_size dst_size)
void add_directive_yaml(csubstr yaml_version)
mark val scalar as plain scalar (unquoted, even when multiline)
Definition: node_type.hpp:156
bool _is_sub_(csubstr str) const noexcept
the val has an &anchor
Definition: node_type.hpp:42
the key has a tag
Definition: node_type.hpp:43
void end_seq_flow(bool, type_bits=FLOW_ML1)
void end_map_flow(bool, type_bits=FLOW_ML1)
reading unknown state (when starting): must determine whether scalar, map or seq
evt_size _find_matching_open(ievt::evt_bits open, ievt::evt_bits close, evt_size pos) const
mark key scalar as double quoted "
Definition: node_type.hpp:153
begin seq (+SEQ in test suite events)
mark key scalar as multiline, block literal |
Definition: node_type.hpp:147
Special flag to mark a scalar as unfiltered (when the parser is set not to filter).
mark val scalar as single quoted '
Definition: node_type.hpp:152
void begin_doc_expl()
explicit doc start, with —
void set_key_scalar_squoted(csubstr scalar)
#define ryml_has_any_(bits)
WithSTRing: mask of all events that encode a string following the event. For such events...
size_t required_size_arena() const
get the size needed for the arena from the previous parse
C * str
a restricted pointer to the first character of the substring
Definition: substr.hpp:216
Use this class a base of implementations of event handler to simplify the stack logic.
void set_key_scalar_folded(csubstr scalar)
void set_val_scalar_dquoted(csubstr scalar)
type_bits bits
Definition: node_type.cpp:70
A c-style callbacks class to customize behavior on errors or allocation.
Definition: common.hpp:373
the val has a tag
Definition: node_type.hpp:44
A parser event handler that creates a compact representation of the YAML tree in a contiguous buffer ...
scalar: block folded (>)
EventBits flags
Definition: ints_utils.cpp:27
const char * str
Definition: node_type.cpp:70
bool fits_buffers() const
Predicate to test if the event and arena buffers successfully accomodated all the parse events...
void end_doc()
implicit doc end (without ...)
mark val scalar as double quoted "
Definition: node_type.hpp:154
void _send_flag_only_(ievt::evt_bits flags)
a non-owning string-view, consisting of a character pointer and a length.
Definition: substr.hpp:211
a mask of all bits in this enumeration
Accelerator structure to reduce memory requirements by enabling reuse of resolved tags...
Definition: tag.hpp:70
a document
Definition: node_type.hpp:37
evt_size required_size_events() const
get the size needed for the event buffer from the previous parse
basic_substring first(size_t num) const noexcept
return the first num elements: [0,num[
Definition: substr.hpp:529
the key is null (eg { : b} results in a null key)
Definition: node_type.hpp:45
tag directive, handle: \TAG ........
void set_val_scalar_literal(csubstr scalar)
substr alloc_arena(size_t len)
this may fail, in which case an empty string is returned
a scalar: has a scalar (ie string) value, possibly empty. must be a leaf node, and cannot be MAP or S...
Definition: node_type.hpp:34
evt_size estimate_events_ints_size(csubstr src)
Read YAML source and, without undergoing a full parse, estimate the size of the integer buffer requir...
the key has an &anchor
Definition: node_type.hpp:41
unused: reserved for future use (to enable rope-like buffers)
RYML_ID_TYPE id_type
The type of a node id in the YAML tree; to override the default type, define the macro RYML_ID_TYPE t...
Definition: common.hpp:124
Special flag to enable look-back in the event array. It signifies that the previous event has a strin...
void set_key_scalar_literal(csubstr scalar)
tag directive, prefix: \TAG ........
mark val scalar as multiline, block folded >
Definition: node_type.hpp:150
mark key scalar as multiline, block folded >
Definition: node_type.hpp:149
scalar: block literal (|)
void clear() noexcept
Definition: tag.hpp:93
basic_substring sub(size_t first) const noexcept
return [first,len[
Definition: substr.hpp:502
scalar: single-quoted (')
void actually_val_is_first_key_of_new_map_flow()
set the previous val as the first key of a new map, with flow style.
evt_size _prev(evt_size pos) const noexcept
basic_substring< const char > csubstr
an immutable string view
Definition: substr.hpp:2356
void _send_str_(csubstr scalar, ievt::evt_bits flags)
void set_key_scalar_dquoted(csubstr scalar)
the val is null (eg {a : } results in a null val)
Definition: node_type.hpp:46
a *reference: the val references an &anchor
Definition: node_type.hpp:40
mark container with block style < - seqs as <
Definition: node_type.hpp:136
void set_val_scalar_folded(csubstr scalar)
EventHandlerInts(c4::yml::Callbacks const &cb) noexcept
end seq (-SEQ in test suite events)
the scalar to the left of : in a map's member
Definition: node_type.hpp:33
void clear() noexcept
Definition: tag.cpp:375
void start_parse(const char *filename, substr src)
void set_val_scalar_squoted(csubstr scalar)
a *reference: the key references an &anchor
Definition: node_type.hpp:39
reading at top level
the last flag defined above
end stream (-STR in test suite events)
size_t len
the length of the substring
Definition: substr.hpp:218
void add_directive_tag(csubstr handle, csubstr prefix)
mark key scalar as plain scalar (unquoted, even when multiline)
Definition: node_type.hpp:155
int32_t evt_size
data type for integer events size.
void _pop()
end the current scope
end doc (-DOC in test suite events)
scalar: double-quoted ("")
begin map (+MAP in test suite events)
container: flow: [] for seqs or {} for maps
evt_size _extend_left_to_include_tag_and_or_anchor(evt_size pos) const
Callbacks const & get_callbacks()
get the global callbacks
Definition: common.cpp:94
void end_doc_expl()
explicit doc end, with ...
int32_t evt_bits
data type for integer events bits.
mark val scalar as multiline, block literal |
Definition: node_type.hpp:148
void begin_doc()
implicit doc start (without —)
Special flag to mark events whose string was placed in the arena. This happens when the filtered stri...
uint32_t type_bits
the integral type necessary to cover all the bits for NodeType_e
Definition: node_type.hpp:26
basic_substring last(size_t num) const noexcept
return the last num elements: [len-num,len[
Definition: substr.hpp:536
void _push()
push a new parent, add a child to the new parent, and set the child as the current node ...
--- (with BDOC) or ... (with EDOC)
void actually_val_is_first_key_of_new_map_block()
like its flow counterpart, but this function can only be called after the end of a flow-val at root o...
a map: a parent of KEYVAL/KEYSEQ/KEYMAP nodes
Definition: node_type.hpp:35
evt_size _find_last_bdoc(evt_size pos) const
#define RYML_EXPORT
Definition: export.hpp:18
mark key scalar as single quoted '
Definition: node_type.hpp:151
scalar (=VAL in test suite events)
EventBits
enumeration of integer event bits.
unused: reserved for future use (same purpose as PSTR, but for JUMP)
bool begins_with(const C c) const noexcept
true if the first character of the string is c
Definition: substr.hpp:850
TagDirective const * add(csubstr handle, csubstr prefix, id_type doc_id) noexcept
Definition: tag.cpp:360
mark container with multi-line flow style, 1 element per line < - seqs as <
Definition: node_type.hpp:75
end map (-MAP in test suite events)
a seq: a parent of VAL/SEQ/MAP nodes
Definition: node_type.hpp:36
state * m_curr
current stack level: top of the stack. cached here for easier access.
mark container with single-line flow style < - seqs as <
Definition: node_type.hpp:56
evt_size _next(evt_size pos) const noexcept
begin stream (+STR in test suite events)