rapidyaml  0.7.2
parse and emit YAML, and do it fast
test_suite_event_handler.hpp
Go to the documentation of this file.
1 #ifndef _C4_YML_EVENT_HANDLER_YAMLSTD_HPP_
2 #define _C4_YML_EVENT_HANDLER_YAMLSTD_HPP_
3 
4 #ifdef RYML_SINGLE_HEADER
5 #include <ryml_all.hpp>
6 #else
7 #ifndef _C4_YML_EVENT_HANDLER_STACK_HPP_
9 #endif
10 #ifndef _C4_YML_DETAIL_PRINT_HPP_
11 #include "c4/yml/detail/print.hpp"
12 #endif
13 #endif
14 
15 #ifndef _C4_YML_EXTRA_STRING_HPP_
16 #include "./string.hpp"
17 #endif
18 
19 C4_SUPPRESS_WARNING_GCC_CLANG_PUSH
20 C4_SUPPRESS_WARNING_GCC_CLANG("-Wold-style-cast")
21 C4_SUPPRESS_WARNING_GCC("-Wuseless-cast")
22 
23 namespace c4 {
24 namespace yml {
25 
26 
27 /** @addtogroup doc_event_handlers
28  * @{ */
29 
30 void append_escaped(extra::string *s, csubstr val);
31 
32 
33 /** The stack state needed specifically by @ref EventHandlerYamlStd */
35 {
37 };
38 
39 /** The event handler producing standard YAML events as used in the
40  * [YAML test suite](https://github.com/yaml/yaml-test-suite).
41  * See the documentation for @ref doc_event_handlers, which has
42  * important notes about the event model used by rapidyaml.
43  *
44  * This class is used only in the CI of this project, and in the
45  * application used as part of the [standard YAML
46  * playground](https://play.yaml.io/main/parser). It is not part of
47  * the library and is not installed. *
48  */
49 struct EventHandlerYamlStd : public EventHandlerStack<EventHandlerYamlStd, EventHandlerYamlStdState>
50 {
51 
52  /** @name types
53  * @{ */
54 
55  // our internal state must inherit from parser state
57 
58  using EventSink = extra::string;
59 
60  /** @} */
61 
62 public:
63 
64  /** @cond dev */
65  EventSink *C4_RESTRICT m_sink;
66  extra::string_vector m_val_buffers;
67  extra::string m_key_tag_buf;
68  extra::string m_val_tag_buf;
69  TagDirective m_tag_directives[RYML_MAX_TAG_DIRECTIVES];
70  bool m_has_yaml_directive;
71  extra::string m_arena;
72  bool m_has_docs;
73 
74  // undefined at the end
75  #define _enable_(bits) _enable__<bits>()
76  #define _disable_(bits) _disable__<bits>()
77  #define _has_any_(bits) _has_any__<bits>()
78  /** @endcond */
79 
80 public:
81 
82  /** @name construction and resetting
83  * @{ */
84 
85  EventHandlerYamlStd() : EventHandlerStack(), m_sink(), m_val_buffers(), m_key_tag_buf(), m_val_tag_buf(), m_tag_directives(), m_has_yaml_directive(), m_arena(), m_has_docs() {}
86  EventHandlerYamlStd(Callbacks const& cb) : EventHandlerStack(cb), m_sink(), m_val_buffers(), m_key_tag_buf(), m_val_tag_buf(), m_tag_directives(), m_has_yaml_directive(), m_arena(), m_has_docs() {}
87  EventHandlerYamlStd(EventSink *sink, Callbacks const& cb) : EventHandlerStack(cb), m_sink(sink), m_val_buffers(), m_key_tag_buf(), m_val_tag_buf(), m_tag_directives(), m_has_yaml_directive(), m_arena(), m_has_docs()
88  {
89  reset();
90  }
92 
93  void reset()
94  {
95  _stack_reset_root();
96  m_curr->flags |= RUNK|RTOP;
97  m_has_yaml_directive = false;
98  for(TagDirective &td : m_tag_directives)
99  td = {};
100  m_val_buffers.clear();
101  m_val_buffers.resize((size_t)m_stack.size());
102  m_arena.clear();
103  m_arena.reserve(1024);
104  m_key_tag_buf.resize(256);
105  m_val_tag_buf.resize(256);
106  m_has_docs = false;
107  }
108 
109  /** @} */
110 
111 public:
112 
113  /** @name parse events
114  * @{ */
115 
116  void start_parse(const char* filename, detail::pfn_relocate_arena relocate_arena, void *relocate_arena_data)
117  {
118  this->_stack_start_parse(filename, relocate_arena, relocate_arena_data);
119  }
120 
122  {
123  if((_num_tag_directives() || m_has_yaml_directive) && !m_has_docs)
124  _RYML_CB_ERR_(m_stack.m_callbacks, "directives cannot be used without a document", {});
125  this->_stack_finish_parse();
126  }
127 
129  {
130  while(m_stack.size() > 1)
131  _pop();
132  _buf_flush_();
133  }
134 
135  /** @} */
136 
137 public:
138 
139  /** @name YAML stream events */
140  /** @{ */
141 
143  {
144  _send_("+STR\n");
145  }
146 
147  void end_stream()
148  {
149  _send_("-STR\n");
150  _buf_flush_();
151  }
152 
153  /** @} */
154 
155 public:
156 
157  /** @name YAML document events */
158  /** @{ */
159 
160  /** implicit doc start (without ---) */
161  void begin_doc()
162  {
163  _c4dbgp("begin_doc");
164  if(_stack_should_push_on_begin_doc())
165  {
166  _c4dbgp("push!");
167  _push();
168  _enable_(DOC);
169  }
170  _send_("+DOC\n");
171  m_has_docs = true;
172  }
173  /** implicit doc end (without ...) */
174  void end_doc()
175  {
176  _c4dbgp("end_doc");
177  _send_("-DOC\n");
178  if(_stack_should_pop_on_end_doc())
179  {
180  _c4dbgp("pop!");
181  _pop();
182  }
183  }
184 
185  /** explicit doc start, with --- */
187  {
188  _c4dbgp("begin_doc_expl");
189  if(_stack_should_push_on_begin_doc())
190  {
191  _c4dbgp("push!");
192  _push();
193  }
194  _send_("+DOC ---\n");
195  _enable_(DOC);
196  m_has_docs = true;
197  }
198  /** explicit doc end, with ... */
200  {
201  _c4dbgp("end_doc_expl");
202  _send_("-DOC ...\n");
203  if(_stack_should_pop_on_end_doc())
204  {
205  _c4dbgp("pop!");
206  _pop();
207  }
208  m_has_yaml_directive = false;
209  }
210 
211  /** @} */
212 
213 public:
214 
215  /** @name YAML map functions */
216  /** @{ */
217 
219  {
220  _RYML_CB_CHECK(m_stack.m_callbacks, !_has_any_(VAL));
221  _send_("+MAP {}");
222  _send_key_props_();
223  _send_('\n');
224  _mark_parent_with_children_();
225  _enable_(MAP|FLOW_SL);
226  _push();
227  }
229  {
230  _RYML_CB_CHECK(m_stack.m_callbacks, !_has_any_(VAL));
231  _send_("+MAP");
232  _send_key_props_();
233  _send_('\n');
234  _mark_parent_with_children_();
235  _enable_(MAP|BLOCK);
236  _push();
237  }
238 
240  {
241  _RYML_CB_CHECK(m_stack.m_callbacks, !_has_any_(VAL));
242  _send_("+MAP {}");
243  _send_val_props_();
244  _send_('\n');
245  _mark_parent_with_children_();
246  _enable_(MAP|FLOW_SL);
247  _push();
248  }
250  {
251  _RYML_CB_CHECK(m_stack.m_callbacks, !_has_any_(VAL));
252  _send_("+MAP");
253  _send_val_props_();
254  _send_('\n');
255  _mark_parent_with_children_();
256  _enable_(MAP|BLOCK);
257  _push();
258  }
259 
260  void end_map()
261  {
262  _pop();
263  _send_("-MAP\n");
264  }
265 
266  /** @} */
267 
268 public:
269 
270  /** @name YAML seq events */
271  /** @{ */
272 
274  {
275  _RYML_CB_CHECK(m_stack.m_callbacks, !_has_any_(VAL));
276  _send_("+SEQ []");
277  _send_key_props_();
278  _send_('\n');
279  _mark_parent_with_children_();
280  _enable_(SEQ|FLOW_SL);
281  _push();
282  }
284  {
285  _RYML_CB_CHECK(m_stack.m_callbacks, !_has_any_(VAL));
286  _send_("+SEQ");
287  _send_key_props_();
288  _send_('\n');
289  _mark_parent_with_children_();
290  _enable_(SEQ|BLOCK);
291  _push();
292  }
293 
295  {
296  _RYML_CB_CHECK(m_stack.m_callbacks, !_has_any_(VAL));
297  _send_("+SEQ []");
298  _send_val_props_();
299  _send_('\n');
300  _mark_parent_with_children_();
301  _enable_(SEQ|FLOW_SL);
302  _push();
303  }
305  {
306  _RYML_CB_CHECK(m_stack.m_callbacks, !_has_any_(VAL));
307  _send_("+SEQ");
308  _send_val_props_();
309  _send_('\n');
310  _mark_parent_with_children_();
311  _enable_(SEQ|BLOCK);
312  _push();
313  }
314 
315  void end_seq()
316  {
317  _pop();
318  _send_("-SEQ\n"); // before popping
319  }
320 
321  /** @} */
322 
323 public:
324 
325  /** @name YAML structure events */
326  /** @{ */
327 
328  void add_sibling()
329  {
330  _RYML_CB_ASSERT(m_stack.m_callbacks, m_parent);
331  _buf_flush_to_(m_curr->level, m_parent->level);
332  m_curr->ev_data = {};
333  }
334 
335  /** set the previous val as the first key of a new map, with flow style.
336  *
337  * See the documentation for @ref doc_event_handlers, which has
338  * important notes about this event.
339  */
341  {
342  // ensure we have a temporary buffer to save the current val
343  const id_type tmp = m_curr->level + id_type(2);
344  _buf_ensure_(tmp + id_type(2));
345  // save the current val to the temporary buffer
346  _buf_flush_to_(m_curr->level, tmp);
347  _disable_(_VALMASK|VAL_STYLE);
348  // create the map.
349  // this will push a new level, and tmp is one further
350  begin_map_val_flow();
351  _RYML_CB_ASSERT(m_stack.m_callbacks, tmp != m_curr->level);
352  // now move the saved val as the first key
353  _buf_flush_to_(tmp, m_curr->level);
354  }
355 
356  /** like its flow counterpart, but this function can only be
357  * called after the end of a flow-val at root or doc level.
358  *
359  * See the documentation for @ref doc_event_handlers, which has
360  * important notes about this event.
361  */
363  {
364  EventSink &sink = _buf_();
365  substr full = sink;(void)full;
366  // interpolate +MAP\n after the last +DOC\n
367  _RYML_CB_ASSERT(m_stack.m_callbacks, full.len);
368  _RYML_CB_ASSERT(m_stack.m_callbacks, !full.count('\r'));
369  size_t docpos = sink.find_last("+DOC\n");
370  if(docpos != npos)
371  {
372  _RYML_CB_ASSERT(m_stack.m_callbacks, (m_stack.size() == 1u) ? (docpos >= 5u) : (docpos == 0u));
373  _RYML_CB_ASSERT(m_stack.m_callbacks, docpos + 5u < full.len);
374  sink.insert("+MAP\n", docpos + 5u);
375  }
376  else
377  {
378  // ... or interpolate +MAP\n after the last +DOC ---\n
379  docpos = sink.find_last("+DOC ---\n");
380  _RYML_CB_ASSERT(m_stack.m_callbacks, docpos != npos);
381  _RYML_CB_ASSERT(m_stack.m_callbacks, (m_stack.size() == 1u) ? (docpos >= 5u) : (docpos == 0u));
382  _RYML_CB_ASSERT(m_stack.m_callbacks, docpos + 9u < full.len);
383  sink.insert("+MAP\n", docpos + 9u);
384  }
385  _push();
386  }
387 
388  /** @} */
389 
390 public:
391 
392  /** @name YAML scalar events */
393  /** @{ */
394 
395 
396  C4_ALWAYS_INLINE void set_key_scalar_plain(csubstr scalar)
397  {
398  _c4dbgpf("node[{}]: set key scalar plain: [{}]~~~{}~~~ ({})", m_curr->node_id, scalar.len, scalar, reinterpret_cast<void const*>(scalar.str));
399  _send_key_scalar_(scalar, ':');
400  _enable_(KEY|KEY_PLAIN);
401  }
402  C4_ALWAYS_INLINE void set_val_scalar_plain(csubstr scalar)
403  {
404  _c4dbgpf("node[{}]: set val scalar plain: [{}]~~~{}~~~ ({})", m_curr->node_id, scalar.len, scalar, reinterpret_cast<void const*>(scalar.str));
405  _send_val_scalar_(scalar, ':');
406  _enable_(VAL|VAL_PLAIN);
407  }
408 
409 
410  C4_ALWAYS_INLINE void set_key_scalar_dquoted(csubstr scalar)
411  {
412  _c4dbgpf("node[{}]: set key scalar dquot: [{}]~~~{}~~~ ({})", m_curr->node_id, scalar.len, scalar, reinterpret_cast<void const*>(scalar.str));
413  _send_key_scalar_(scalar, '"');
414  _enable_(KEY|KEY_DQUO);
415  }
416  C4_ALWAYS_INLINE void set_val_scalar_dquoted(csubstr scalar)
417  {
418  _c4dbgpf("node[{}]: set val scalar dquot: [{}]~~~{}~~~ ({})", m_curr->node_id, scalar.len, scalar, reinterpret_cast<void const*>(scalar.str));
419  _send_val_scalar_(scalar, '"');
420  _enable_(VAL|VAL_DQUO);
421  }
422 
423 
424  C4_ALWAYS_INLINE void set_key_scalar_squoted(csubstr scalar)
425  {
426  _c4dbgpf("node[{}]: set key scalar squot: [{}]~~~{}~~~ ({})", m_curr->node_id, scalar.len, scalar, reinterpret_cast<void const*>(scalar.str));
427  _send_key_scalar_(scalar, '\'');
428  _enable_(KEY|KEY_SQUO);
429  }
430  C4_ALWAYS_INLINE void set_val_scalar_squoted(csubstr scalar)
431  {
432  _c4dbgpf("node[{}]: set val scalar squot: [{}]~~~{}~~~ ({})", m_curr->node_id, scalar.len, scalar, reinterpret_cast<void const*>(scalar.str));
433  _send_val_scalar_(scalar, '\'');
434  _enable_(VAL|VAL_SQUO);
435  }
436 
437 
438  C4_ALWAYS_INLINE void set_key_scalar_literal(csubstr scalar)
439  {
440  _c4dbgpf("node[{}]: set key scalar literal: [{}]~~~{}~~~ ({})", m_curr->node_id, scalar.len, scalar, reinterpret_cast<void const*>(scalar.str));
441  _send_key_scalar_(scalar, '|');
442  _enable_(KEY|KEY_LITERAL);
443  }
444  C4_ALWAYS_INLINE void set_val_scalar_literal(csubstr scalar)
445  {
446  _c4dbgpf("node[{}]: set val scalar literal: [{}]~~~{}~~~ ({})", m_curr->node_id, scalar.len, scalar, reinterpret_cast<void const*>(scalar.str));
447  _send_val_scalar_(scalar, '|');
448  _enable_(VAL|VAL_LITERAL);
449  }
450 
451 
452  C4_ALWAYS_INLINE void set_key_scalar_folded(csubstr scalar)
453  {
454  _c4dbgpf("node[{}]: set key scalar folded: [{}]~~~{}~~~ ({})", m_curr->node_id, scalar.len, scalar, reinterpret_cast<void const*>(scalar.str));
455  _send_key_scalar_(scalar, '>');
456  _enable_(KEY|KEY_FOLDED);
457  }
458  C4_ALWAYS_INLINE void set_val_scalar_folded(csubstr scalar)
459  {
460  _c4dbgpf("node[{}]: set val scalar folded: [{}]~~~{}~~~ ({})", m_curr->node_id, scalar.len, scalar, reinterpret_cast<void const*>(scalar.str));
461  _send_val_scalar_(scalar, '>');
462  _enable_(VAL|VAL_FOLDED);
463  }
464 
465 
466  C4_ALWAYS_INLINE void mark_key_scalar_unfiltered()
467  {
468  C4_NOT_IMPLEMENTED();
469  }
470  C4_ALWAYS_INLINE void mark_val_scalar_unfiltered()
471  {
472  C4_NOT_IMPLEMENTED();
473  }
474 
475  /** @} */
476 
477 public:
478 
479  /** @name YAML anchor/reference events */
480  /** @{ */
481 
482  void set_key_anchor(csubstr anchor)
483  {
484  _c4dbgpf("node[{}]: set key anchor: [{}]~~~{}~~~", m_curr->node_id, anchor.len, anchor);
485  if(C4_UNLIKELY(_has_any_(KEYANCH)))
486  _RYML_CB_ERR_(m_stack.m_callbacks, "key cannot have both anchor and ref", m_curr->pos);
487  _RYML_CB_ASSERT(m_stack.m_callbacks, !anchor.begins_with('&'));
488  _enable_(KEYANCH);
489  m_curr->ev_data.m_key.anchor = anchor;
490  }
491  void set_val_anchor(csubstr anchor)
492  {
493  _c4dbgpf("node[{}]: set val anchor: [{}]~~~{}~~~", m_curr->node_id, anchor.len, anchor);
494  if(C4_UNLIKELY(_has_any_(VALREF)))
495  _RYML_CB_ERR_(m_stack.m_callbacks, "val cannot have both anchor and ref", m_curr->pos);
496  _RYML_CB_ASSERT(m_stack.m_callbacks, !anchor.begins_with('&'));
497  _enable_(VALANCH);
498  m_curr->ev_data.m_val.anchor = anchor;
499  }
500 
501  void set_key_ref(csubstr ref)
502  {
503  _c4dbgpf("node[{}]: set key ref: [{}]~~~{}~~~", m_curr->node_id, ref.len, ref);
504  if(C4_UNLIKELY(_has_any_(KEYANCH)))
505  _RYML_CB_ERR_(m_stack.m_callbacks, "key cannot have both anchor and ref", m_curr->pos);
506  _RYML_CB_ASSERT(m_stack.m_callbacks, ref.begins_with('*'));
507  _enable_(KEY|KEYREF);
508  _send_("=ALI ");
509  _send_(ref);
510  _send_('\n');
511  }
512  void set_val_ref(csubstr ref)
513  {
514  _c4dbgpf("node[{}]: set val ref: [{}]~~~{}~~~", m_curr->node_id, ref.len, ref);
515  if(C4_UNLIKELY(_has_any_(VALANCH)))
516  _RYML_CB_ERR_(m_stack.m_callbacks, "val cannot have both anchor and ref", m_curr->pos);
517  _RYML_CB_ASSERT(m_stack.m_callbacks, ref.begins_with('*'));
518  _enable_(VAL|VALREF);
519  _send_("=ALI ");
520  _send_(ref);
521  _send_('\n');
522  }
523 
524  /** @} */
525 
526 public:
527 
528  /** @name YAML tag events */
529  /** @{ */
530 
531  void set_key_tag(csubstr tag)
532  {
533  _c4dbgpf("node[{}]: set key tag: [{}]~~~{}~~~", m_curr->node_id, tag.len, tag);
534  _enable_(KEYTAG);
535  m_curr->ev_data.m_key.tag = _transform_directive(tag, &m_key_tag_buf);
536  }
537  void set_val_tag(csubstr tag)
538  {
539  _c4dbgpf("node[{}]: set val tag: [{}]~~~{}~~~", m_curr->node_id, tag.len, tag);
540  _enable_(VALTAG);
541  m_curr->ev_data.m_val.tag = _transform_directive(tag, &m_val_tag_buf);
542  }
543 
544  /** @} */
545 
546 public:
547 
548  /** @name YAML directive events */
549  /** @{ */
550 
551  void add_directive(csubstr directive)
552  {
553  _RYML_CB_ASSERT(m_stack.m_callbacks, directive.begins_with('%'));
554  if(directive.begins_with("%TAG"))
555  {
556  const id_type pos = _num_tag_directives();
557  if(C4_UNLIKELY(pos >= RYML_MAX_TAG_DIRECTIVES))
558  _RYML_CB_ERR_(m_stack.m_callbacks, "too many directives", m_curr->pos);
559  if(C4_UNLIKELY(!m_tag_directives[pos].create_from_str(directive)))
560  _RYML_CB_ERR_(m_stack.m_callbacks, "failed to add directive", m_curr->pos);
561  }
562  else if(directive.begins_with("%YAML"))
563  {
564  _c4dbgpf("%YAML directive! ignoring...: {}", directive);
565  if(C4_UNLIKELY(m_has_yaml_directive))
566  _RYML_CB_ERR_(m_stack.m_callbacks, "multiple yaml directives", m_curr->pos);
567  m_has_yaml_directive = true;
568  }
569  else
570  {
571  _c4dbgpf("unknown directive! ignoring... {}", directive);
572  }
573  }
574 
575  /** @} */
576 
577 public:
578 
579  /** @name YAML arena events */
580  /** @{ */
581 
582  substr alloc_arena(size_t len)
583  {
584  const size_t sz = m_arena.size();
585  csubstr prev = m_arena;
586  m_arena.resize(sz + len);
587  substr out = to_substr(m_arena).sub(sz);
588  substr curr = to_substr(m_arena);
589  if(curr.str != prev.str)
590  _stack_relocate_to_new_arena(prev, curr);
591  return out;
592  }
593 
594  substr alloc_arena(size_t len, substr *relocated)
595  {
596  csubstr prev = m_arena;
597  if(!prev.is_super(*relocated))
598  return alloc_arena(len);
599  substr out = alloc_arena(len);
600  substr curr = to_substr(m_arena);
601  if(curr.str != prev.str)
602  *relocated = _stack_relocate_to_new_arena(*relocated, prev, curr);
603  return out;
604  }
605 
606  /** @} */
607 
608 public:
609 
610  /** @cond dev */
611 
612  /** push a new parent, add a child to the new parent, and set the
613  * child as the current node */
614  void _push()
615  {
616  _stack_push();
617  _buf_ensure_(m_stack.size() + id_type(1));
618  _buf_().clear();
619  m_curr->ev_data = {};
620  _c4dbgpf("pushed! level={}", m_curr->level);
621  }
622 
623  /** end the current scope */
624  void _pop()
625  {
626  _buf_flush_to_(m_curr->level, m_parent->level);
627  _stack_pop();
628  }
629 
630  template<type_bits bits> C4_ALWAYS_INLINE void _enable__() noexcept
631  {
632  m_curr->ev_data.m_type.type = static_cast<NodeType_e>(m_curr->ev_data.m_type.type | bits);
633  }
634  template<type_bits bits> C4_ALWAYS_INLINE void _disable__() noexcept
635  {
636  m_curr->ev_data.m_type.type = static_cast<NodeType_e>(m_curr->ev_data.m_type.type & (~bits));
637  }
638  template<type_bits bits> C4_ALWAYS_INLINE bool _has_any__() const noexcept
639  {
640  return (m_curr->ev_data.m_type.type & bits) != 0;
641  }
642 
643  void _mark_parent_with_children_()
644  {
645  if(m_parent)
646  m_parent->has_children = true;
647  }
648 
649  EventSink& _buf_() noexcept
650  {
651  _RYML_CB_ASSERT(m_stack.m_callbacks, m_curr->level < m_val_buffers.size());
652  return m_val_buffers[m_curr->level];
653  }
654 
655  EventSink& _buf_(id_type level) noexcept
656  {
657  _RYML_CB_ASSERT(m_stack.m_callbacks, level < m_val_buffers.size());
658  return m_val_buffers[level];
659  }
660 
661  EventSink const& _buf_(id_type level) const noexcept
662  {
663  _RYML_CB_ASSERT(m_stack.m_callbacks, level < m_val_buffers.size());
664  return m_val_buffers[level];
665  }
666 
667  static void _buf_flush_to_(EventSink &C4_RESTRICT src, EventSink &C4_RESTRICT dst) noexcept
668  {
669  dst.append(src);
670  src.clear();
671  }
672 
673  void _buf_flush_to_(id_type level_src, id_type level_dst) noexcept
674  {
675  auto &src = _buf_(level_src);
676  auto &dst = _buf_(level_dst);
677  _buf_flush_to_(src, dst);
678  }
679 
680  void _buf_flush_() noexcept
681  {
682  _buf_flush_to_(_buf_(), *m_sink);
683  }
684 
685  void _buf_ensure_(id_type size_needed) noexcept
686  {
687  if(size_needed > m_val_buffers.size())
688  m_val_buffers.resize(size_needed);
689  }
690 
691  C4_ALWAYS_INLINE void _send_(csubstr s) noexcept { _buf_().append(s); }
692  C4_ALWAYS_INLINE void _send_(char c) noexcept { _buf_().append(c); }
693 
694  void _send_key_scalar_(csubstr scalar, char scalar_type_code)
695  {
696  _send_("=VAL");
697  _send_key_props_();
698  _send_(' ');
699  _send_(scalar_type_code);
700  append_escaped(&_buf_(), scalar);
701  _send_('\n');
702  }
703  void _send_val_scalar_(csubstr scalar, char scalar_type_code)
704  {
705  _send_("=VAL");
706  _send_val_props_();
707  _send_(' ');
708  _send_(scalar_type_code);
709  append_escaped(&_buf_(), scalar);
710  _send_('\n');
711  }
712 
713  void _send_key_props_()
714  {
716  {
717  _send_(" &");
718  _send_(m_curr->ev_data.m_key.anchor);
719  }
720  if(_has_any_(KEYTAG))
721  {
722  _send_tag_(m_curr->ev_data.m_key.tag);
723  }
724  m_curr->ev_data.m_key = {};
725  _disable_(KEYANCH|KEYREF|KEYTAG);
726  }
727  void _send_val_props_()
728  {
730  {
731  _send_(" &");
732  _send_(m_curr->ev_data.m_val.anchor);
733  }
734  if(m_curr->ev_data.m_type.type & VALTAG)
735  {
736  _send_tag_(m_curr->ev_data.m_val.tag);
737  }
738  m_curr->ev_data.m_val = {};
739  _disable_(VALANCH|VALREF|VALTAG);
740  }
741  void _send_tag_(csubstr tag)
742  {
743  _RYML_CB_ASSERT(m_stack.m_callbacks, !tag.empty());
744  if(tag.str[0] == '<')
745  {
746  _send_(' ');
747  _send_(tag);
748  }
749  else
750  {
751  _send_(" <");
752  _send_(tag);
753  _send_('>');
754  }
755  }
756 
757  void _clear_tag_directives_()
758  {
759  for(TagDirective &td : m_tag_directives)
760  td = {};
761  }
762  id_type _num_tag_directives() const
763  {
764  // this assumes we have a very small number of tag directives
765  for(id_type i = 0; i < RYML_MAX_TAG_DIRECTIVES; ++i)
766  if(m_tag_directives[i].handle.empty())
767  return i;
769  }
770  csubstr _transform_directive(csubstr tag, extra::string *output)
771  {
772  // lookup from the end. We want to find the first directive that
773  // matches the tag and has a target node id leq than the given
774  // node_id.
775  for(id_type i = RYML_MAX_TAG_DIRECTIVES-1; i != NONE; --i)
776  {
777  TagDirective const& td = m_tag_directives[i];
778  if(td.handle.empty())
779  continue;
780  if(tag.begins_with(td.handle))
781  {
782  bool retry = false;
783  again1:
784  size_t len = td.transform(tag, *output, m_stack.m_callbacks);
785  if(len == 0)
786  {
787  if(tag.begins_with("!<"))
788  return tag.sub(1);
789  return tag;
790  }
791  if(len > output->size())
792  {
793  _RYML_CB_CHECK(m_stack.m_callbacks, !retry);
794  retry = true;
795  output->resize(len);
796  output->resize(output->capacity());
797  goto again1;
798  }
799  return csubstr(*output).first(len);
800  }
801  }
802  if(tag.begins_with('!'))
803  {
804  if(is_custom_tag(tag))
805  {
806  _RYML_CB_ERR_(m_stack.m_callbacks, "tag not found", m_curr->pos);
807  }
808  }
809  bool retry = false;
810  again2:
811  csubstr result = normalize_tag_long(tag, *output);
812  if(!result.str)
813  {
814  _RYML_CB_CHECK(m_stack.m_callbacks, !retry);
815  retry = true;
816  output->resize(result.len);
817  output->resize(output->capacity());
818  goto again2;
819  }
820  return result;
821  }
822 
823  #undef _enable_
824  #undef _disable_
825  #undef _has_any_
826 
827  /** @endcond */
828 };
829 
830 /** @} */
831 
832 } // namespace yml
833 } // namespace c4
834 
835 C4_SUPPRESS_WARNING_GCC_POP
836 
837 #endif /* _C4_YML_EVENT_HANDLER_YAMLSTD_HPP_ */
#define _has_any_(bits)
Callbacks const & get_callbacks()
get the global callbacks
Definition: common.cpp:118
void append_escaped(extra::string *s, csubstr val)
NodeType_e
a bit mask for marking node types and styles
Definition: node_type.hpp:30
@ VALANCH
the val has an &anchor
Definition: node_type.hpp:42
@ KEY_DQUO
mark key scalar as double quoted "
Definition: node_type.hpp:63
@ VALREF
a *reference: the val references an &anchor
Definition: node_type.hpp:40
@ MAP
a map: a parent of KEYVAL/KEYSEQ/KEYMAP nodes
Definition: node_type.hpp:35
@ KEY
is member of a map, must have non-empty key
Definition: node_type.hpp:33
@ VAL_FOLDED
mark val scalar as multiline, block folded >
Definition: node_type.hpp:60
@ VAL_STYLE
mask of all the scalar styles for val (not container styles!)
Definition: node_type.hpp:87
@ KEYTAG
the key has a tag
Definition: node_type.hpp:43
@ FLOW_SL
mark container with single-line flow style (seqs as '[val1,val2], maps as '{key: val,...
Definition: node_type.hpp:54
@ 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 '
Definition: node_type.hpp:62
@ VAL_PLAIN
mark val scalar as plain scalar (unquoted, even when multiline)
Definition: node_type.hpp:66
@ KEYREF
a *reference: the key references an &anchor
Definition: node_type.hpp:39
@ BLOCK
mark container with block style (seqs as '- val ', maps as 'key: val')
Definition: node_type.hpp:56
@ KEYANCH
the key has an &anchor
Definition: node_type.hpp:41
@ VAL_DQUO
mark val scalar as double quoted "
Definition: node_type.hpp:64
@ KEY_SQUO
mark key scalar as single quoted '
Definition: node_type.hpp:61
@ VAL_LITERAL
mark val scalar as multiline, block literal |
Definition: node_type.hpp:58
@ KEY_LITERAL
mark key scalar as multiline, block literal |
Definition: node_type.hpp:57
@ KEY_PLAIN
mark key scalar as plain scalar (unquoted, even when multiline)
Definition: node_type.hpp:65
@ _VALMASK
Definition: node_type.hpp:96
@ KEY_FOLDED
mark key scalar as multiline, block folded >
Definition: node_type.hpp:59
@ DOC
a document
Definition: node_type.hpp:37
substr to_substr(substr s) noexcept
neutral version for use in generic code
Definition: substr.hpp:2187
bool is_custom_tag(csubstr tag)
Definition: tag.cpp:9
csubstr normalize_tag_long(csubstr tag)
Definition: tag.cpp:31
#define RYML_MAX_TAG_DIRECTIVES
the maximum number of tag directives in a Tree
Definition: tag.hpp:19
void(*)(void *, csubstr prev_arena, substr next_arena) pfn_relocate_arena
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:252
@ npos
a null string position
Definition: common.hpp:266
@ RTOP
reading at top level
@ RUNK
reading unknown state (when starting): must determine whether scalar, map or seq
@ NONE
an index to none
Definition: common.hpp:259
Definition: common.cpp:12
a c-style callbacks class.
Definition: common.hpp:375
Use this class a base of implementations of event handler to simplify the stack logic.
The stack state needed specifically by EventHandlerYamlStd.
The event handler producing standard YAML events as used in the YAML test suite.
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.
substr alloc_arena(size_t len, substr *relocated)
void begin_doc()
implicit doc start (without —)
EventHandlerYamlStd(EventSink *sink, Callbacks const &cb)
void end_doc()
implicit doc end (without ...)
void begin_doc_expl()
explicit doc start, with —
void end_doc_expl()
explicit doc end, with ...
void start_parse(const char *filename, detail::pfn_relocate_arena relocate_arena, void *relocate_arena_data)
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...
contains the data for each YAML node.
Definition: tree.hpp:222
size_t transform(csubstr tag, substr output, Callbacks const &callbacks) const
Definition: tag.cpp:243