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_
23 C4_SUPPRESS_WARNING_GCC_CLANG_WITH_PUSH(
"-Wold-style-cast")
24 C4_SUPPRESS_WARNING_GCC("-Wuseless-cast")
47 template<
class Writer>
51 if(!tree || tree->
empty())
64 else if(type == EMIT_JSON)
67 RYML_ERR_BASIC_CB_(m_tree->callbacks(),
"unknown emit type");
86 template<
class Writer>
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_);
165 template<
class Writer>
166 void 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);
207 else if(ty.is_container())
212 if(m_tree->next_sibling(child) !=
NONE)
214 write_tag_directives(m_tree->next_sibling(child));
223 template<
class Writer>
224 void Emitter<Writer>::visit_blck_container_(
id_type id)
226 NodeType ty = m_tree->type(
id);
229 write_pws_and_pend_(PWS_NONE_);
232 else if(ty.is_flow_mlx())
238 template<
class Writer>
239 void Emitter<Writer>::visit_flow_container_(
id_type id)
241 NodeType ty = m_tree->type(
id);
244 write_pws_and_pend_(PWS_NONE_);
254 template<
class Writer>
255 void 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);
292 template<
class Writer>
293 void 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);
312 template<
class Writer>
313 void 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);
351 template<
class Writer>
352 void Emitter<Writer>::top_close_entry_(
id_type node)
354 NodeType ty = m_tree->type(node);
355 if(ty.is_val() && !(ty.m_bits &
VALNIL))
364 template<
class Writer>
365 void Emitter<Writer>::flow_seq_open_entry_(
id_type node)
367 NodeType ty = m_tree->type(node);
368 write_pws_and_pend_(PWS_NONE_);
371 write_pws_and_pend_(PWS_SPACE_);
373 write_(m_tree->val_anchor(node));
377 write_pws_and_pend_(PWS_SPACE_);
378 write_tag_(m_tree->val_tag(node));
385 template<
class Writer>
386 void 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);
393 write_pws_and_pend_(PWS_SPACE_);
395 write_(m_tree->key_anchor(node));
399 write_pws_and_pend_(PWS_SPACE_);
400 write_tag_(m_tree->key_tag(node));
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);
415 write_pws_and_pend_(PWS_SPACE_);
419 write_pws_and_pend_(PWS_SPACE_);
421 write_(m_tree->val_anchor(node));
425 write_pws_and_pend_(PWS_SPACE_);
426 write_tag_(m_tree->val_tag(node));
433 template<
class Writer>
434 C4_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());
446 template<
class Writer>
447 C4_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())
464 template<
class Writer>
465 void 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_;
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");
480 pend_after_comma = PWS_NEWL_;
484 template<
class Writer>
485 void 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);
494 template<
class Writer>
495 void 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);
511 template<
class Writer>
512 void 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;
521 has_tag_or_anchor =
true;
522 write_pws_and_pend_(PWS_SPACE_);
524 write_(m_tree->val_anchor(node));
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())
536 if((ty.m_bits &
BLOCK) && m_tree->has_children(node))
544 template<
class Writer>
545 void 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);
552 write_pws_and_pend_(PWS_NONE_);
555 write_pws_and_pend_(PWS_SPACE_);
557 write_(m_tree->key_anchor(node));
561 write_pws_and_pend_(PWS_SPACE_);
562 write_tag_(m_tree->key_tag(node));
566 write_pws_and_pend_(PWS_SPACE_);
571 write_pws_and_pend_(PWS_NONE_);
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_);
588 write_pws_and_pend_(PWS_SPACE_);
590 write_(m_tree->val_anchor(node));
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))
609 template<
class Writer>
610 void Emitter<Writer>::blck_close_entry_(
id_type node)
619 template<
class Writer>
620 void 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);
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_);
665 template<
class Writer>
666 void 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);
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_);
711 template<
class Writer>
712 void 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);
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));
751 template<
class Writer>
752 void 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);
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_);
797 template<
class Writer>
798 void 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);
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_);
838 template<
class Writer>
839 void 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);
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_);
884 template<
class Writer>
885 void 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);
907 template<
class Writer>
908 void 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);
930 template<
class Writer>
931 void 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);
953 template<
class Writer>
959 write_scalar_plain_(str, m_ilevel);
963 write_scalar_squo_(str, m_ilevel);
967 write_scalar_dquo_(str, m_ilevel);
971 template<
class Writer>
974 if((ty & detail::styles_plain_) || !(ty & SCALAR_STYLE))
976 write_scalar_plain_(str, m_ilevel);
980 write_scalar_squo_(str, m_ilevel);
984 write_scalar_dquo_(str, m_ilevel);
988 write_scalar_literal_(str, m_ilevel);
992 write_scalar_folded_(str, m_ilevel);
996 template<
class Writer>
997 size_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');
1017 inline 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');
1026 template<
class Writer>
1027 size_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));
1062 template<
class Writer>
1063 void 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)
1104 template<
class Writer>
1105 void 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)
1178 template<
class Writer>
1179 void 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] ==
'\'')
1210 template<
class Writer>
1211 void 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')
1308 template<
class Writer>
1309 void 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);
1350 else if((ty & (
SEQ|
MAP)) && !(ty & sl_bits))
1359 template<
class Writer>
1360 void 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);
1379 template<
class Writer>
1380 void 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())
1426 template<
class Writer>
1427 void 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())
1498 template<
class Writer>
1499 bool 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\"");
1556 template<
class Writer>
1557 void 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);
1577 template<
class Writer>
1578 void 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);
1609 template<
class Writer>
1610 void 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));
1663 template<
class Writer>
1664 void 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(
'.'))
1713 C4_SUPPRESS_WARNING_GCC_CLANG_POP
mark val scalar as plain scalar (unquoted, even when multiline)
basic_substring trimr(const C c) const
trim the character c from the right
mark key scalar as double quoted "
bool is_doc() const noexcept
A YAML/JSON emitter, templated on a writer class such as WriterBuf, WriterFile, or WriterOStream...
mark key scalar as multiline, block literal |
mark val scalar as single quoted '
val style is one of `'">|`. mask of VAL_SQUO|VAL_DQUO|VAL_FOLDED|VAL_LITERAL
bool empty() const
Query for zero size.
NodeType scalar_style_choose_json(csubstr scalar) noexcept
choose a json scalar style based on the scalar's contents
bool is_val() const noexcept
mask of CONTAINER_STYLE_FLOW|CONTAINER_STYLE_BLOCK : all container style flags
mark val scalar as double quoted "
bool is_stream() const noexcept
mark container with multi-line flow style, n elements per line, < wrapped (as set by EmitOptions::max...
mask of KEY_STYLE|VAL_STYLE : all the key+val scalar styles
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 ...
a scalar: has a scalar (ie string) value, possibly empty. must be a leaf node, and cannot be MAP or S...
bool has_val() const noexcept
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...
mark val scalar as multiline, block folded >
NodeType scalar_style_choose_flow(csubstr scalar) noexcept
choose a YAML scalar style based on the scalar's contents, while in flow mode.
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)
mark key scalar as multiline, block folded >
basic_substring sub(size_t first) const noexcept
return [first,len[
Callbacks const & callbacks() const
basic_substring< const char > csubstr
an immutable string view
bool is_val_plain() const noexcept
the val is null (eg {a : } results in a null val)
mark container with block style < - seqs as <
basic_substring range(size_t first, size_t last=npos) const noexcept
return [first,last[.
a *reference: the key references an &anchor
mask of KEYQUO|KEY_PLAIN : all the key scalar styles for key (not container styles!) ...
no node type or style is set
size_t len
the length of the substring
bool is_flow_mlx() const noexcept
mark container with spaces after comma when in flow mode. < Applies to both FLOW_SL and FLOW_MLN (but...
mark key scalar as plain scalar (unquoted, even when multiline)
Error utilities used by ryml.
bool has_key() const noexcept
mask of KEY_DQUO|VAL_DQUO,
mark val scalar as multiline, block literal |
uint32_t type_bits
the integral type necessary to cover all the bits for NodeType_e
NodeType scalar_style_choose_block(csubstr scalar) noexcept
choose a YAML scalar style based on the scalar's contents, while in block mode.
a map: a parent of KEYVAL/KEYSEQ/KEYMAP nodes
bool is_container() const noexcept
Wraps a type_bits mask of NodeTypeBits flags with some syntactic sugar and predicates.
mark key scalar as single quoted '
mark container with multi-line flow style, 1 element per line < - seqs as <
mask of VALQUO|VAL_PLAIN : all the val scalar styles for val (not container styles!) ...
a seq: a parent of VAL/SEQ/MAP nodes
mark container with single-line flow style < - seqs as <