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