rapidyaml 0.16.0
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 */
5
6#ifndef RYML_SINGLE_HEADER
7#ifndef 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
23namespace c4 {
24namespace yml {
25namespace 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
64source : [a, bb, ccc]
65 has a string........
66 | offset "a"
67 | | length "a"
68 | | |
69 event0 event1 event2 [ event3 "a"......|..|
70 | | | | | |
71(start) +--------+-------+------------------+---------------+--+-----> (continued)
72arr[i] : BSTR BDOC VAL_|BSEQ|FLOW VAL_|SCLR|PLAI..1..1
73i : 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)
83arr[i] : VAL_|SCLR|PLAI|PSTR..4..2 VAL_|SCLR|PLAI|PSTR..8..3
84i : 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)
95arr[i] : ESEQ|PSTR EDOC ESTR
96i : 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. */
176using evt_size = int32_t;
177
178namespace 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. */
183using evt_bits = int32_t;
184
185
186/** enumeration of integer event bits. */
187typedef 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 */
275using DataType RYML_DEPRECATED("use evt_bits") = evt_bits;
276using 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
292namespace c4 {
293namespace yml {
294namespace 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
322C4_SUPPRESS_WARNING_GCC_CLANG_PUSH
323C4_SUPPRESS_WARNING_GCC_CLANG("-Wold-style-cast")
324C4_SUPPRESS_WARNING_GCC("-Wuseless-cast")
325
326namespace c4 {
327namespace yml {
328namespace extra {
329
330
331/** @addtogroup doc_event_handlers_ints
332 * @{ */
333
334/** @cond dev */
335struct 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 */
460struct 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
472public:
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
491public:
492
493 /** @name construction and resetting
494 * @{ */
495
498 {
499 reset(substr{}, substr{}, nullptr, 0);
500 }
503 {
504 }
505
506 void reset(substr str, substr arena, ievt::evt_bits *dst, evt_size dst_size)
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
557public:
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
582public:
583
584 /** @name YAML stream events */
585 /** @{ */
586
588 {
590 }
591
593 {
595 }
596
597 /** @} */
598
599public:
600
601 /** @name YAML document events */
602 /** @{ */
603
604 /** implicit doc start (without ---) */
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
653public:
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
706public:
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
759public:
760
761 /** @name YAML structure events */
762 /** @{ */
763
765 {
766 RYML_ASSERT_BASIC_CB_(m_stack.m_callbacks, m_parent);
767 m_curr->evt_type = {};
768 }
769
770 /** @} */
771
772public:
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{});
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{});
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
877private:
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
899public:
900
901 /** @name YAML anchor/reference events */
902 /** @{ */
903
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 }
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
950public:
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
972public:
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
994public:
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
1133public:
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 */
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
1160public:
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)
1322C4_SUPPRESS_WARNING_GCC_CLANG_POP
1323
1324#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)