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_TAG = 1u << 3u,
71 JSON_ERR_ON_ANCHOR = 1u << 4u,
72 _JSON_ERR_MASK = JSON_ERR_ON_TAG|JSON_ERR_ON_ANCHOR,
73 DEFAULT_FLAGS = EMIT_NONROOT_KEY|INDENT_FLOW_ML,
96 C4_ALWAYS_INLINE
bool indent_flow_ml() const noexcept {
return (m_flags & INDENT_FLOW_ML) != 0; }
104 C4_ALWAYS_INLINE
bool force_flow_spc() const noexcept {
return (m_flags & FORCE_FLOW_SPC) != 0; }
126 C4_ALWAYS_INLINE
bool emit_nonroot_key() const noexcept {
return (m_flags & EMIT_NONROOT_KEY) != 0; }
132 C4_ALWAYS_INLINE
bool emit_nonroot_dash() const noexcept {
return (m_flags & EMIT_NONROOT_DASH) != 0; }
145 C4_ALWAYS_INLINE
bool json_err_on_tag() const noexcept {
return (m_flags & JSON_ERR_ON_TAG) != 0; }
150 C4_ALWAYS_INLINE
bool json_err_on_anchor() const noexcept {
return (m_flags & JSON_ERR_ON_ANCHOR) != 0; }
153 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); }
154 RYML_DEPRECATED(
"use .json_err_on_{tag,anchor}()") EmitOptions& json_error_flags(Flags_e d) noexcept { m_flags = (d & _JSON_ERR_MASK);
return *
this; }
176 return m_max_depth == that.m_max_depth &&
177 m_flags == that.m_flags;
183 id_type m_max_depth{max_depth_default};
184 id_type m_max_cols{max_cols_default};
185 uint32_t m_flags{DEFAULT_FLAGS};
196template<
class Writer>
206 template<
class ...WriterArgs>
208 : Writer(std::forward<WriterArgs>(args)...)
221 template<
class ...WriterArgs>
223 : Writer(std::forward<WriterArgs>(args)...)
265 return this->
emit_as(type, *n.
tree(), n.
id(), error_on_excess);
283 typedef enum : uint32_t { _PWS_NONE = 0u, _PWS_SPACE = 1u, _PWS_NEWL = 2u } Pws_e;
286 C4_ALWAYS_INLINE
void _pend_none() noexcept
291 C4_ALWAYS_INLINE
void _pend_newl() noexcept
296 C4_ALWAYS_INLINE
void _pend_space() noexcept
301 C4_ALWAYS_INLINE
void _write_pws_and_pend(Pws_e next=_PWS_NONE)
noexcept
303 if(m_pws == _PWS_SPACE)
307 else if(m_pws == _PWS_NEWL)
321 C4_ALWAYS_INLINE Pws_e
next_pws(
size_t col)
const noexcept
329 C4_NODISCARD
bool _maybe_start_flow_pws_ml(
id_type node)
noexcept
331 _RYML_ASSERT_VISIT_(m_tree->callbacks(), m_tree->type(node) & (
FLOW_ML1|
FLOW_MLN), m_tree, node);
332 if(m_flow_pws.active)
335 if(m_opts.force_flow_spc())
337 m_flow_pws.start(ty, m_opts.max_cols());
340 C4_NODISCARD flow_pws _setup_flow_pws_sl(id_type node)
noexcept
343 if(m_flow_pws.active)
349 NodeType ty = m_tree->
type(node);
350 if(m_opts.force_flow_spc())
361 void _emit_yaml(id_type
id);
363 void _visit_stream(id_type
id);
364 void _visit_doc(id_type
id);
365 void _visit_doc_val(id_type
id);
366 void _visit_blck_container(id_type
id);
367 void _visit_flow_container(id_type
id);
369 void _visit_flow_sl(id_type
id);
370 void _visit_flow_sl_seq(id_type
id);
371 void _visit_flow_sl_map(id_type
id);
373 void _visit_flow_ml(id_type
id);
374 void _visit_flow_ml_seq(id_type
id);
375 void _visit_flow_ml_map(id_type
id);
377 void _visit_blck(id_type
id);
378 void _visit_blck_seq(id_type
id);
379 void _visit_blck_map(id_type
id);
381 void _top_open_entry(id_type
id);
382 void _top_close_entry(id_type
id);
383 void _blck_seq_open_entry(id_type
id);
384 void _blck_map_open_entry(id_type
id);
385 void _blck_close_entry(id_type
id);
386 void _blck_write_scalar(csubstr str, type_bits type);
388 void _flow_seq_open_entry(id_type
id);
389 void _flow_map_open_entry(id_type
id);
390 void _flow_close_entry_sl(id_type
id, id_type last_sibling, Pws_e pend_after);
391 void _flow_close_entry_ml(id_type
id, id_type last_sibling, Pws_e pend_after);
392 void _flow_write_scalar(csubstr str, type_bits type);
396 void _json_emit(id_type
id);
397 void _write_scalar_literal(csubstr s, id_type level);
398 void _write_scalar_folded(csubstr s, id_type level);
399 void _write_scalar_squo(csubstr s, id_type level);
400 void _write_scalar_dquo(csubstr s, id_type level);
401 void _write_scalar_plain(csubstr s, id_type level);
403 size_t _write_escaped_newlines(csubstr s,
size_t i);
404 size_t _write_indented_block(csubstr s,
size_t i, id_type level);
408 void _json_visit_ml(id_type
id, id_type depth);
409 void _json_visit_sl(id_type
id, id_type depth);
410 bool _json_maybe_write_naninf(csubstr s);
411 void _json_writek(id_type
id, NodeType ty);
412 void _json_writev(id_type
id, NodeType ty);
413 void _json_write_scalar_dquo(csubstr s);
414 void _json_write_number(csubstr s);
418 void _write_tag(csubstr tag)
420 if(!tag.begins_with(
'!'))
424 void _write_ref(csubstr ref)
428 if(!ref.begins_with(
'*'))
436 C4_ALWAYS_INLINE
void _indent(id_type level)
438 size_t num = (size_t)(2u * level);
439 this->Writer::_do_write(
' ', num);
444 C4_ALWAYS_INLINE
void _write(
const char (&a)[N])
446 this->Writer::_do_write(std::forward<
const char (&)[N]>(a));
449 C4_ALWAYS_INLINE
void _write(csubstr s)
451 this->Writer::_do_write(s);
454 C4_ALWAYS_INLINE
void _write(
char c)
456 this->Writer::_do_write(c);
459 C4_ALWAYS_INLINE
void _write(
char c,
size_t num)
461 this->Writer::_do_write(c, num);
466 C4_ALWAYS_INLINE
void _newl()
468 this->Writer::_do_write(
'\n');
474 Tree
const* C4_RESTRICT m_tree;
484 C4_SUPPRESS_WARNING_GCC_PUSH
485 #if defined(__GNUC__) && (__GNUC__ < 5) && (!defined(__clang__))
487 C4_SUPPRESS_WARNING_GCC_WITH_PUSH(
"-Wparentheses")
492 _styles_block = ((
type_bits)_styles_block_key) | ((type_bits)_styles_block_val),
494 _styles_flow_val = VAL_STYLE & (~((type_bits)_styles_block_val)),
495 _styles_flow = ((
type_bits)_styles_flow_key) | ((type_bits)_styles_flow_val),
502 C4_SUPPRESS_WARNING_GCC_POP
626template<
class OStream>
627inline OStream& operator<< (OStream& s,
Tree const& t)
636template<
class OStream>
689template<
class OStream>
690inline OStream& operator<< (OStream& s,
as_json const& j)
700template<
class OStream>
701inline OStream& operator<< (OStream& s,
as_yaml const& y)
870template<
class CharOwningContainer>
873 size_t startpos = append ? cont->size() : 0u;
874 cont->resize(cont->capacity());
877 if(ret.
str ==
nullptr && ret.
len > 0)
879 cont->resize(startpos + ret.
len);
885 cont->resize(startpos + ret.
len);
890template<
class CharOwningContainer>
900template<
class CharOwningContainer>
903 const size_t startpos = append ? cont->size() : 0u;
904 cont->resize(cont->capacity());
908 if(ret.
str ==
nullptr && ret.
len > 0)
910 cont->resize(startpos + ret.
len);
916 cont->resize(startpos + ret.
len);
921template<
class CharOwningContainer>
929template<
class CharOwningContainer>
932 CharOwningContainer c;
933 emitrs_yaml(t,
id, opts, &c);
937template<
class CharOwningContainer>
940 CharOwningContainer c;
941 emitrs_json(t,
id, opts, &c);
951template<
class CharOwningContainer>
959template<
class CharOwningContainer>
969template<
class CharOwningContainer>
977template<
class CharOwningContainer>
987template<
class CharOwningContainer>
990 CharOwningContainer c;
993 emitrs_yaml(t, t.
root_id(), opts, &c);
997template<
class CharOwningContainer>
1000 CharOwningContainer c;
1003 emitrs_json(t, t.
root_id(), opts, &c);
1014template<
class CharOwningContainer>
1022template<
class CharOwningContainer>
1032template<
class CharOwningContainer>
1040template<
class CharOwningContainer>
1050template<
class CharOwningContainer>
1055 CharOwningContainer c;
1056 emitrs_yaml(*n.
tree(), n.
id(), opts, &c);
1060template<
class CharOwningContainer>
1065 CharOwningContainer c;
1066 emitrs_json(*n.
tree(), n.
id(), opts, &c);
1078#define RYML_DEPRECATE_EMIT \
1079 RYML_DEPRECATED("use emit_yaml() instead. " \
1080 "See https://github.com/biojppm/rapidyaml/issues/120")
1081#define RYML_DEPRECATE_EMITRS \
1082 RYML_DEPRECATED("use emitrs_yaml() instead. " \
1083 "See https://github.com/biojppm/rapidyaml/issues/120")
1089#define RYML_TMP_EMIT_
1093RYML_DEPRECATE_EMIT
inline size_t emit(Tree
const& t, id_type
id, FILE *f)
1097RYML_DEPRECATE_EMIT
inline size_t emit(Tree
const& t, FILE *f=
nullptr)
1101RYML_DEPRECATE_EMIT
inline size_t emit(ConstNodeRef
const& r, FILE *f=
nullptr)
1106RYML_DEPRECATE_EMIT
inline substr emit(Tree
const& t, id_type
id, substr buf,
bool error_on_excess=
true)
1108 return emit_yaml(t,
id, buf, error_on_excess);
1110RYML_DEPRECATE_EMIT
inline substr emit(Tree
const& t, substr buf,
bool error_on_excess=
true)
1112 return emit_yaml(t, buf, error_on_excess);
1114RYML_DEPRECATE_EMIT
inline substr emit(ConstNodeRef
const& r, substr buf,
bool error_on_excess=
true)
1116 return emit_yaml(r, buf, error_on_excess);
1119#ifdef RYML_TMP_EMIT_
1121#undef RYML_TMP_EMIT_
1124template<
class CharOwningContainer>
1125RYML_DEPRECATE_EMITRS
substr emitrs(Tree
const& t, id_type
id, CharOwningContainer * cont)
1129template<
class CharOwningContainer>
1130RYML_DEPRECATE_EMITRS CharOwningContainer emitrs(Tree
const& t, id_type
id)
1132 return emitrs_yaml<CharOwningContainer>(t,
id);
1134template<
class CharOwningContainer>
1135RYML_DEPRECATE_EMITRS
substr emitrs(Tree
const& t, CharOwningContainer * cont)
1139template<
class CharOwningContainer>
1140RYML_DEPRECATE_EMITRS CharOwningContainer emitrs(Tree
const& t)
1142 return emitrs_yaml<CharOwningContainer>(t);
1144template<
class CharOwningContainer>
1145RYML_DEPRECATE_EMITRS
substr emitrs(ConstNodeRef
const& n, CharOwningContainer * cont)
1149template<
class CharOwningContainer>
1150RYML_DEPRECATE_EMITRS CharOwningContainer emitrs(ConstNodeRef
const& n)
1152 return emitrs_yaml<CharOwningContainer>(n);
1162C4_SUPPRESS_WARNING_GCC_CLANG_POP
1164#undef RYML_DEPRECATE_EMIT
1165#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
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<< .