1#ifndef C4_YML_EMITTER_DEF_HPP_
2#define C4_YML_EMITTER_DEF_HPP_
6#ifndef C4_YML_EMITTER_HPP_
9#ifndef C4_YML_TREE_HPP_
12#ifndef C4_YML_SCALAR_STYLE_HPP_
15#ifndef C4_YML_DETAIL_DBGPRINT_HPP_
16#include "c4/yml/detail/dbgprint.hpp"
18#ifndef C4_YML_ERROR_HPP_
23C4_SUPPRESS_WARNING_GCC_CLANG_WITH_PUSH(
"-Wold-style-cast")
24C4_SUPPRESS_WARNING_GCC(
"-Wuseless-cast")
51 if(!tree || tree->
empty())
55 RYML_CHECK_VISIT_CB_(tree->
callbacks(), id < tree->capacity(), tree,
id);
64 else if(type == EMIT_JSON)
67 RYML_ERR_BASIC_CB_(m_tree->callbacks(),
"unknown emit type");
87void Emitter<Writer>::emit_yaml_(
id_type id)
89 const NodeType ty = m_tree->type(
id);
92 const bool has_parent = !m_tree->is_root(
id);
93 const bool emit_key = has_parent && ty.
has_key() && m_opts.emit_nonroot_key();
94 const bool emit_dash = has_parent && !ty.
has_key() && !ty.
is_doc() && m_opts.emit_nonroot_dash();
95 RYML_ASSERT_VISIT_CB_(m_tree->m_callbacks, !(emit_key && emit_dash), m_tree,
id);
100 blck_map_open_entry_(
id);
105 blck_seq_open_entry_(
id);
116 RYML_ASSERT_VISIT_CB_(m_tree->m_callbacks, m_ilevel == 0, m_tree,
id);
121 RYML_ASSERT_VISIT_CB_(m_tree->m_callbacks, m_ilevel == 0, m_tree,
id);
126 visit_blck_container_(
id);
137 blck_close_entry_(
id);
142 blck_close_entry_(
id);
146 top_close_entry_(
id);
153 else if(m_tree->is_root(
id)
154 || emit_dash || emit_key
158 write_pws_and_pend_(PWS_NONE_);
165template<
class Writer>
166void Emitter<Writer>::visit_stream_(id_type
id)
168 auto write_tag_directives = [
this](
const id_type next_node){
169 const id_type doc = m_tree->ancestor_doc(next_node);
170 const TagDirectiveRange tagds = m_tree->m_tag_directives.lookup_range(doc);
171 if(tagds.e != tagds.b)
173 const id_type parent = m_tree->parent(next_node);
174 if(next_node != m_tree->first_child(parent))
176 write_pws_and_pend_(PWS_NEWL_);
180 for(TagDirective
const& td : tagds)
182 write_pws_and_pend_(PWS_NONE_);
190 const id_type first_child = m_tree->first_child(
id);
191 if(first_child != NONE)
192 write_tag_directives(first_child);
194 for(id_type child = first_child; child !=
NONE; child = m_tree->next_sibling(child))
196 NodeType ty = m_tree->type(child);
198 write_pws_and_pend_(PWS_NONE_);
199 top_open_entry_(child);
201 top_close_entry_(child);
204 if(ty.m_bits & VALNIL)
207 else if(ty.is_container())
212 if(m_tree->next_sibling(child) != NONE)
214 write_tag_directives(m_tree->next_sibling(child));
223template<
class Writer>
224void Emitter<Writer>::visit_blck_container_(id_type
id)
226 NodeType ty = m_tree->type(
id);
227 if(!(ty.m_bits & CONTAINER_STYLE))
228 ty.m_bits |= (m_tree->empty(
id) ? FLOW_SL : BLOCK);
229 write_pws_and_pend_(PWS_NONE_);
232 else if(ty.is_flow_mlx())
238template<
class Writer>
239void Emitter<Writer>::visit_flow_container_(id_type
id)
241 NodeType ty = m_tree->type(
id);
242 if(!(ty.m_bits & CONTAINER_STYLE))
244 write_pws_and_pend_(PWS_NONE_);
254template<
class Writer>
255void Emitter<Writer>::visit_doc_val_(id_type
id)
259 NodeType ty = m_tree->type(
id);
260 const csubstr val = m_tree->val(
id);
262 const bool is_ambiguous = ((ty.m_bits &
VAL_PLAIN) || !val_style)
263 && (val.begins_with(
"...") || val.begins_with(
"---"));
267 if(m_pws != PWS_NONE_)
272 write_pws_and_pend_(PWS_NONE_);
273 if(m_tree->is_val_ref(
id))
281 blck_write_scalar_(val, val_style);
292template<
class Writer>
293void Emitter<Writer>::visit_doc_(id_type
id)
295 const NodeType ty = m_tree->type(
id);
296 RYML_ASSERT_VISIT_CB_(m_tree->m_callbacks, ty.is_doc(), m_tree,
id);
297 RYML_ASSERT_VISIT_CB_(m_tree->m_callbacks, !ty.has_key(), m_tree,
id);
298 if(ty.is_container())
300 visit_blck_container_(
id);
312template<
class Writer>
313void Emitter<Writer>::top_open_entry_(id_type node)
315 NodeType ty = m_tree->type(node);
316 if(ty.is_doc() && !m_tree->is_root(node))
321 if(ty.has_val_anchor())
323 write_pws_and_pend_(PWS_SPACE_);
325 write_(m_tree->val_anchor(node));
329 write_pws_and_pend_(PWS_SPACE_);
330 write_tag_(m_tree->val_tag(node));
332 if(m_pws == PWS_SPACE_)
336 if(ty.is_val_plain() && !m_tree->val(node).len)
341 RYML_ASSERT_VISIT_CB_(m_tree->callbacks(), ty.is_container(), m_tree, node);
351template<
class Writer>
352void Emitter<Writer>::top_close_entry_(id_type node)
354 NodeType ty = m_tree->type(node);
355 if(ty.is_val() && !(ty.m_bits & VALNIL))
364template<
class Writer>
365void Emitter<Writer>::flow_seq_open_entry_(id_type node)
367 NodeType ty = m_tree->type(node);
368 write_pws_and_pend_(PWS_NONE_);
369 if(ty.m_bits & VALANCH)
371 write_pws_and_pend_(PWS_SPACE_);
373 write_(m_tree->val_anchor(node));
375 if(ty.m_bits & VALTAG)
377 write_pws_and_pend_(PWS_SPACE_);
378 write_tag_(m_tree->val_tag(node));
385template<
class Writer>
386void Emitter<Writer>::flow_map_open_entry_(id_type node)
388 NodeType ty = m_tree->type(node);
389 write_pws_and_pend_(PWS_NONE_);
390 RYML_ASSERT_VISIT_CB_(m_tree->callbacks(), ty.has_key(), m_tree, node);
391 if(ty.m_bits & KEYANCH)
393 write_pws_and_pend_(PWS_SPACE_);
395 write_(m_tree->key_anchor(node));
397 if(ty.m_bits & KEYTAG)
399 write_pws_and_pend_(PWS_SPACE_);
400 write_tag_(m_tree->key_tag(node));
402 if(ty.m_bits & KEYREF)
404 write_pws_and_pend_(PWS_SPACE_);
405 write_ref_(m_tree->key(node));
409 write_pws_and_pend_(PWS_NONE_);
410 csubstr key = m_tree->key(node);
411 if(!(ty.m_bits & detail::styles_flow_key_))
413 flow_write_scalar_(key, ty.m_bits & detail::styles_flow_key_);
415 write_pws_and_pend_(PWS_SPACE_);
417 if(ty.m_bits & VALANCH)
419 write_pws_and_pend_(PWS_SPACE_);
421 write_(m_tree->val_anchor(node));
423 if(ty.m_bits & VALTAG)
425 write_pws_and_pend_(PWS_SPACE_);
426 write_tag_(m_tree->val_tag(node));
433template<
class Writer>
434C4_NODISCARD
bool Emitter<Writer>::maybe_start_flow_pws_ml_(id_type node)
noexcept
436 RYML_ASSERT_VISIT_CB_(m_tree->callbacks(), m_tree->type(node) & (FLOW_ML1|FLOW_MLN), m_tree, node);
437 if(m_flow_pws.active)
439 NodeType ty = m_tree->type(node);
440 if(m_opts.force_flow_spc())
442 m_flow_pws.start(ty, m_opts.max_cols());
446template<
class Writer>
447C4_NODISCARD
typename Emitter<Writer>::flow_pws Emitter<Writer>::setup_flow_pws_sl_(id_type node)
noexcept
450 if(m_flow_pws.active)
456 NodeType ty = m_tree->type(node);
457 if(m_opts.force_flow_spc())
464template<
class Writer>
465void Emitter<Writer>::flow_pws::start(NodeType ty,
size_t max_cols_)
noexcept
468 pend_after_comma = (ty.m_bits &
FLOW_SPC) ? PWS_SPACE_ : PWS_NONE_;
469 if(ty.m_bits & FLOW_MLN)
471 max_cols_ = max_cols_ >= 2 ? max_cols_ : 2;
473 max_cols = max_cols_ - 1 - pend_after_comma;
475 static_assert((size_t)PWS_NONE_ == 0 && (size_t)PWS_SPACE_ == 1,
"invalid assumptions");
478 else if(ty.m_bits & FLOW_ML1)
480 pend_after_comma = PWS_NEWL_;
484template<
class Writer>
485void Emitter<Writer>::flow_close_entry_sl_(id_type node, id_type last_sibling, Pws_e pend_after)
487 if(node != last_sibling)
489 write_pws_and_pend_(pend_after);
494template<
class Writer>
495void Emitter<Writer>::flow_close_entry_ml_(id_type node, id_type last_sibling, Pws_e pend_after)
497 if(node != last_sibling)
499 write_pws_and_pend_(pend_after);
511template<
class Writer>
512void Emitter<Writer>::blck_seq_open_entry_(id_type node)
514 NodeType ty = m_tree->type(node);
515 write_pws_and_pend_(PWS_NONE_);
516 write_pws_and_pend_(PWS_SPACE_);
518 bool has_tag_or_anchor =
false;
519 if(ty.m_bits & VALANCH)
521 has_tag_or_anchor =
true;
522 write_pws_and_pend_(PWS_SPACE_);
524 write_(m_tree->val_anchor(node));
526 if(ty.m_bits & VALTAG)
528 has_tag_or_anchor =
true;
529 write_pws_and_pend_(PWS_SPACE_);
530 write_tag_(m_tree->val_tag(node));
532 if(has_tag_or_anchor && ty.is_container())
534 if(!(ty.m_bits & CONTAINER_STYLE))
536 if((ty.m_bits & BLOCK) && m_tree->has_children(node))
544template<
class Writer>
545void Emitter<Writer>::blck_map_open_entry_(id_type node)
547 NodeType ty = m_tree->type(node);
548 RYML_ASSERT_VISIT_CB_(m_tree->callbacks(), ty.has_key(), m_tree, node);
549 csubstr key = m_tree->key(node);
550 if(!(ty.m_bits & (KEY_STYLE|KEYREF)))
552 write_pws_and_pend_(PWS_NONE_);
553 if(ty.m_bits & KEYANCH)
555 write_pws_and_pend_(PWS_SPACE_);
557 write_(m_tree->key_anchor(node));
559 if(ty.m_bits & KEYTAG)
561 write_pws_and_pend_(PWS_SPACE_);
562 write_tag_(m_tree->key_tag(node));
564 if(ty.m_bits & KEYREF)
566 write_pws_and_pend_(PWS_SPACE_);
571 write_pws_and_pend_(PWS_NONE_);
572 const type_bits use_qmrk = ty.m_bits & detail::styles_block_key_;
575 blck_write_scalar_(key, ty.m_bits & KEY_STYLE);
580 blck_write_scalar_(key, ty.m_bits & KEY_STYLE);
584 write_pws_and_pend_(PWS_SPACE_);
586 if(ty.m_bits & VALANCH)
588 write_pws_and_pend_(PWS_SPACE_);
590 write_(m_tree->val_anchor(node));
592 if(ty.m_bits & VALTAG)
594 write_pws_and_pend_(PWS_SPACE_);
595 write_tag_(m_tree->val_tag(node));
597 if(ty.is_container() && m_tree->has_children(node))
599 if(!(ty.m_bits & CONTAINER_STYLE))
609template<
class Writer>
610void Emitter<Writer>::blck_close_entry_(id_type node)
619template<
class Writer>
620void Emitter<Writer>::visit_blck_seq_(id_type node)
622 RYML_ASSERT_VISIT_CB_(m_tree->callbacks(), m_tree->is_seq(node), m_tree, node);
624 for(id_type child = m_tree->first_child(node); child != NONE; child = m_tree->next_sibling(child))
627 NodeType ty = m_tree->type(child);
628 RYML_ASSERT_VISIT_CB_(m_tree->callbacks(), ty.is_val() || ty.is_container() || ty == NOTYPE, m_tree, node);
629 blck_seq_open_entry_(child);
632 write_pws_and_pend_(PWS_NONE_);
633 csubstr val = m_tree->val(child);
636 if(!(ty.m_bits & VAL_STYLE))
638 blck_write_scalar_(val, ty.m_bits & VAL_STYLE);
645 else if(ty.is_container())
649 visit_blck_container_(child);
653 blck_close_entry_(child);
657 write_pws_and_pend_(PWS_NONE_);
665template<
class Writer>
666void Emitter<Writer>::visit_blck_map_(id_type node)
668 RYML_ASSERT_VISIT_CB_(m_tree->callbacks(), m_tree->is_map(node), m_tree, node);
670 for(id_type child = m_tree->first_child(node); child != NONE; child = m_tree->next_sibling(child))
673 NodeType ty = m_tree->type(child);
674 RYML_ASSERT_VISIT_CB_(m_tree->callbacks(), ty.is_keyval() || ty.is_container() || ty == NOTYPE, m_tree, node);
675 blck_map_open_entry_(child);
678 write_pws_and_pend_(PWS_NONE_);
679 csubstr val = m_tree->val(child);
682 if(!(ty.m_bits & VAL_STYLE))
684 blck_write_scalar_(val, ty.m_bits & VAL_STYLE);
691 else if(ty.is_container())
695 visit_blck_container_(child);
699 blck_close_entry_(child);
703 write_pws_and_pend_(PWS_NONE_);
711template<
class Writer>
712void Emitter<Writer>::visit_flow_sl_seq_(id_type node)
714 RYML_ASSERT_VISIT_CB_(m_tree->callbacks(), m_tree->is_seq(node), m_tree, node);
715 const flow_pws pws = setup_flow_pws_sl_(node);
717 for(id_type child = m_tree->first_child(node), last = m_tree->last_child(node); child != NONE; child = m_tree->next_sibling(child))
719 NodeType ty = m_tree->type(child);
720 RYML_ASSERT_VISIT_CB_(m_tree->callbacks(), (ty & (VAL|SEQ|MAP)) || ty == NOTYPE, m_tree, node);
721 flow_seq_open_entry_(child);
724 write_pws_and_pend_(PWS_NONE_);
725 csubstr val = m_tree->val(child);
728 if(!(ty.m_bits & detail::styles_flow_val_))
730 flow_write_scalar_(val, ty.m_bits & detail::styles_flow_val_);
737 else if(ty.m_bits & (SEQ|MAP))
740 visit_flow_container_(child);
743 flow_close_entry_sl_(child, last, pws.next_pws(m_col));
751template<
class Writer>
752void Emitter<Writer>::visit_flow_ml_seq_(id_type node)
754 RYML_ASSERT_VISIT_CB_(m_tree->callbacks(), m_tree->is_seq(node), m_tree, node);
757 if(m_opts.indent_flow_ml()) ++m_ilevel;
758 const bool stop_at_end = maybe_start_flow_pws_ml_(node);
759 for(id_type child = m_tree->first_child(node), last = m_tree->last_child(node); child != NONE; child = m_tree->next_sibling(child))
761 NodeType ty = m_tree->type(child);
762 RYML_ASSERT_VISIT_CB_(m_tree->callbacks(), ty.is_val() || ty.is_container() || ty == NOTYPE, m_tree, node);
763 flow_seq_open_entry_(child);
766 write_pws_and_pend_(PWS_NONE_);
767 csubstr val = m_tree->val(child);
770 if(!(ty.m_bits & detail::styles_flow_val_))
772 flow_write_scalar_(val, ty.m_bits & detail::styles_flow_val_);
779 else if(ty.is_container())
782 visit_flow_container_(child);
785 flow_close_entry_ml_(child, last, m_flow_pws.next_pws(m_col));
789 if(m_opts.indent_flow_ml()) --m_ilevel;
790 write_pws_and_pend_(PWS_NONE_);
797template<
class Writer>
798void Emitter<Writer>::visit_flow_sl_map_(id_type node)
800 RYML_ASSERT_VISIT_CB_(m_tree->callbacks(), m_tree->is_map(node), m_tree, node);
801 flow_pws pws = setup_flow_pws_sl_(node);
803 for(id_type child = m_tree->first_child(node), last = m_tree->last_child(node); child != NONE; child = m_tree->next_sibling(child))
805 NodeType ty = m_tree->type(child);
806 RYML_ASSERT_VISIT_CB_(m_tree->callbacks(), ty.has_key() && (ty.has_val() || ty.is_container() || ty == NOTYPE), m_tree, node);
807 flow_map_open_entry_(child);
810 write_pws_and_pend_(PWS_NONE_);
811 csubstr val = m_tree->val(child);
814 if(!(ty.m_bits & detail::styles_flow_val_))
816 flow_write_scalar_(val, ty.m_bits & detail::styles_flow_val_);
823 else if(ty.is_container())
826 visit_flow_container_(child);
829 flow_close_entry_sl_(child, last, pws.next_pws(m_col));
831 write_pws_and_pend_(PWS_NONE_);
838template<
class Writer>
839void Emitter<Writer>::visit_flow_ml_map_(id_type node)
841 RYML_ASSERT_VISIT_CB_(m_tree->callbacks(), m_tree->is_map(node), m_tree, node);
844 if(m_opts.indent_flow_ml()) ++m_ilevel;
845 const bool stop_at_end = maybe_start_flow_pws_ml_(node);
846 for(id_type child = m_tree->first_child(node), last = m_tree->last_child(node); child != NONE; child = m_tree->next_sibling(child))
848 NodeType ty = m_tree->type(child);
849 RYML_ASSERT_VISIT_CB_(m_tree->callbacks(), ty.has_key() && (ty.has_val() || ty.is_container() || ty == NOTYPE), m_tree, node);
850 flow_map_open_entry_(child);
853 write_pws_and_pend_(PWS_NONE_);
854 csubstr val = m_tree->val(child);
857 if(!(ty.m_bits & detail::styles_flow_val_))
859 flow_write_scalar_(val, ty.m_bits & detail::styles_flow_val_);
866 else if(ty.is_container())
869 visit_flow_container_(child);
872 flow_close_entry_ml_(child, last, m_flow_pws.next_pws(m_col));
876 if(m_opts.indent_flow_ml()) --m_ilevel;
877 write_pws_and_pend_(PWS_NONE_);
884template<
class Writer>
885void Emitter<Writer>::visit_blck_(id_type node)
887 const NodeType ty = m_tree->type(node);
888 RYML_ASSERT_VISIT_CB_(m_tree->callbacks(), !ty.is_stream(), m_tree, node);
889 RYML_ASSERT_VISIT_CB_(m_tree->callbacks(), ty.is_container() || ty.is_doc(), m_tree, node);
890 RYML_ASSERT_VISIT_CB_(m_tree->callbacks(), m_tree->is_root(node) || (m_tree->parent_is_map(node) || m_tree->parent_is_seq(node)), m_tree, node);
891 if C4_UNLIKELY(m_depth > m_opts.max_depth())
892 RYML_ERR_VISIT_CB_(m_tree->callbacks(), m_tree, node,
"max depth exceeded");
895 visit_blck_seq_(node);
899 RYML_ASSERT_VISIT_CB_(m_tree->callbacks(), ty.is_map(), m_tree, node);
900 visit_blck_map_(node);
907template<
class Writer>
908void Emitter<Writer>::visit_flow_sl_(id_type node)
910 const NodeType ty = m_tree->type(node);
911 RYML_ASSERT_VISIT_CB_(m_tree->callbacks(), !ty.is_stream(), m_tree, node);
912 RYML_ASSERT_VISIT_CB_(m_tree->callbacks(), ty.is_container() || ty.is_doc(), m_tree, node);
913 RYML_ASSERT_VISIT_CB_(m_tree->callbacks(), m_tree->is_root(node) || (m_tree->parent_is_map(node) || m_tree->parent_is_seq(node)), m_tree, node);
914 if C4_UNLIKELY(m_depth > m_opts.max_depth())
915 RYML_ERR_VISIT_CB_(m_tree->callbacks(), m_tree, node,
"max depth exceeded");
918 visit_flow_sl_seq_(node);
922 RYML_ASSERT_VISIT_CB_(m_tree->callbacks(), ty.is_map(), m_tree, node);
923 visit_flow_sl_map_(node);
930template<
class Writer>
931void Emitter<Writer>::visit_flow_ml_(id_type node)
933 const NodeType ty = m_tree->type(node);
934 RYML_ASSERT_VISIT_CB_(m_tree->callbacks(), !ty.is_stream(), m_tree, node);
935 RYML_ASSERT_VISIT_CB_(m_tree->callbacks(), ty.is_container() || ty.is_doc(), m_tree, node);
936 RYML_ASSERT_VISIT_CB_(m_tree->callbacks(), m_tree->is_root(node) || (m_tree->parent_is_map(node) || m_tree->parent_is_seq(node)), m_tree, node);
937 if C4_UNLIKELY(m_depth > m_opts.max_depth())
938 RYML_ERR_VISIT_CB_(m_tree->callbacks(), m_tree, node,
"max depth exceeded");
941 visit_flow_ml_seq_(node);
945 RYML_ASSERT_VISIT_CB_(m_tree->callbacks(), ty.is_map(), m_tree, node);
946 visit_flow_ml_map_(node);
953template<
class Writer>
954void Emitter<Writer>::flow_write_scalar_(csubstr str, type_bits ty)
956 RYML_ASSERT_BASIC_CB_(m_tree->callbacks(), !(ty & detail::styles_block_));
957 if((ty & detail::styles_plain_) || !(ty & SCALAR_STYLE))
959 write_scalar_plain_(str, m_ilevel);
961 else if(ty & detail::styles_squo_)
963 write_scalar_squo_(str, m_ilevel);
967 write_scalar_dquo_(str, m_ilevel);
971template<
class Writer>
972void Emitter<Writer>::blck_write_scalar_(csubstr str, type_bits ty)
974 if((ty & detail::styles_plain_) || !(ty & SCALAR_STYLE))
976 write_scalar_plain_(str, m_ilevel);
978 else if(ty & detail::styles_squo_)
980 write_scalar_squo_(str, m_ilevel);
982 else if(ty & detail::styles_dquo_)
984 write_scalar_dquo_(str, m_ilevel);
986 else if(ty & detail::styles_literal_)
988 write_scalar_literal_(str, m_ilevel);
992 write_scalar_folded_(str, m_ilevel);
996template<
class Writer>
997size_t Emitter<Writer>::write_escaped_newlines_(csubstr s,
size_t i)
999 RYML_ASSERT_BASIC_CB_(m_tree->callbacks(), s.len > i);
1000 RYML_ASSERT_BASIC_CB_(m_tree->callbacks(), s.str[i] ==
'\n');
1009 }
while(i < s.len && s.str[i] ==
'\n');
1010 RYML_ASSERT_BASIC_CB_(m_tree->callbacks(), i > 0);
1012 RYML_ASSERT_BASIC_CB_(m_tree->callbacks(), s.str[i] ==
'\n');
1017inline bool _is_indented_block(csubstr s,
size_t prev,
size_t i)
noexcept
1019 if(prev == 0 && s.begins_with_any(
" \t"))
1021 const size_t pos = s.first_not_of(
'\n', i);
1022 return (pos != npos) && (s.str[pos] ==
' ' || s.str[pos] ==
'\t');
1026template<
class Writer>
1027size_t Emitter<Writer>::write_indented_block_(csubstr s,
size_t i, id_type ilevel)
1030 RYML_ASSERT_BASIC_CB_(m_tree->callbacks(), i > 0);
1031 RYML_ASSERT_BASIC_CB_(m_tree->callbacks(), s.str[i-1] ==
'\n');
1032 RYML_ASSERT_BASIC_CB_(m_tree->callbacks(), i < s.len);
1033 RYML_ASSERT_BASIC_CB_(m_tree->callbacks(), s.str[i] ==
' ' || s.str[i] ==
'\t' || s.str[i] ==
'\n');
1035 size_t pos = s.find(
"\n ", i);
1037 pos = s.find(
"\n\t", i);
1042 indent_(ilevel + 1);
1043 write_(s.range(i, pos));
1049 pos = s.find(
'\n', i);
1052 const size_t pos2 = s.first_not_of(
'\n', pos);
1053 pos = (pos2 !=
npos) ? pos2 : pos;
1055 indent_(ilevel + 1);
1056 write_(s.range(i, pos));
1062template<
class Writer>
1063void Emitter<Writer>::write_scalar_literal_(csubstr s, id_type ilevel)
1065 RYML_ASSERT_BASIC_CB_(m_tree->callbacks(), s.find(
"\r") == csubstr::npos);
1067 const size_t numnewlines_at_end = s.
len - trimmed.len;
1068 const bool is_newline_only = (trimmed.len == 0 && (s.len > 0));
1069 const bool explicit_indentation = s.triml(
"\n\r").begins_with_any(
" \t");
1072 if(explicit_indentation)
1075 if(numnewlines_at_end > 1 || is_newline_only)
1077 else if(numnewlines_at_end == 0)
1084 for(
size_t i = 0; i < trimmed.len; ++i)
1086 if(trimmed[i] !=
'\n')
1090 indent_(ilevel + 1);
1094 if(pos < trimmed.len)
1096 indent_(ilevel + 1);
1097 write_(trimmed.sub(pos));
1100 for(
size_t i = !is_newline_only; i < numnewlines_at_end; ++i)
1104template<
class Writer>
1105void Emitter<Writer>::write_scalar_folded_(csubstr s, id_type ilevel)
1107 RYML_ASSERT_BASIC_CB_(m_tree->callbacks(), s.find(
"\r") == csubstr::npos);
1109 const size_t numnewlines_at_end = s.
len - trimmed.len;
1110 const bool is_newline_only = (trimmed.len == 0 && (s.len > 0));
1111 const bool explicit_indentation = s.triml(
"\n\r").begins_with_any(
" \t");
1114 if(explicit_indentation)
1117 if(numnewlines_at_end == 0)
1119 else if(numnewlines_at_end > 1 || is_newline_only)
1126 for(
size_t i = 0; i < trimmed.len; ++i)
1128 if(trimmed[i] !=
'\n')
1131 if( ! _is_indented_block(s, pos, i))
1135 indent_(ilevel + 1);
1136 write_(s.range(pos, i));
1137 i = write_escaped_newlines_(s, i);
1144 if(s.str[i+1] ==
'\n')
1147 i = write_escaped_newlines_(s, i);
1161 indent_(ilevel + 1);
1162 write_(s.range(pos, i));
1163 if(pos > 0 || !s.begins_with_any(
" \t"))
1164 i = write_indented_block_(s, i, ilevel);
1168 if(pos < trimmed.len)
1170 indent_(ilevel + 1);
1171 write_(trimmed.sub(pos));
1174 for(
size_t i = !is_newline_only; i < numnewlines_at_end; ++i)
1178template<
class Writer>
1179void Emitter<Writer>::write_scalar_squo_(csubstr s, id_type ilevel)
1183 for(
size_t i = 0; i < s.len; ++i)
1187 write_(s.range(pos, i));
1189 i = write_escaped_newlines_(s, i);
1192 indent_(ilevel + 1);
1195 else if(s[i] ==
'\'')
1210template<
class Writer>
1211void Emitter<Writer>::write_scalar_dquo_(csubstr s, id_type ilevel)
1215 for(
size_t i = 0; i < s.len; ++i)
1217 const char curr = s.str[i];
1230#ifndef prefer_writing_newlines_as_double_newlines
1245 _write(s.range(pos, i));
1246 i = _write_escaped_newlines(s, i);
1252 _indent(ilevel + 1);
1254 size_t first = s.first_not_of(
" \t", i);
1261 _write(s.range(i, first));
1273 const size_t next = s.first_not_of(
" \t\r", i);
1274 if(next != npos && s.str[next] ==
'\n')
1308template<
class Writer>
1309void Emitter<Writer>::write_scalar_plain_(csubstr s, id_type ilevel)
1311 if C4_UNLIKELY(ilevel == 0 && (s.begins_with(
"...") || s.begins_with(
"---")))
1313 indent_(ilevel + 1);
1317 for(
size_t i = 0; i < s.len; ++i)
1319 const char curr = s.str[i];
1324 i = write_escaped_newlines_(s, i);
1327 indent_(ilevel + 1);
1339inline type_bits json_type_(type_bits ty)
1343 sl_bits = (CONTAINER_STYLE & ~FLOW_SPC),
1350 else if((ty & (SEQ|MAP)) && !(ty & sl_bits))
1359template<
class Writer>
1360void Emitter<Writer>::json_emit_(id_type
id)
1362 NodeType ty = m_tree->type(
id);
1364 if C4_UNLIKELY(ty.is_stream() && m_opts.json_err_on_stream())
1365 RYML_ERR_VISIT_CB_(m_tree->callbacks(), m_tree,
id,
"found stream node");
1366 static_assert(STREAM & SEQ,
"STREAM must be a SEQ");
1367 ty = detail::json_type_(ty);
1368 if(ty.is_flow_mlx())
1370 json_visit_ml_(
id, ty, 0);
1375 json_visit_sl_(
id, ty, 0);
1379template<
class Writer>
1380void Emitter<Writer>::json_visit_sl_(id_type
id, NodeType ty, id_type depth)
1382 if C4_UNLIKELY(depth > m_opts.max_depth())
1383 RYML_ERR_VISIT_CB_(m_tree->callbacks(), m_tree,
id,
"max depth exceeded");
1386 json_writev_(
id, ty);
1388 else if(ty.is_keyval())
1390 json_writek_(
id, ty);
1392 json_writev_(
id, ty);
1394 else if(ty.is_container())
1396 ty = detail::json_type_(ty);
1399 json_writek_(
id, ty);
1404 else if(ty.is_map())
1407 for(id_type child = m_tree->first_child(
id); child != NONE; child = m_tree->next_sibling(child))
1409 if(child != m_tree->first_child(
id))
1411 if((ty & FLOW_SPC) || m_opts.force_flow_spc())
1416 json_visit_sl_(child, m_tree->type(child), depth+1);
1421 else if(ty.is_map())
1426template<
class Writer>
1427void Emitter<Writer>::json_visit_ml_(id_type
id, NodeType ty, id_type depth)
1429 if C4_UNLIKELY(depth > m_opts.max_depth())
1430 RYML_ERR_VISIT_CB_(m_tree->callbacks(), m_tree,
id,
"max depth exceeded");
1433 json_writev_(
id, ty);
1435 else if(ty.is_keyval())
1437 json_writek_(
id, ty);
1439 json_writev_(
id, ty);
1441 else if(ty.is_container())
1443 ty = detail::json_type_(ty);
1446 json_writek_(
id, ty);
1451 else if(ty.is_map())
1454 if(m_tree->has_children(
id))
1457 if(m_opts.indent_flow_ml()) ++m_ilevel;
1460 for(id_type first = m_tree->first_child(
id), child = first;
1462 child = m_tree->next_sibling(child))
1467 const size_t maxcols = m_opts.max_cols();
1468 if((ty.m_bits & FLOW_MLN) && (m_col+1 < maxcols))
1470 if((ty.m_bits & FLOW_SPC) || m_opts.force_flow_spc())
1473 else if((ty.m_bits & FLOW_ML1) || (m_col+1 >= maxcols))
1479 NodeType chty = m_tree->type(child);
1480 if(chty.is_flow_sl())
1481 json_visit_sl_(child, chty, depth);
1483 json_visit_ml_(child, chty, depth);
1485 if(m_opts.indent_flow_ml()) --m_ilevel;
1493 else if(ty.is_map())
1498template<
class Writer>
1499bool Emitter<Writer>::json_maybe_write_naninf_(csubstr s)
1503 case 3:
case 4:
case 5:
1509 const char first = s.str[0];
1511 if(s.len == 4 && first ==
'.')
1514 goto write_inf_positive;
1518 else if(first ==
'-' || first ==
'+')
1521 if((rest.len == 4 && rest.str[0] ==
'.' &&
scalar_is_inf3(rest.str + 1))
1525 || (rest.len == 8 && (0 == memcmp(rest.str,
"infinity", 8))))
1528 goto write_inf_negative;
1530 goto write_inf_positive;
1533 else if(s.len == 8 && (0 == memcmp(s.str,
"infinity", 8)))
1535 goto write_inf_positive;
1540 goto write_inf_positive;
1549 write_(
"\"-.inf\"");
1556template<
class Writer>
1557void Emitter<Writer>::json_writek_(id_type
id, NodeType ty)
1559 if C4_UNLIKELY(ty.has_key_tag() && m_opts.json_err_on_tag())
1560 RYML_ERR_VISIT_CB_(m_tree->callbacks(), m_tree,
id,
"JSON does not have tags");
1561 if C4_UNLIKELY(ty.has_key_anchor() && m_opts.json_err_on_anchor())
1562 RYML_ERR_VISIT_CB_(m_tree->callbacks(), m_tree,
id,
"JSON does not have anchors");
1563 csubstr key = m_tree->key(
id);
1566 if(json_maybe_write_naninf_(key))
1569 json_write_scalar_dquo_(key);
1577template<
class Writer>
1578void Emitter<Writer>::json_writev_(id_type
id, NodeType ty)
1580 if C4_UNLIKELY(ty.has_val_tag() && m_opts.json_err_on_tag())
1581 RYML_ERR_VISIT_CB_(m_tree->callbacks(), m_tree,
id,
"JSON does not have tags");
1582 if C4_UNLIKELY(ty.has_val_anchor() && m_opts.json_err_on_anchor())
1583 RYML_ERR_VISIT_CB_(m_tree->callbacks(), m_tree,
id,
"JSON does not have anchors");
1584 csubstr val = m_tree->val(
id);
1588 bool dquoted = ((ty.m_bits &
VALQUO)
1591 json_write_scalar_dquo_(val);
1592 else if(json_maybe_write_naninf_(val))
1594 else if(val.is_number())
1595 json_write_number_(val);
1601 if(val.str || (ty.m_bits & (VALQUO|VALTAG)))
1609template<
class Writer>
1610void Emitter<Writer>::json_write_scalar_dquo_(csubstr s)
1614 for(
size_t i = 0; i < s.len; ++i)
1619 write_(s.range(pos, i));
1624 write_(s.range(pos, i));
1629 write_(s.range(pos, i));
1634 write_(s.range(pos, i));
1639 write_(s.range(pos, i));
1644 write_(s.range(pos, i));
1649 write_(s.range(pos, i));
1663template<
class Writer>
1664void Emitter<Writer>::json_write_number_(csubstr s)
1672 if(s.begins_with(
'-') && s.len > 1)
1675 if(rest.begins_with(
'.'))
1680 else if(rest.ends_with(
'.'))
1690 else if(s.begins_with(
'.'))
1695 else if(s.ends_with(
'.'))
1713C4_SUPPRESS_WARNING_GCC_CLANG_POP
void emit_as(EmitType_e type, Tree const *tree, id_type id=NONE)
emit!
id_type root_id() const
Get the id of the root node. The tree must not be empty. The tree can be empty only when constructed ...
bool empty() const
Query for zero size.
Callbacks const & callbacks() const
Error utilities used by ryml.
uint32_t type_bits
the integral type necessary to cover all the bits for NodeType_e
@ KEY_DQUO
mark key scalar as double quoted "
@ STREAM
a stream: a seq of docs
@ FLOW_ML1
mark container with multi-line flow style, 1 element per line
@ VAL_FOLDED
mark val scalar as multiline, block folded >
@ VAL_STYLE
mask of VALQUO|VAL_PLAIN : all the val scalar styles for val (not container styles!...
@ FLOW_SL
mark container with single-line flow style
@ SCALAR_DQUO
mask of KEY_DQUO|VAL_DQUO,
@ VAL_SQUO
mark val scalar as single quoted '
@ KEY_STYLE
mask of KEYQUO|KEY_PLAIN : all the key scalar styles for key (not container styles!...
@ VAL_PLAIN
mark val scalar as plain scalar (unquoted, even when multiline)
@ BLOCK
mark container with block style
@ FLOW_SPC
mark container with spaces after comma when in flow mode. Applies to both FLOW_SL and FLOW_MLN (but n...
@ VALQUO
val style is one of '">|. mask of VAL_SQUO|VAL_DQUO|VAL_FOLDED|VAL_LITERAL
@ 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 >
bool scalar_is_inf3(const char *s) noexcept
Query if a scalar is inf (inf, Inf, INF).
bool scalar_is_nan3(const char *s) noexcept
Query if a scalar is nan (nan, NaN, Nan, NAN).
NodeType scalar_style_choose_json(csubstr scalar) noexcept
choose a json scalar style based on the scalar's contents
NodeType scalar_style_choose_flow(csubstr scalar) noexcept
choose a YAML scalar style based on the scalar's contents, while in flow mode.
NodeType scalar_style_choose_block(csubstr scalar) noexcept
choose a YAML scalar style based on the scalar's contents, while in block mode.
basic_substring< const char > csubstr
an immutable string view
@ npos
a null string position
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...
basic_substring range(size_t first, size_t last=npos) const noexcept
return [first,last[.
size_t len
the length of the substring
basic_substring sub(size_t first) const noexcept
return [first,len[
basic_substring trimr(const C c) const
trim the character c from the right
Wraps a type_bits mask of NodeTypeBits flags with some syntactic sugar and predicates.
bool has_key() const noexcept
bool is_doc() const noexcept
bool is_val_plain() const noexcept
bool is_flow_mlx() const noexcept
bool has_val() const noexcept
bool is_container() const noexcept
bool is_val() const noexcept
bool is_stream() const noexcept