rapidyaml  0.8.0
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_empty() noexcept
397  {
398  _c4dbgpf("node[{}]: set key scalar plain as empty", m_curr->node_id);
399  _send_key_scalar_({}, ':');
400  _enable_(KEY|KEY_PLAIN|KEYNIL);
401  }
402  C4_ALWAYS_INLINE void set_val_scalar_plain_empty() noexcept
403  {
404  _c4dbgpf("node[{}]: set val scalar plain as empty", m_curr->node_id);
405  _send_val_scalar_({}, ':');
406  _enable_(VAL|VAL_PLAIN|VALNIL);
407  }
408 
409  C4_ALWAYS_INLINE void set_key_scalar_plain(csubstr scalar)
410  {
411  _c4dbgpf("node[{}]: set key scalar plain: [{}]~~~{}~~~", m_curr->node_id, scalar.len, scalar);
412  _send_key_scalar_(scalar, ':');
413  _enable_(KEY|KEY_PLAIN);
414  }
415  C4_ALWAYS_INLINE void set_val_scalar_plain(csubstr scalar)
416  {
417  _c4dbgpf("node[{}]: set val scalar plain: [{}]~~~{}~~~", m_curr->node_id, scalar.len, scalar);
418  _send_val_scalar_(scalar, ':');
419  _enable_(VAL|VAL_PLAIN);
420  }
421 
422 
423  C4_ALWAYS_INLINE void set_key_scalar_dquoted(csubstr scalar)
424  {
425  _c4dbgpf("node[{}]: set key scalar dquot: [{}]~~~{}~~~", m_curr->node_id, scalar.len, scalar);
426  _send_key_scalar_(scalar, '"');
427  _enable_(KEY|KEY_DQUO);
428  }
429  C4_ALWAYS_INLINE void set_val_scalar_dquoted(csubstr scalar)
430  {
431  _c4dbgpf("node[{}]: set val scalar dquot: [{}]~~~{}~~~", m_curr->node_id, scalar.len, scalar);
432  _send_val_scalar_(scalar, '"');
433  _enable_(VAL|VAL_DQUO);
434  }
435 
436 
437  C4_ALWAYS_INLINE void set_key_scalar_squoted(csubstr scalar)
438  {
439  _c4dbgpf("node[{}]: set key scalar squot: [{}]~~~{}~~~", m_curr->node_id, scalar.len, scalar);
440  _send_key_scalar_(scalar, '\'');
441  _enable_(KEY|KEY_SQUO);
442  }
443  C4_ALWAYS_INLINE void set_val_scalar_squoted(csubstr scalar)
444  {
445  _c4dbgpf("node[{}]: set val scalar squot: [{}]~~~{}~~~", m_curr->node_id, scalar.len, scalar);
446  _send_val_scalar_(scalar, '\'');
447  _enable_(VAL|VAL_SQUO);
448  }
449 
450 
451  C4_ALWAYS_INLINE void set_key_scalar_literal(csubstr scalar)
452  {
453  _c4dbgpf("node[{}]: set key scalar literal: [{}]~~~{}~~~", m_curr->node_id, scalar.len, scalar);
454  _send_key_scalar_(scalar, '|');
455  _enable_(KEY|KEY_LITERAL);
456  }
457  C4_ALWAYS_INLINE void set_val_scalar_literal(csubstr scalar)
458  {
459  _c4dbgpf("node[{}]: set val scalar literal: [{}]~~~{}~~~", m_curr->node_id, scalar.len, scalar);
460  _send_val_scalar_(scalar, '|');
461  _enable_(VAL|VAL_LITERAL);
462  }
463 
464 
465  C4_ALWAYS_INLINE void set_key_scalar_folded(csubstr scalar)
466  {
467  _c4dbgpf("node[{}]: set key scalar folded: [{}]~~~{}~~~", m_curr->node_id, scalar.len, scalar);
468  _send_key_scalar_(scalar, '>');
469  _enable_(KEY|KEY_FOLDED);
470  }
471  C4_ALWAYS_INLINE void set_val_scalar_folded(csubstr scalar)
472  {
473  _c4dbgpf("node[{}]: set val scalar folded: [{}]~~~{}~~~", m_curr->node_id, scalar.len, scalar);
474  _send_val_scalar_(scalar, '>');
475  _enable_(VAL|VAL_FOLDED);
476  }
477 
478 
479  C4_ALWAYS_INLINE void mark_key_scalar_unfiltered()
480  {
481  C4_NOT_IMPLEMENTED();
482  }
483  C4_ALWAYS_INLINE void mark_val_scalar_unfiltered()
484  {
485  C4_NOT_IMPLEMENTED();
486  }
487 
488  /** @} */
489 
490 public:
491 
492  /** @name YAML anchor/reference events */
493  /** @{ */
494 
495  void set_key_anchor(csubstr anchor)
496  {
497  _c4dbgpf("node[{}]: set key anchor: [{}]~~~{}~~~", m_curr->node_id, anchor.len, anchor);
498  if(C4_UNLIKELY(_has_any_(KEYANCH)))
499  _RYML_CB_ERR_(m_stack.m_callbacks, "key cannot have both anchor and ref", m_curr->pos);
500  _RYML_CB_ASSERT(m_stack.m_callbacks, !anchor.begins_with('&'));
501  _enable_(KEYANCH);
502  m_curr->ev_data.m_key.anchor = anchor;
503  }
504  void set_val_anchor(csubstr anchor)
505  {
506  _c4dbgpf("node[{}]: set val anchor: [{}]~~~{}~~~", m_curr->node_id, anchor.len, anchor);
507  if(C4_UNLIKELY(_has_any_(VALREF)))
508  _RYML_CB_ERR_(m_stack.m_callbacks, "val cannot have both anchor and ref", m_curr->pos);
509  _RYML_CB_ASSERT(m_stack.m_callbacks, !anchor.begins_with('&'));
510  _enable_(VALANCH);
511  m_curr->ev_data.m_val.anchor = anchor;
512  }
513 
514  void set_key_ref(csubstr ref)
515  {
516  _c4dbgpf("node[{}]: set key ref: [{}]~~~{}~~~", m_curr->node_id, ref.len, ref);
517  if(C4_UNLIKELY(_has_any_(KEYANCH)))
518  _RYML_CB_ERR_(m_stack.m_callbacks, "key cannot have both anchor and ref", m_curr->pos);
519  _RYML_CB_ASSERT(m_stack.m_callbacks, ref.begins_with('*'));
520  _enable_(KEY|KEYREF);
521  _send_("=ALI ");
522  _send_(ref);
523  _send_('\n');
524  }
525  void set_val_ref(csubstr ref)
526  {
527  _c4dbgpf("node[{}]: set val ref: [{}]~~~{}~~~", m_curr->node_id, ref.len, ref);
528  if(C4_UNLIKELY(_has_any_(VALANCH)))
529  _RYML_CB_ERR_(m_stack.m_callbacks, "val cannot have both anchor and ref", m_curr->pos);
530  _RYML_CB_ASSERT(m_stack.m_callbacks, ref.begins_with('*'));
531  _enable_(VAL|VALREF);
532  _send_("=ALI ");
533  _send_(ref);
534  _send_('\n');
535  }
536 
537  /** @} */
538 
539 public:
540 
541  /** @name YAML tag events */
542  /** @{ */
543 
544  void set_key_tag(csubstr tag)
545  {
546  _c4dbgpf("node[{}]: set key tag: [{}]~~~{}~~~", m_curr->node_id, tag.len, tag);
547  _enable_(KEYTAG);
548  m_curr->ev_data.m_key.tag = _transform_directive(tag, &m_key_tag_buf);
549  }
550  void set_val_tag(csubstr tag)
551  {
552  _c4dbgpf("node[{}]: set val tag: [{}]~~~{}~~~", m_curr->node_id, tag.len, tag);
553  _enable_(VALTAG);
554  m_curr->ev_data.m_val.tag = _transform_directive(tag, &m_val_tag_buf);
555  }
556 
557  /** @} */
558 
559 public:
560 
561  /** @name YAML directive events */
562  /** @{ */
563 
564  void add_directive(csubstr directive)
565  {
566  _RYML_CB_ASSERT(m_stack.m_callbacks, directive.begins_with('%'));
567  if(directive.begins_with("%TAG"))
568  {
569  const id_type pos = _num_tag_directives();
570  if(C4_UNLIKELY(pos >= RYML_MAX_TAG_DIRECTIVES))
571  _RYML_CB_ERR_(m_stack.m_callbacks, "too many directives", m_curr->pos);
572  if(C4_UNLIKELY(!m_tag_directives[pos].create_from_str(directive)))
573  _RYML_CB_ERR_(m_stack.m_callbacks, "failed to add directive", m_curr->pos);
574  }
575  else if(directive.begins_with("%YAML"))
576  {
577  _c4dbgpf("%YAML directive! ignoring...: {}", directive);
578  if(C4_UNLIKELY(m_has_yaml_directive))
579  _RYML_CB_ERR_(m_stack.m_callbacks, "multiple yaml directives", m_curr->pos);
580  m_has_yaml_directive = true;
581  }
582  else
583  {
584  _c4dbgpf("unknown directive! ignoring... {}", directive);
585  }
586  }
587 
588  /** @} */
589 
590 public:
591 
592  /** @name YAML arena events */
593  /** @{ */
594 
595  substr alloc_arena(size_t len)
596  {
597  const size_t sz = m_arena.size();
598  csubstr prev = m_arena;
599  m_arena.resize(sz + len);
600  substr out = to_substr(m_arena).sub(sz);
601  substr curr = to_substr(m_arena);
602  if(curr.str != prev.str)
603  _stack_relocate_to_new_arena(prev, curr);
604  return out;
605  }
606 
607  substr alloc_arena(size_t len, substr *relocated)
608  {
609  csubstr prev = m_arena;
610  if(!prev.is_super(*relocated))
611  return alloc_arena(len);
612  substr out = alloc_arena(len);
613  substr curr = to_substr(m_arena);
614  if(curr.str != prev.str)
615  *relocated = _stack_relocate_to_new_arena(*relocated, prev, curr);
616  return out;
617  }
618 
619  /** @} */
620 
621 public:
622 
623  /** @cond dev */
624 
625  /** push a new parent, add a child to the new parent, and set the
626  * child as the current node */
627  void _push()
628  {
629  _stack_push();
630  _buf_ensure_(m_stack.size() + id_type(1));
631  _buf_().clear();
632  m_curr->ev_data = {};
633  _c4dbgpf("pushed! level={}", m_curr->level);
634  }
635 
636  /** end the current scope */
637  void _pop()
638  {
639  _buf_flush_to_(m_curr->level, m_parent->level);
640  _stack_pop();
641  }
642 
643  template<type_bits bits> C4_ALWAYS_INLINE void _enable__() noexcept
644  {
645  m_curr->ev_data.m_type.type = static_cast<NodeType_e>(m_curr->ev_data.m_type.type | bits);
646  }
647  template<type_bits bits> C4_ALWAYS_INLINE void _disable__() noexcept
648  {
649  m_curr->ev_data.m_type.type = static_cast<NodeType_e>(m_curr->ev_data.m_type.type & (~bits));
650  }
651  template<type_bits bits> C4_ALWAYS_INLINE bool _has_any__() const noexcept
652  {
653  return (m_curr->ev_data.m_type.type & bits) != 0;
654  }
655 
656  void _mark_parent_with_children_()
657  {
658  if(m_parent)
659  m_parent->has_children = true;
660  }
661 
662  EventSink& _buf_() noexcept
663  {
664  _RYML_CB_ASSERT(m_stack.m_callbacks, m_curr->level < m_val_buffers.size());
665  return m_val_buffers[m_curr->level];
666  }
667 
668  EventSink& _buf_(id_type level) noexcept
669  {
670  _RYML_CB_ASSERT(m_stack.m_callbacks, level < m_val_buffers.size());
671  return m_val_buffers[level];
672  }
673 
674  EventSink const& _buf_(id_type level) const noexcept
675  {
676  _RYML_CB_ASSERT(m_stack.m_callbacks, level < m_val_buffers.size());
677  return m_val_buffers[level];
678  }
679 
680  static void _buf_flush_to_(EventSink &C4_RESTRICT src, EventSink &C4_RESTRICT dst) noexcept
681  {
682  dst.append(src);
683  src.clear();
684  }
685 
686  void _buf_flush_to_(id_type level_src, id_type level_dst) noexcept
687  {
688  auto &src = _buf_(level_src);
689  auto &dst = _buf_(level_dst);
690  _buf_flush_to_(src, dst);
691  }
692 
693  void _buf_flush_() noexcept
694  {
695  _buf_flush_to_(_buf_(), *m_sink);
696  }
697 
698  void _buf_ensure_(id_type size_needed) noexcept
699  {
700  if(size_needed > m_val_buffers.size())
701  m_val_buffers.resize(size_needed);
702  }
703 
704  C4_ALWAYS_INLINE void _send_(csubstr s) noexcept { _buf_().append(s); }
705  C4_ALWAYS_INLINE void _send_(char c) noexcept { _buf_().append(c); }
706 
707  void _send_key_scalar_(csubstr scalar, char scalar_type_code)
708  {
709  _send_("=VAL");
710  _send_key_props_();
711  _send_(' ');
712  _send_(scalar_type_code);
713  append_escaped(&_buf_(), scalar);
714  _send_('\n');
715  }
716  void _send_val_scalar_(csubstr scalar, char scalar_type_code)
717  {
718  _send_("=VAL");
719  _send_val_props_();
720  _send_(' ');
721  _send_(scalar_type_code);
722  append_escaped(&_buf_(), scalar);
723  _send_('\n');
724  }
725 
726  void _send_key_props_()
727  {
729  {
730  _send_(" &");
731  _send_(m_curr->ev_data.m_key.anchor);
732  }
733  if(_has_any_(KEYTAG))
734  {
735  _send_tag_(m_curr->ev_data.m_key.tag);
736  }
737  m_curr->ev_data.m_key = {};
738  _disable_(KEYANCH|KEYREF|KEYTAG);
739  }
740  void _send_val_props_()
741  {
743  {
744  _send_(" &");
745  _send_(m_curr->ev_data.m_val.anchor);
746  }
747  if(m_curr->ev_data.m_type.type & VALTAG)
748  {
749  _send_tag_(m_curr->ev_data.m_val.tag);
750  }
751  m_curr->ev_data.m_val = {};
752  _disable_(VALANCH|VALREF|VALTAG);
753  }
754  void _send_tag_(csubstr tag)
755  {
756  _RYML_CB_ASSERT(m_stack.m_callbacks, !tag.empty());
757  if(tag.str[0] == '<')
758  {
759  _send_(' ');
760  _send_(tag);
761  }
762  else
763  {
764  _send_(" <");
765  _send_(tag);
766  _send_('>');
767  }
768  }
769 
770  void _clear_tag_directives_()
771  {
772  for(TagDirective &td : m_tag_directives)
773  td = {};
774  }
775  id_type _num_tag_directives() const
776  {
777  // this assumes we have a very small number of tag directives
778  for(id_type i = 0; i < RYML_MAX_TAG_DIRECTIVES; ++i)
779  if(m_tag_directives[i].handle.empty())
780  return i;
782  }
783  csubstr _transform_directive(csubstr tag, extra::string *output)
784  {
785  // lookup from the end. We want to find the first directive that
786  // matches the tag and has a target node id leq than the given
787  // node_id.
788  for(id_type i = RYML_MAX_TAG_DIRECTIVES-1; i != NONE; --i)
789  {
790  TagDirective const& td = m_tag_directives[i];
791  if(td.handle.empty())
792  continue;
793  if(tag.begins_with(td.handle))
794  {
795  bool retry = false;
796  again1:
797  size_t len = td.transform(tag, *output, m_stack.m_callbacks);
798  if(len == 0)
799  {
800  if(tag.begins_with("!<"))
801  return tag.sub(1);
802  return tag;
803  }
804  if(len > output->size())
805  {
806  _RYML_CB_CHECK(m_stack.m_callbacks, !retry);
807  retry = true;
808  output->resize(len);
809  output->resize(output->capacity());
810  goto again1;
811  }
812  return csubstr(*output).first(len);
813  }
814  }
815  if(tag.begins_with('!'))
816  {
817  if(is_custom_tag(tag))
818  {
819  _RYML_CB_ERR_(m_stack.m_callbacks, "tag not found", m_curr->pos);
820  }
821  }
822  bool retry = false;
823  again2:
824  csubstr result = normalize_tag_long(tag, *output);
825  if(!result.str)
826  {
827  _RYML_CB_CHECK(m_stack.m_callbacks, !retry);
828  retry = true;
829  output->resize(result.len);
830  output->resize(output->capacity());
831  goto again2;
832  }
833  return result;
834  }
835 
836  #undef _enable_
837  #undef _disable_
838  #undef _has_any_
839 
840  /** @endcond */
841 };
842 
843 /** @} */
844 
845 } // namespace yml
846 } // namespace c4
847 
848 C4_SUPPRESS_WARNING_GCC_POP
849 
850 #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:65
@ 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
is member of a map
Definition: node_type.hpp:33
@ VAL_FOLDED
mark val scalar as multiline, block folded >
Definition: node_type.hpp:62
@ VAL_STYLE
mask of all the scalar styles for val (not container styles!)
Definition: node_type.hpp:89
@ 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: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 '
Definition: node_type.hpp:64
@ VAL_PLAIN
mark val scalar as plain scalar (unquoted, even when multiline)
Definition: node_type.hpp:68
@ 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:58
@ KEYANCH
the key has an &anchor
Definition: node_type.hpp:41
@ VAL_DQUO
mark val scalar as double quoted "
Definition: node_type.hpp:66
@ KEY_SQUO
mark key scalar as single quoted '
Definition: node_type.hpp:63
@ VAL_LITERAL
mark val scalar as multiline, block literal |
Definition: node_type.hpp:60
@ KEY_LITERAL
mark key scalar as multiline, block literal |
Definition: node_type.hpp:59
@ KEY_PLAIN
mark key scalar as plain scalar (unquoted, even when multiline)
Definition: node_type.hpp:67
@ _VALMASK
Definition: node_type.hpp:98
@ KEY_FOLDED
mark key scalar as multiline, block folded >
Definition: node_type.hpp:61
@ 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
substr to_substr(substr s) noexcept
neutral version for use in generic code
Definition: substr.hpp:2184
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:253
@ npos
a null string position
Definition: common.hpp:267
@ 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:260
Definition: common.cpp:12
a c-style callbacks class.
Definition: common.hpp:376
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:181
size_t transform(csubstr tag, substr output, Callbacks const &callbacks) const
Definition: tag.cpp:243