1#ifndef _C4_YML_EMIT_HPP_
2#define _C4_YML_EMIT_HPP_
6#ifndef _C4_YML_WRITER_HPP_
10#ifndef _C4_YML_TREE_HPP_
14#ifndef _C4_YML_NODE_HPP_
19C4_SUPPRESS_WARNING_GCC_CLANG_WITH_PUSH(
"-Wold-style-cast")
36template<
class Writer>
class Emitter;
37template<
class OStream>
64 typedef enum : uint32_t {
65 INDENT_FLOW_ML = 1u << 0u,
66 FORCE_FLOW_SPC = 1u << 1u,
67 EMIT_NONROOT_KEY = 1u << 2u,
68 EMIT_NONROOT_DASH = 1u << 3u,
69 EMIT_NONROOT_MARKUP = EMIT_NONROOT_KEY|EMIT_NONROOT_DASH,
70 JSON_ERR_ON_STREAM = 1u << 4u,
71 JSON_ERR_ON_TAG = 1u << 5u,
72 JSON_ERR_ON_ANCHOR = 1u << 6u,
73 _JSON_ERR_MASK = JSON_ERR_ON_STREAM|JSON_ERR_ON_TAG|JSON_ERR_ON_ANCHOR,
74 DEFAULT_FLAGS = EMIT_NONROOT_KEY|INDENT_FLOW_ML,
97 C4_ALWAYS_INLINE
bool indent_flow_ml() const noexcept {
return (m_flags & INDENT_FLOW_ML) != 0; }
105 C4_ALWAYS_INLINE
bool force_flow_spc() const noexcept {
return (m_flags & FORCE_FLOW_SPC) != 0; }
127 C4_ALWAYS_INLINE
bool emit_nonroot_key() const noexcept {
return (m_flags & EMIT_NONROOT_KEY) != 0; }
133 C4_ALWAYS_INLINE
bool emit_nonroot_dash() const noexcept {
return (m_flags & EMIT_NONROOT_DASH) != 0; }
146 C4_ALWAYS_INLINE
bool json_err_on_stream() const noexcept {
return (m_flags & JSON_ERR_ON_STREAM) != 0; }
151 C4_ALWAYS_INLINE
bool json_err_on_tag() const noexcept {
return (m_flags & JSON_ERR_ON_TAG) != 0; }
156 C4_ALWAYS_INLINE
bool json_err_on_anchor() const noexcept {
return (m_flags & JSON_ERR_ON_ANCHOR) != 0; }
159 RYML_DEPRECATED(
"use .json_err_on_{tag,anchor}()") C4_ALWAYS_INLINE Flags_e json_error_flags() const noexcept {
return (Flags_e)(m_flags & _JSON_ERR_MASK); }
160 RYML_DEPRECATED(
"use .json_err_on_{tag,anchor}()") EmitOptions& json_error_flags(Flags_e d) noexcept { m_flags = (d & _JSON_ERR_MASK);
return *
this; }
182 return m_max_depth == that.m_max_depth &&
183 m_flags == that.m_flags;
189 id_type m_max_depth{max_depth_default};
190 id_type m_max_cols{max_cols_default};
191 uint32_t m_flags{DEFAULT_FLAGS};
202template<
class Writer>
212 template<
class ...WriterArgs>
214 : Writer(std::forward<WriterArgs>(args)...)
227 template<
class ...WriterArgs>
229 : Writer(std::forward<WriterArgs>(args)...)
271 return this->
emit_as(type, *n.
tree(), n.
id(), error_on_excess);
289 typedef enum : uint32_t { _PWS_NONE = 0u, _PWS_SPACE = 1u, _PWS_NEWL = 2u } Pws_e;
292 C4_ALWAYS_INLINE
void _pend_none() noexcept
297 C4_ALWAYS_INLINE
void _pend_newl() noexcept
302 C4_ALWAYS_INLINE
void _pend_space() noexcept
307 C4_ALWAYS_INLINE
void _write_pws_and_pend(Pws_e next=_PWS_NONE)
noexcept
309 if(m_pws == _PWS_SPACE)
313 else if(m_pws == _PWS_NEWL)
327 C4_ALWAYS_INLINE Pws_e
next_pws(
size_t col)
const noexcept
335 C4_NODISCARD
bool _maybe_start_flow_pws_ml(
id_type node)
noexcept
337 _RYML_ASSERT_VISIT_(m_tree->callbacks(), m_tree->type(node) & (
FLOW_ML1|
FLOW_MLN), m_tree, node);
338 if(m_flow_pws.active)
341 if(m_opts.force_flow_spc())
343 m_flow_pws.start(ty, m_opts.max_cols());
346 C4_NODISCARD flow_pws _setup_flow_pws_sl(id_type node)
noexcept
349 if(m_flow_pws.active)
355 NodeType ty = m_tree->
type(node);
356 if(m_opts.force_flow_spc())
367 void _emit_yaml(id_type
id);
369 void _visit_stream(id_type
id);
370 void _visit_doc(id_type
id);
371 void _visit_doc_val(id_type
id);
372 void _visit_blck_container(id_type
id);
373 void _visit_flow_container(id_type
id);
375 void _visit_flow_sl(id_type
id);
376 void _visit_flow_sl_seq(id_type
id);
377 void _visit_flow_sl_map(id_type
id);
379 void _visit_flow_ml(id_type
id);
380 void _visit_flow_ml_seq(id_type
id);
381 void _visit_flow_ml_map(id_type
id);
383 void _visit_blck(id_type
id);
384 void _visit_blck_seq(id_type
id);
385 void _visit_blck_map(id_type
id);
387 void _top_open_entry(id_type
id);
388 void _top_close_entry(id_type
id);
389 void _blck_seq_open_entry(id_type
id);
390 void _blck_map_open_entry(id_type
id);
391 void _blck_close_entry(id_type
id);
392 void _blck_write_scalar(csubstr str, type_bits type);
394 void _flow_seq_open_entry(id_type
id);
395 void _flow_map_open_entry(id_type
id);
396 void _flow_close_entry_sl(id_type
id, id_type last_sibling, Pws_e pend_after);
397 void _flow_close_entry_ml(id_type
id, id_type last_sibling, Pws_e pend_after);
398 void _flow_write_scalar(csubstr str, type_bits type);
402 void _json_emit(id_type
id);
403 void _write_scalar_literal(csubstr s, id_type level);
404 void _write_scalar_folded(csubstr s, id_type level);
405 void _write_scalar_squo(csubstr s, id_type level);
406 void _write_scalar_dquo(csubstr s, id_type level);
407 void _write_scalar_plain(csubstr s, id_type level);
409 size_t _write_escaped_newlines(csubstr s,
size_t i);
410 size_t _write_indented_block(csubstr s,
size_t i, id_type level);
414 void _json_visit_ml(id_type
id, NodeType ty, id_type depth);
415 void _json_visit_sl(id_type
id, NodeType ty, id_type depth);
416 bool _json_maybe_write_naninf(csubstr s);
417 void _json_writek(id_type
id, NodeType ty);
418 void _json_writev(id_type
id, NodeType ty);
419 void _json_write_scalar_dquo(csubstr s);
420 void _json_write_number(csubstr s);
424 void _write_tag(csubstr tag)
426 if(!tag.begins_with(
'!'))
430 void _write_ref(csubstr ref)
434 if(!ref.begins_with(
'*'))
442 C4_ALWAYS_INLINE
void _indent(id_type level)
444 size_t num = (size_t)(2u * level);
445 this->Writer::_do_write(
' ', num);
450 C4_ALWAYS_INLINE
void _write(
const char (&a)[N])
452 this->Writer::_do_write(std::forward<
const char (&)[N]>(a));
455 C4_ALWAYS_INLINE
void _write(csubstr s)
457 this->Writer::_do_write(s);
460 C4_ALWAYS_INLINE
void _write(
char c)
462 this->Writer::_do_write(c);
465 C4_ALWAYS_INLINE
void _write(
char c,
size_t num)
467 this->Writer::_do_write(c, num);
472 C4_ALWAYS_INLINE
void _newl()
474 this->Writer::_do_write(
'\n');
480 Tree
const* C4_RESTRICT m_tree;
490 C4_SUPPRESS_WARNING_GCC_PUSH
491 #if defined(__GNUC__) && (__GNUC__ < 5) && (!defined(__clang__))
493 C4_SUPPRESS_WARNING_GCC_WITH_PUSH(
"-Wparentheses")
498 _styles_block = ((
type_bits)_styles_block_key) | ((type_bits)_styles_block_val),
500 _styles_flow_val = VAL_STYLE & (~((type_bits)_styles_block_val)),
501 _styles_flow = ((
type_bits)_styles_flow_key) | ((type_bits)_styles_flow_val),
508 C4_SUPPRESS_WARNING_GCC_POP
632template<
class OStream>
633inline OStream& operator<< (OStream& s,
Tree const& t)
642template<
class OStream>
695template<
class OStream>
696inline OStream& operator<< (OStream& s,
as_json const& j)
706template<
class OStream>
707inline OStream& operator<< (OStream& s,
as_yaml const& y)
876template<
class CharOwningContainer>
879 size_t startpos = append ? cont->size() : 0u;
880 cont->resize(cont->capacity());
883 if(ret.
str ==
nullptr && ret.
len > 0)
885 cont->resize(startpos + ret.
len);
891 cont->resize(startpos + ret.
len);
896template<
class CharOwningContainer>
906template<
class CharOwningContainer>
909 const size_t startpos = append ? cont->size() : 0u;
910 cont->resize(cont->capacity());
914 if(ret.
str ==
nullptr && ret.
len > 0)
916 cont->resize(startpos + ret.
len);
922 cont->resize(startpos + ret.
len);
927template<
class CharOwningContainer>
935template<
class CharOwningContainer>
938 CharOwningContainer c;
939 emitrs_yaml(t,
id, opts, &c);
943template<
class CharOwningContainer>
946 CharOwningContainer c;
947 emitrs_json(t,
id, opts, &c);
957template<
class CharOwningContainer>
965template<
class CharOwningContainer>
975template<
class CharOwningContainer>
983template<
class CharOwningContainer>
993template<
class CharOwningContainer>
996 CharOwningContainer c;
999 emitrs_yaml(t, t.
root_id(), opts, &c);
1003template<
class CharOwningContainer>
1006 CharOwningContainer c;
1009 emitrs_json(t, t.
root_id(), opts, &c);
1020template<
class CharOwningContainer>
1028template<
class CharOwningContainer>
1038template<
class CharOwningContainer>
1046template<
class CharOwningContainer>
1056template<
class CharOwningContainer>
1061 CharOwningContainer c;
1062 emitrs_yaml(*n.
tree(), n.
id(), opts, &c);
1066template<
class CharOwningContainer>
1071 CharOwningContainer c;
1072 emitrs_json(*n.
tree(), n.
id(), opts, &c);
1084#define RYML_DEPRECATE_EMIT \
1085 RYML_DEPRECATED("use emit_yaml() instead. " \
1086 "See https://github.com/biojppm/rapidyaml/issues/120")
1087#define RYML_DEPRECATE_EMITRS \
1088 RYML_DEPRECATED("use emitrs_yaml() instead. " \
1089 "See https://github.com/biojppm/rapidyaml/issues/120")
1095#define RYML_TMP_EMIT_
1099RYML_DEPRECATE_EMIT
inline size_t emit(Tree
const& t, id_type
id, FILE *f)
1103RYML_DEPRECATE_EMIT
inline size_t emit(Tree
const& t, FILE *f=
nullptr)
1107RYML_DEPRECATE_EMIT
inline size_t emit(ConstNodeRef
const& r, FILE *f=
nullptr)
1112RYML_DEPRECATE_EMIT
inline substr emit(Tree
const& t, id_type
id, substr buf,
bool error_on_excess=
true)
1114 return emit_yaml(t,
id, buf, error_on_excess);
1116RYML_DEPRECATE_EMIT
inline substr emit(Tree
const& t, substr buf,
bool error_on_excess=
true)
1118 return emit_yaml(t, buf, error_on_excess);
1120RYML_DEPRECATE_EMIT
inline substr emit(ConstNodeRef
const& r, substr buf,
bool error_on_excess=
true)
1122 return emit_yaml(r, buf, error_on_excess);
1125#ifdef RYML_TMP_EMIT_
1127#undef RYML_TMP_EMIT_
1130template<
class CharOwningContainer>
1131RYML_DEPRECATE_EMITRS
substr emitrs(Tree
const& t, id_type
id, CharOwningContainer * cont)
1135template<
class CharOwningContainer>
1136RYML_DEPRECATE_EMITRS CharOwningContainer emitrs(Tree
const& t, id_type
id)
1138 return emitrs_yaml<CharOwningContainer>(t,
id);
1140template<
class CharOwningContainer>
1141RYML_DEPRECATE_EMITRS
substr emitrs(Tree
const& t, CharOwningContainer * cont)
1145template<
class CharOwningContainer>
1146RYML_DEPRECATE_EMITRS CharOwningContainer emitrs(Tree
const& t)
1148 return emitrs_yaml<CharOwningContainer>(t);
1150template<
class CharOwningContainer>
1151RYML_DEPRECATE_EMITRS
substr emitrs(ConstNodeRef
const& n, CharOwningContainer * cont)
1155template<
class CharOwningContainer>
1156RYML_DEPRECATE_EMITRS CharOwningContainer emitrs(ConstNodeRef
const& n)
1158 return emitrs_yaml<CharOwningContainer>(n);
1168C4_SUPPRESS_WARNING_GCC_CLANG_POP
1170#undef RYML_DEPRECATE_EMIT
1171#undef RYML_DEPRECATE_EMITRS
Holds a pointer to an existing tree, and a node id.
id_type id() const noexcept
Tree const * tree() const noexcept
bool readable() const noexcept
because a ConstNodeRef cannot be used to write to the tree, readable() has the same meaning as !...
A stateful emitter, for use with a writer such as WriterBuf, WriterFile, or WriterOStream.
id_type root_id() const
Get the id of the root node. The tree must not be empty.
Definitions for emit functions.
id_type max_depth() const noexcept
get the max depth for emitted trees (to prevent a stack overflow)
substr emit_as(EmitType_e type, ConstNodeRef const &n, bool error_on_excess=true)
emit starting at the given node
EmitOptions const & options() const noexcept
get the emit options for this object
bool emit_nonroot_key() const noexcept
id_type max_cols() const noexcept
bool json_err_on_tag() const noexcept
bool force_flow_spc() const noexcept
void max_depth(id_type max_depth) noexcept
set the max depth for emitted trees (to prevent a stack overflow)
as_yaml(Tree const &t, EmitOptions const &opts={})
void options(EmitOptions opts) noexcept
set the emit options for this object
static constexpr const id_type max_cols_default
substr emit_as(EmitType_e type, Tree const &t, bool error_on_excess=true)
emit starting at the root node
EmitOptions & max_cols(id_type cols) noexcept
Set max columns for the emitted YAML in FLOW_MLN mode.
bool json_err_on_anchor() const noexcept
id_type max_depth() const noexcept
void start(NodeType ty, size_t max_cols_) noexcept
as_yaml(Tree const &t, id_type id, EmitOptions const &opts={})
Emitter(WriterArgs &&...args)
Construct the emitter and its internal Writer state, using default emit options.
Emitter(EmitOptions const &opts, WriterArgs &&...args)
Construct the emitter and its internal Writer state.
substr emit_as(EmitType_e type, Tree const &t, id_type id, bool error_on_excess)
emit!
EmitOptions & json_err_on_tag(bool enabled) noexcept
Whether to trigger an error (or ignore the tag) when finding a tag in json mode.
EmitOptions & max_depth(id_type d) noexcept
Pws_e next_pws(size_t col) const noexcept
bool json_err_on_stream() const noexcept
EmitOptions & json_err_on_stream(bool enabled) noexcept
Whether to trigger an error when findind a stream in json mode.
as_json(Tree const &t, EmitOptions const &opts={})
EmitOptions & indent_flow_ml(bool enabled) noexcept
as_yaml(ConstNodeRef const &n, EmitOptions const &opts={})
bool indent_flow_ml() const noexcept
Indent the contents of FLOW_ML1 and FLOW_MLN containers.
EmitOptions & emit_nonroot_key(bool enabled) noexcept
When emit starts on a node which is not the root node, emit the node key as well.
EmitOptions & json_err_on_anchor(bool enabled) noexcept
Whether to trigger an error (or ignore the anchor) when finding an anchor in json mode.
bool emit_nonroot_dash() const noexcept
as_json(ConstNodeRef const &n, EmitOptions const &opts={})
EmitOptions & emit_nonroot_dash(bool enabled) noexcept
When emit starts on a node which is not the root node, emit a leading dash.
EmitOptions & force_flow_spc(bool enabled) noexcept
Force everywhere a space after comma in flow mode, overriding the FLOW_SPC status of individual conta...
static constexpr const id_type max_depth_default
as_json(Tree const &t, id_type id, EmitOptions const &opts={})
substr emitrs_json(Tree const &t, id_type id, EmitOptions const &opts, CharOwningContainer *cont, bool append=false)
(1) emit+resize: emit JSON to the given std::string/std::vector-like container, resizing it as needed...
substr emitrs_yaml(Tree const &t, id_type id, EmitOptions const &opts, CharOwningContainer *cont, bool append=false)
(1) emit+resize: emit YAML to the given std::string/std::vector-like container, resizing it as needed...
size_t emit_yaml(Tree const &t, id_type id, EmitOptions const &opts, FILE *f)
(1) emit YAML to the given file, starting at the given node.
size_t emit_json(Tree const &t, id_type id, EmitOptions const &opts, FILE *f)
(1) emit JSON to the given file, starting at the given node.
Emitter< WriterBuf > EmitterBuf
Emitter< WriterFile > EmitterFile
Emitter< WriterOStream< OStream > > EmitterOStream
EmitType_e
Specifies the type of content to emit.
uint32_t type_bits
the integral type necessary to cover all the bits for NodeType_e
@ KEY_DQUO
mark key scalar as double quoted "
@ FLOW_ML1
mark container with multi-line flow style, 1 element per line
@ VAL_FOLDED
mark val scalar as multiline, block folded >
@ FLOW_MLN
mark container with multi-line flow style, n elements per line, wrapped (as set by EmitOptions::max_c...
@ 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)
@ FLOW_SPC
mark container with spaces after comma when in flow mode. Applies to both FLOW_SL and FLOW_MLN (but n...
@ 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 >
substr to_substr(char(&s)[N]) noexcept
basic_substring< char > substr
a mutable string view
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...
(Undefined by default) Use shorter error message from checks/asserts: do not show the check condition...
size_t len
the length of the substring
C * str
a restricted pointer to the first character of the substring
A lightweight object containing options to be used when emitting.
wraps a NodeType_e element with some syntactic sugar and predicates
mark a tree or node to be emitted as yaml when using operator<<, with options.
mark a tree or node to be emitted as yaml when using operator<< .