rapidyaml 0.15.2
parse and emit YAML, and do it fast
Loading...
Searching...
No Matches
emit.hpp
Go to the documentation of this file.
1#ifndef _C4_YML_EMIT_HPP_
2#define _C4_YML_EMIT_HPP_
3
4/** @file emit.hpp Utilities to emit YAML and JSON. */
5
6#ifndef _C4_YML_WRITER_HPP_
7#include "./writer.hpp"
8#endif
9
10#ifndef _C4_YML_TREE_HPP_
11#include "./tree.hpp"
12#endif
13
14#ifndef _C4_YML_NODE_HPP_
15#include "./node.hpp"
16#endif
17
18
19C4_SUPPRESS_WARNING_GCC_CLANG_WITH_PUSH("-Wold-style-cast")
20// NOLINTBEGIN(modernize-avoid-c-style-cast)
21
22
23//-----------------------------------------------------------------------------
24//-----------------------------------------------------------------------------
25//-----------------------------------------------------------------------------
26
27namespace c4 {
28namespace yml {
29
30/** @addtogroup doc_emit
31 *
32 * @{
33 */
34
35// fwd declarations
36template<class Writer> class Emitter;
37template<class OStream>
41
42
43//-----------------------------------------------------------------------------
44//-----------------------------------------------------------------------------
45//-----------------------------------------------------------------------------
46
47/** Specifies the type of content to emit */
48typedef enum { // NOLINT
49 EMIT_YAML = 0, ///< emit YAML
50 EMIT_JSON = 1, ///< emit JSON
51} EmitType_e;
52
53
54//-----------------------------------------------------------------------------
55//-----------------------------------------------------------------------------
56//-----------------------------------------------------------------------------
57
58/** A lightweight object containing options to be used when emitting. */
60{
61public:
62
63 /** @cond dev */
64 typedef enum : uint32_t { // NOLINT
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,
75 } Flags_e;
76 /** @endcond */
77
78private:
79
80 EmitOptions& set_flags_(bool enabled, Flags_e f)
81 {
82 if(enabled)
83 m_flags |= f;
84 else
85 m_flags &= ~f;
86 return *this;
87 }
88
89public:
90
91 /** @name flow customization
92 *
93 * @{ */
94
95 /** Indent the contents of @ref FLOW_ML1 and @ref FLOW_MLN
96 * containers. Enabled by default. */
97 C4_ALWAYS_INLINE bool indent_flow_ml() const noexcept { return (m_flags & INDENT_FLOW_ML) != 0; }
98 EmitOptions& indent_flow_ml(bool enabled) noexcept { return set_flags_(enabled, INDENT_FLOW_ML); }
99
100 /** Force everywhere a space after comma in flow mode, overriding
101 * the @ref FLOW_SPC status of individual containers. This only
102 * applies to @ref FLOW_ML1 or @ref FLOW_MLN containers. Disabled
103 * by default. */
104 EmitOptions& force_flow_spc(bool enabled) noexcept { return set_flags_(enabled, FORCE_FLOW_SPC); }
105 C4_ALWAYS_INLINE bool force_flow_spc() const noexcept { return (m_flags & FORCE_FLOW_SPC) != 0; }
106
107 /** Set max columns for the emitted YAML in @ref FLOW_MLN
108 * mode. This will make the emitted YAML wrap around when the line
109 * reaches max cols, but only in containers with @ref FLOW_MLN
110 * mode. Defaults to 80 columns. */
111 EmitOptions& max_cols(id_type cols) noexcept { m_max_cols = cols; return *this; }
112 C4_ALWAYS_INLINE id_type max_cols() const noexcept { return m_max_cols; }
113 static constexpr const id_type max_cols_default = 80;
114
115 /** @} */
116
117public:
118
119 /** @name option flags - control emission of non-root (nested) nodes
120 *
121 * @{ */
122
123 /** When emit starts on a node which is not the root node, emit
124 * the node key as well. This will make the resuling YAML a map
125 * with the node as its single element. Enabled by default. */
126 EmitOptions& emit_nonroot_key(bool enabled) noexcept { return set_flags_(enabled, EMIT_NONROOT_KEY); }
127 C4_ALWAYS_INLINE bool emit_nonroot_key() const noexcept { return (m_flags & EMIT_NONROOT_KEY) != 0; }
128
129 /** When emit starts on a node which is not the root node, emit a
130 * leading dash. This will make the resulting YAML a seq with the
131 * node as its single element. Disabled by default. */
132 EmitOptions& emit_nonroot_dash(bool enabled) noexcept { return set_flags_(enabled, EMIT_NONROOT_DASH); }
133 C4_ALWAYS_INLINE bool emit_nonroot_dash() const noexcept { return (m_flags & EMIT_NONROOT_DASH) != 0; }
134
135 /** @} */
136
137public:
138
139 /** @name option flags - json behavior
140 *
141 * @{ */
142
143 /** Whether to trigger an error when findind a stream
144 * in json mode. Disabled by default. */
145 EmitOptions& json_err_on_stream(bool enabled) noexcept { return set_flags_(enabled, JSON_ERR_ON_STREAM); }
146 C4_ALWAYS_INLINE bool json_err_on_stream() const noexcept { return (m_flags & JSON_ERR_ON_STREAM) != 0; }
147
148 /** Whether to trigger an error (or ignore the tag) when finding a tag
149 * in json mode. Disabled by default. */
150 EmitOptions& json_err_on_tag(bool enabled) noexcept { return set_flags_(enabled, JSON_ERR_ON_TAG); }
151 C4_ALWAYS_INLINE bool json_err_on_tag() const noexcept { return (m_flags & JSON_ERR_ON_TAG) != 0; }
152
153 /** Whether to trigger an error (or ignore the anchor) when finding an
154 * anchor in json mode. Disabled by default. */
155 EmitOptions& json_err_on_anchor(bool enabled) noexcept { return set_flags_(enabled, JSON_ERR_ON_ANCHOR); }
156 C4_ALWAYS_INLINE bool json_err_on_anchor() const noexcept { return (m_flags & JSON_ERR_ON_ANCHOR) != 0; }
157
158 /** @cond dev */
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; }
161 /** @endcond */
162
163 /** @} */
164
165public:
166
167 /** @name maximum depth for the emitted tree
168 *
169 * This prevents stack overflows by making the emitter fail when
170 * the tree exceeds the maximum depth.
171 *
172 * @{ */
173 C4_ALWAYS_INLINE id_type max_depth() const noexcept { return m_max_depth; }
174 EmitOptions& max_depth(id_type d) noexcept { m_max_depth = d; return *this; }
175 static constexpr const id_type max_depth_default = 64;
176 /** @} */
177
178public:
179
180 bool operator== (const EmitOptions& that) const noexcept
181 {
182 return m_max_depth == that.m_max_depth &&
183 m_flags == that.m_flags;
184 }
185
186private:
187
188 /** @cond dev */
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};
192 /** @endcond */
193};
194
195
196//-----------------------------------------------------------------------------
197//-----------------------------------------------------------------------------
198//-----------------------------------------------------------------------------
199
200/** A stateful emitter, for use with a writer such as @ref WriterBuf,
201 * @ref WriterFile, or @ref WriterOStream */
202template<class Writer>
203class Emitter : public Writer
204{
205public:
206
207 /** Construct the emitter and its internal Writer state.
208 *
209 * @param opts @ref EmitOptions
210 * @param args arguments to be forwarded to the constructor of the writer.
211 */
212 template<class ...WriterArgs>
213 Emitter(EmitOptions const& opts, WriterArgs &&...args)
214 : Writer(std::forward<WriterArgs>(args)...)
215 , m_tree()
216 , m_opts(opts)
217 , m_col()
218 , m_depth()
219 , m_ilevel()
220 , m_pws()
221 , m_flow_pws()
222 {}
223
224 /** Construct the emitter and its internal Writer state, using default emit options.
225 * @param args arguments to be forwarded to the constructor of the writer.
226 */
227 template<class ...WriterArgs>
228 Emitter(WriterArgs &&...args)
229 : Writer(std::forward<WriterArgs>(args)...)
230 , m_tree()
231 , m_opts()
232 , m_col()
233 , m_depth()
234 , m_ilevel()
235 , m_pws()
236 , m_flow_pws()
237 {}
238
239public:
240
241 /** emit!
242 *
243 * When writing to a buffer, returns a substr of the emitted YAML.
244 * If the given buffer has insufficient space, the returned substr
245 * will be null and its size will be the needed space. Whatever
246 * the size of the buffer, it is guaranteed that no writes are
247 * done past its end.
248 *
249 * When writing to a file, the returned substr will be null, but its
250 * length will be set to the number of bytes written.
251 *
252 * @param type specify what to emit (YAML or JSON)
253 * @param t the tree to emit
254 * @param id the id of the node to emit
255 * @param error_on_excess when true, an error is raised when the
256 * output buffer is too small for the emitted YAML/JSON
257 * */
258 substr emit_as(EmitType_e type, Tree const& t, id_type id, bool error_on_excess);
259 /** emit starting at the root node */
260 substr emit_as(EmitType_e type, Tree const& t, bool error_on_excess=true)
261 {
262 if(t.empty())
263 return {};
264 return this->emit_as(type, t, t.root_id(), error_on_excess);
265 }
266 /** emit starting at the given node */
267 substr emit_as(EmitType_e type, ConstNodeRef const& n, bool error_on_excess=true)
268 {
269 if(!n.readable())
270 return {};
271 return this->emit_as(type, *n.tree(), n.id(), error_on_excess);
272 }
273
274public:
275
276 /** get the emit options for this object */
277 EmitOptions const& options() const noexcept { return m_opts; }
278 /** set the emit options for this object */
279 void options(EmitOptions opts) noexcept { m_opts = opts; }
280
281 /** set the max depth for emitted trees (to prevent a stack overflow) */
282 void max_depth(id_type max_depth) noexcept { m_opts.max_depth(max_depth); }
283 /** get the max depth for emitted trees (to prevent a stack overflow) */
284 id_type max_depth() const noexcept { return m_opts.max_depth(); }
285
286private: // pending whitespace
287
288 /// pending whitespace
289 typedef enum : uint32_t { _PWS_NONE = 0u, _PWS_SPACE = 1u, _PWS_NEWL = 2u } Pws_e; // NOLINT
290
291 /// set pending whitespace, ignoring pending
292 C4_ALWAYS_INLINE void _pend_none() noexcept
293 {
294 m_pws = _PWS_NONE;
295 }
296 /// set pending whitespace, ignoring pending
297 C4_ALWAYS_INLINE void _pend_newl() noexcept
298 {
299 m_pws = _PWS_NEWL;
300 }
301 /// set pending whitespace, ignoring pending
302 C4_ALWAYS_INLINE void _pend_space() noexcept
303 {
304 m_pws = _PWS_SPACE;
305 }
306 /// write pending whitespace, and then set the next pending whitespace
307 C4_ALWAYS_INLINE void _write_pws_and_pend(Pws_e next=_PWS_NONE) noexcept
308 {
309 if(m_pws == _PWS_SPACE)
310 {
311 _write(' ');
312 }
313 else if(m_pws == _PWS_NEWL)
314 {
315 _newl();
316 _indent(m_ilevel);
317 }
318 m_pws = next;
319 }
320
321 /// specs for obtaining pending whitespace in flow mode
322 struct flow_pws
323 {
324 size_t max_cols = 0; // leave this member first to avoid padding
325 Pws_e pend_after_comma = _PWS_NONE;
326 bool active = false;
327 C4_ALWAYS_INLINE Pws_e next_pws(size_t col) const noexcept
328 {
329 return (active && col >= max_cols) ? _PWS_NEWL : pend_after_comma;
330 }
331 void start(NodeType ty, size_t max_cols_) noexcept;
332 void stop() noexcept { active = false; }
333 };
334
335 C4_NODISCARD bool _maybe_start_flow_pws_ml(id_type node) noexcept
336 {
337 _RYML_ASSERT_VISIT_(m_tree->callbacks(), m_tree->type(node) & (FLOW_ML1|FLOW_MLN), m_tree, node);
338 if(m_flow_pws.active)
339 return false;
340 NodeType ty = m_tree->type(node);
341 if(m_opts.force_flow_spc())
342 ty |= FLOW_SPC;
343 m_flow_pws.start(ty, m_opts.max_cols());
344 return true;
345 }
346 C4_NODISCARD flow_pws _setup_flow_pws_sl(id_type node) noexcept
347 {
348 flow_pws ret = {};
349 if(m_flow_pws.active)
350 {
351 ret = m_flow_pws;
352 }
353 else
354 {
355 NodeType ty = m_tree->type(node);
356 if(m_opts.force_flow_spc())
357 ty |= FLOW_SPC;
358 ret.start(ty, 0);
359 }
360 return ret;
361 }
362
363private:
364
365 /** @cond dev */
366
367 void _emit_yaml(id_type id);
368
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);
374
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);
378
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);
382
383 void _visit_blck(id_type id);
384 void _visit_blck_seq(id_type id);
385 void _visit_blck_map(id_type id);
386
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);
393
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);
399
400private:
401
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);
408
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);
411
412private:
413
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);
421
422private:
423
424 void _write_tag(csubstr tag)
425 {
426 if(!tag.begins_with('!'))
427 _write('!');
428 _write(tag);
429 }
430 void _write_ref(csubstr ref)
431 {
432 if(ref != "<<")
433 {
434 if(!ref.begins_with('*'))
435 _write('*');
436 _write(ref);
437 }
438 }
439
440private:
441
442 C4_ALWAYS_INLINE void _indent(id_type level)
443 {
444 size_t num = (size_t)(2u * level);
445 this->Writer::_do_write(' ', num);
446 m_col += num;
447 }
448
449 template<size_t N>
450 C4_ALWAYS_INLINE void _write(const char (&a)[N])
451 {
452 this->Writer::_do_write(std::forward<const char (&)[N]>(a));
453 m_col += N-1;
454 }
455 C4_ALWAYS_INLINE void _write(csubstr s)
456 {
457 this->Writer::_do_write(s);
458 m_col += s.len;
459 }
460 C4_ALWAYS_INLINE void _write(char c)
461 {
462 this->Writer::_do_write(c);
463 ++m_col;
464 }
465 C4_ALWAYS_INLINE void _write(char c, size_t num)
466 {
467 this->Writer::_do_write(c, num);
468 m_col += num;
469 }
470
471 /// write a newline and reset the column
472 C4_ALWAYS_INLINE void _newl()
473 {
474 this->Writer::_do_write('\n');
475 m_col = 0;
476 }
477
478private:
479
480 Tree const* C4_RESTRICT m_tree;
481 EmitOptions m_opts;
482 size_t m_col;
483 id_type m_depth;
484 id_type m_ilevel;
485 Pws_e m_pws;
486 flow_pws m_flow_pws;
487
488private:
489
490 C4_SUPPRESS_WARNING_GCC_PUSH
491 #if defined(__GNUC__) && (__GNUC__ < 5) && (!defined(__clang__))
492 // g++-4.x has problems with the operand types here...
493 C4_SUPPRESS_WARNING_GCC_WITH_PUSH("-Wparentheses")
494 #endif
495 enum : type_bits { // NOLINT
496 _styles_block_key = KEY_LITERAL|KEY_FOLDED,
497 _styles_block_val = VAL_LITERAL|VAL_FOLDED,
498 _styles_block = ((type_bits)_styles_block_key) | ((type_bits)_styles_block_val),
499 _styles_flow_key = KEY_STYLE & (~((type_bits)_styles_block_key)),
500 _styles_flow_val = VAL_STYLE & (~((type_bits)_styles_block_val)),
501 _styles_flow = ((type_bits)_styles_flow_key) | ((type_bits)_styles_flow_val),
502 _styles_squo = KEY_SQUO|VAL_SQUO,
503 _styles_dquo = KEY_DQUO|VAL_DQUO,
504 _styles_plain = KEY_PLAIN|VAL_PLAIN,
505 _styles_literal = KEY_LITERAL|VAL_LITERAL,
506 _styles_folded = KEY_FOLDED|VAL_FOLDED,
507 };
508 C4_SUPPRESS_WARNING_GCC_POP
509
510 /** @endcond */
511};
512
513
514//-----------------------------------------------------------------------------
515//-----------------------------------------------------------------------------
516//-----------------------------------------------------------------------------
517
518/** @defgroup doc_emit_to_file Emit to file
519 *
520 * @{
521 */
522
523
524// emit from tree and node id -----------------------
525
526/** (1) emit YAML to the given file, starting at the given node. A null
527 * file defaults to stdout. Return the number of bytes written. */
528inline size_t emit_yaml(Tree const& t, id_type id, EmitOptions const& opts, FILE *f)
529{
530 EmitterFile em(opts, f);
531 return em.emit_as(EMIT_YAML, t, id, /*error_on_excess*/true).len;
532}
533/** (2) like (1), but use default emit options */
534inline size_t emit_yaml(Tree const& t, id_type id, FILE *f)
535{
536 EmitterFile em(f);
537 return em.emit_as(EMIT_YAML, t, id, /*error_on_excess*/true).len;
538}
539/** (1) emit JSON to the given file, starting at the given node. A null
540 * file defaults to stdout. Return the number of bytes written. */
541inline size_t emit_json(Tree const& t, id_type id, EmitOptions const& opts, FILE *f)
542{
543 EmitterFile em(opts, f);
544 return em.emit_as(EMIT_JSON, t, id, /*error_on_excess*/true).len;
545}
546/** (2) like (1), but use default emit options */
547inline size_t emit_json(Tree const& t, id_type id, FILE *f)
548{
549 EmitterFile em(f);
550 return em.emit_as(EMIT_JSON, t, id, /*error_on_excess*/true).len;
551}
552
553
554// emit from root -------------------------
555
556/** (1) emit YAML to the given file, starting at the root node. A null file defaults to stdout.
557 * Return the number of bytes written. */
558inline size_t emit_yaml(Tree const& t, EmitOptions const& opts, FILE *f=nullptr)
559{
560 EmitterFile em(opts, f);
561 return em.emit_as(EMIT_YAML, t, /*error_on_excess*/true).len;
562}
563/** (2) like (1), but use default emit options */
564inline size_t emit_yaml(Tree const& t, FILE *f=nullptr)
565{
566 EmitterFile em(f);
567 return em.emit_as(EMIT_YAML, t, /*error_on_excess*/true).len;
568}
569/** (1) emit JSON to the given file. A null file defaults to stdout.
570 * Return the number of bytes written. */
571inline size_t emit_json(Tree const& t, EmitOptions const& opts, FILE *f=nullptr)
572{
573 EmitterFile em(opts, f);
574 return em.emit_as(EMIT_JSON, t, /*error_on_excess*/true).len;
575}
576/** (2) like (1), but use default emit options */
577inline size_t emit_json(Tree const& t, FILE *f=nullptr)
578{
579 EmitterFile em(f);
580 return em.emit_as(EMIT_JSON, t, /*error_on_excess*/true).len;
581}
582
583
584// emit from ConstNodeRef ------------------------
585
586/** (1) emit YAML to the given file. A null file defaults to stdout.
587 * Return the number of bytes written. */
588inline size_t emit_yaml(ConstNodeRef const& r, EmitOptions const& opts, FILE *f=nullptr)
589{
590 if(!r.readable())
591 return {};
592 EmitterFile em(opts, f);
593 return em.emit_as(EMIT_YAML, r, /*error_on_excess*/true).len;
594}
595/** (2) like (1), but use default emit options */
596inline size_t emit_yaml(ConstNodeRef const& r, FILE *f=nullptr)
597{
598 if(!r.readable())
599 return {};
600 EmitterFile em(f);
601 return em.emit_as(EMIT_YAML, r, /*error_on_excess*/true).len;
602}
603/** (1) emit JSON to the given file. A null file defaults to stdout.
604 * Return the number of bytes written. */
605inline size_t emit_json(ConstNodeRef const& r, EmitOptions const& opts, FILE *f=nullptr)
606{
607 if(!r.readable())
608 return {};
609 EmitterFile em(opts, f);
610 return em.emit_as(EMIT_JSON, r, /*error_on_excess*/true).len;
611}
612/** (2) like (1), but use default emit options */
613inline size_t emit_json(ConstNodeRef const& r, FILE *f=nullptr)
614{
615 if(!r.readable())
616 return {};
617 EmitterFile em(f);
618 return em.emit_as(EMIT_JSON, r, /*error_on_excess*/true).len;
619}
620
621/** @} */
622
623
624//-----------------------------------------------------------------------------
625
626/** @defgroup doc_emit_to_ostream Emit to an STL-like ostream
627 *
628 * @{
629 */
630
631/** emit YAML to an STL-like ostream */
632template<class OStream>
633inline OStream& operator<< (OStream& s, Tree const& t)
634{
636 em.emit_as(EMIT_YAML, t);
637 return s;
638}
639
640/** emit YAML to an STL-like ostream
641 * @overload */
642template<class OStream>
643inline OStream& operator<< (OStream& s, ConstNodeRef const& n)
644{
645 if(!n.readable())
646 return s;
648 em.emit_as(EMIT_YAML, n);
649 return s;
650}
651
652/** mark a tree or node to be emitted as yaml when using @ref
653 * operator<<, with options. For example:
654 *
655 * ```cpp
656 * Tree t = parse_in_arena("{foo: bar}");
657 * std::cout << t; // emits YAML
658 * std::cout << as_yaml(t); // emits YAML, same as above
659 * std::cout << as_yaml(t, EmitOptions().max_depth(10)); // emits JSON with a max tree depth
660 * ```
661 *
662 * @see @ref operator<< */
664{
665 Tree const* tree;
668 as_json(Tree const& t, EmitOptions const& opts={}) : tree(&t), node(t.empty() ? NONE : t.root_id()), options(opts) {}
669 as_json(Tree const& t, id_type id, EmitOptions const& opts={}) : tree(&t), node(id), options(opts) {}
670 as_json(ConstNodeRef const& n, EmitOptions const& opts={}) : tree(n.tree()), node(n.id()), options(opts) {}
671};
672
673/** mark a tree or node to be emitted as yaml when using @ref
674 * operator<< . For example:
675 *
676 * ```cpp
677 * Tree t = parse_in_arena("{foo: bar}");
678 * std::cout << t; // emits YAML
679 * std::cout << as_json(t); // emits JSON
680 * std::cout << as_json(t, EmitOptions().max_depth(10)); // emits JSON with a max tree depth
681 * ```
682 *
683 * @see @ref operator<< */
685{
686 Tree const* tree;
689 as_yaml(Tree const& t, EmitOptions const& opts={}) : tree(&t), node(t.empty() ? NONE : t.root_id()), options(opts) {}
690 as_yaml(Tree const& t, id_type id, EmitOptions const& opts={}) : tree(&t), node(id), options(opts) {}
691 as_yaml(ConstNodeRef const& n, EmitOptions const& opts={}) : tree(n.tree()), node(n.id()), options(opts) {}
692};
693
694/** emit json to an STL-like stream */
695template<class OStream>
696inline OStream& operator<< (OStream& s, as_json const& j)
697{
698 if(!j.tree || j.tree->empty())
699 return s;
701 em.emit_as(EMIT_JSON, *j.tree, j.node != NONE ? j.node : j.tree->root_id(), true);
702 return s;
703}
704
705/** emit yaml to an STL-like stream */
706template<class OStream>
707inline OStream& operator<< (OStream& s, as_yaml const& y)
708{
709 if(!y.tree || y.tree->empty())
710 return s;
712 em.emit_as(EMIT_YAML, *y.tree, y.node != NONE ? y.node : y.tree->root_id(), true);
713 return s;
714}
715
716/** @} */
717
718
719//-----------------------------------------------------------------------------
720
721/** @defgroup doc_emit_to_buffer Emit to memory buffer
722 *
723 * @{
724 */
725
726// emit from tree and node id -----------------------
727
728/** (1) emit YAML to the given buffer. Return a substr trimmed to the emitted YAML.
729 * @param t the tree to emit.
730 * @param id the node where to start emitting.
731 * @param opts emit options.
732 * @param buf the output buffer.
733 * @param error_on_excess Raise an error if the space in the buffer is insufficient.
734 * @return a substr trimmed to the result in the output buffer. If the buffer is
735 * insufficient (when error_on_excess is false), the string pointer of the
736 * result will be set to null, and the length will report the required buffer size. */
737inline substr emit_yaml(Tree const& t, id_type id, EmitOptions const& opts, substr buf, bool error_on_excess=true)
738{
739 EmitterBuf em(opts, buf);
740 return em.emit_as(EMIT_YAML, t, id, error_on_excess);
741}
742/** (2) like (1), but use default emit options */
743inline substr emit_yaml(Tree const& t, id_type id, substr buf, bool error_on_excess=true)
744{
745 EmitterBuf em(buf);
746 return em.emit_as(EMIT_YAML, t, id, error_on_excess);
747}
748/** (1) emit JSON to the given buffer. Return a substr trimmed to the emitted JSON.
749 * @param t the tree to emit.
750 * @param id the node where to start emitting.
751 * @param opts emit options.
752 * @param buf the output buffer.
753 * @param error_on_excess Raise an error if the space in the buffer is insufficient.
754 * @return a substr trimmed to the result in the output buffer. If the buffer is
755 * insufficient (when error_on_excess is false), the string pointer of the
756 * result will be set to null, and the length will report the required buffer size. */
757inline substr emit_json(Tree const& t, id_type id, EmitOptions const& opts, substr buf, bool error_on_excess=true)
758{
759 EmitterBuf em(opts, buf);
760 return em.emit_as(EMIT_JSON, t, id, error_on_excess);
761}
762/** (2) like (1), but use default emit options */
763inline substr emit_json(Tree const& t, id_type id, substr buf, bool error_on_excess=true)
764{
765 EmitterBuf em(buf);
766 return em.emit_as(EMIT_JSON, t, id, error_on_excess);
767}
768
769
770// emit from root -------------------------
771
772/** (1) emit YAML to the given buffer. Return a substr trimmed to the emitted YAML.
773 * @param t the tree; will be emitted from the root node.
774 * @param opts emit options.
775 * @param buf the output buffer.
776 * @param error_on_excess Raise an error if the space in the buffer is insufficient.
777 * @return a substr trimmed to the result in the output buffer. If the buffer is
778 * insufficient (when error_on_excess is false), the string pointer of the
779 * result will be set to null, and the length will report the required buffer size. */
780inline substr emit_yaml(Tree const& t, EmitOptions const& opts, substr buf, bool error_on_excess=true)
781{
782 EmitterBuf em(opts, buf);
783 return em.emit_as(EMIT_YAML, t, error_on_excess);
784}
785/** (2) like (1), but use default emit options */
786inline substr emit_yaml(Tree const& t, substr buf, bool error_on_excess=true)
787{
788 EmitterBuf em(buf);
789 return em.emit_as(EMIT_YAML, t, error_on_excess);
790}
791/** (1) emit JSON to the given buffer. Return a substr trimmed to the emitted JSON.
792 * @param t the tree; will be emitted from the root node.
793 * @param opts emit options.
794 * @param buf the output buffer.
795 * @param error_on_excess Raise an error if the space in the buffer is insufficient.
796 * @return a substr trimmed to the result in the output buffer. If the buffer is
797 * insufficient (when error_on_excess is false), the string pointer of the
798 * result will be set to null, and the length will report the required buffer size. */
799inline substr emit_json(Tree const& t, EmitOptions const& opts, substr buf, bool error_on_excess=true)
800{
801 EmitterBuf em(opts, buf);
802 return em.emit_as(EMIT_JSON, t, error_on_excess);
803}
804/** (2) like (1), but use default emit options */
805inline substr emit_json(Tree const& t, substr buf, bool error_on_excess=true)
806{
807 EmitterBuf em(buf);
808 return em.emit_as(EMIT_JSON, t, error_on_excess);
809}
810
811
812// emit from ConstNodeRef ------------------------
813
814/** (1) emit YAML to the given buffer. Return a substr trimmed to the emitted YAML.
815 * @param r the starting node.
816 * @param buf the output buffer.
817 * @param opts emit options.
818 * @param error_on_excess Raise an error if the space in the buffer is insufficient.
819 * @return a substr trimmed to the result in the output buffer. If the buffer is
820 * insufficient (when error_on_excess is false), the string pointer of the
821 * result will be set to null, and the length will report the required buffer size. */
822inline substr emit_yaml(ConstNodeRef const& r, EmitOptions const& opts, substr buf, bool error_on_excess=true)
823{
824 if(!r.readable())
825 return {};
826 EmitterBuf em(opts, buf);
827 return em.emit_as(EMIT_YAML, r, error_on_excess);
828}
829/** (2) like (1), but use default emit options */
830inline substr emit_yaml(ConstNodeRef const& r, substr buf, bool error_on_excess=true)
831{
832 if(!r.readable())
833 return {};
834 EmitterBuf em(buf);
835 return em.emit_as(EMIT_YAML, r, error_on_excess);
836}
837/** (1) emit JSON to the given buffer. Return a substr trimmed to the emitted JSON.
838 * @param r the starting node.
839 * @param buf the output buffer.
840 * @param opts emit options.
841 * @param error_on_excess Raise an error if the space in the buffer is insufficient.
842 * @return a substr trimmed to the result in the output buffer. If the buffer is
843 * insufficient (when error_on_excess is false), the string pointer of the
844 * result will be set to null, and the length will report the required buffer size. */
845inline substr emit_json(ConstNodeRef const& r, EmitOptions const& opts, substr buf, bool error_on_excess=true)
846{
847 if(!r.readable())
848 return {};
849 EmitterBuf em(opts, buf);
850 return em.emit_as(EMIT_JSON, r, error_on_excess);
851}
852/** (2) like (1), but use default emit options */
853inline substr emit_json(ConstNodeRef const& r, substr buf, bool error_on_excess=true)
854{
855 if(!r.readable())
856 return {};
857 EmitterBuf em(buf);
858 return em.emit_as(EMIT_JSON, r, error_on_excess);
859}
860
861
862//-----------------------------------------------------------------------------
863
864/** @defgroup doc_emit_to_container Emit to resizeable container
865 *
866 * @{
867 */
868
869// emit from tree and node id ---------------------------
870
871/** (1) emit+resize: emit YAML to the given `std::string`/`std::vector`-like
872 * container, resizing it as needed to fit the emitted YAML. If @p append is
873 * set to true, the emitted YAML is appended at the end of the container.
874 *
875 * @return a substr trimmed to the emitted YAML (excluding the initial contents, when appending) */
876template<class CharOwningContainer>
877substr emitrs_yaml(Tree const& t, id_type id, EmitOptions const& opts, CharOwningContainer * cont, bool append=false)
878{
879 size_t startpos = append ? cont->size() : 0u;
880 cont->resize(cont->capacity()); // otherwise the first emit would be certain to fail
881 substr buf = to_substr(*cont).sub(startpos);
882 substr ret = emit_yaml(t, id, opts, buf, /*error_on_excess*/false);
883 if(ret.str == nullptr && ret.len > 0)
884 {
885 cont->resize(startpos + ret.len);
886 buf = to_substr(*cont).sub(startpos);
887 ret = emit_yaml(t, id, opts, buf, /*error_on_excess*/true);
888 }
889 else
890 {
891 cont->resize(startpos + ret.len);
892 }
893 return ret;
894}
895/** (2) like (1), but use default emit options */
896template<class CharOwningContainer>
897substr emitrs_yaml(Tree const& t, id_type id, CharOwningContainer * cont, bool append=false)
898{
899 return emitrs_yaml(t, id, EmitOptions{}, cont, append);
900}
901/** (1) emit+resize: emit JSON to the given `std::string`/`std::vector`-like
902 * container, resizing it as needed to fit the emitted JSON. If @p append is
903 * set to true, the emitted YAML is appended at the end of the container.
904 *
905 * @return a substr trimmed to the emitted JSON (excluding the initial contents, when appending) */
906template<class CharOwningContainer>
907substr emitrs_json(Tree const& t, id_type id, EmitOptions const& opts, CharOwningContainer * cont, bool append=false)
908{
909 const size_t startpos = append ? cont->size() : 0u;
910 cont->resize(cont->capacity()); // otherwise the first emit would be certain to fail
911 substr buf = to_substr(*cont).sub(startpos);
912 EmitterBuf em(opts, buf);
913 substr ret = emit_json(t, id, opts, buf, /*error_on_excess*/false);
914 if(ret.str == nullptr && ret.len > 0)
915 {
916 cont->resize(startpos + ret.len);
917 buf = to_substr(*cont).sub(startpos);
918 ret = emit_json(t, id, opts, buf, /*error_on_excess*/true);
919 }
920 else
921 {
922 cont->resize(startpos + ret.len);
923 }
924 return ret;
925}
926/** (2) like (1), but use default emit options */
927template<class CharOwningContainer>
928substr emitrs_json(Tree const& t, id_type id, CharOwningContainer * cont, bool append=false)
929{
930 return emitrs_json(t, id, EmitOptions{}, cont, append);
931}
932
933
934/** (3) emit+resize: YAML to a newly-created `std::string`/`std::vector`-like container. */
935template<class CharOwningContainer>
936CharOwningContainer emitrs_yaml(Tree const& t, id_type id, EmitOptions const& opts={})
937{
938 CharOwningContainer c;
939 emitrs_yaml(t, id, opts, &c);
940 return c;
941}
942/** (3) emit+resize: JSON to a newly-created `std::string`/`std::vector`-like container. */
943template<class CharOwningContainer>
944CharOwningContainer emitrs_json(Tree const& t, id_type id, EmitOptions const& opts={})
945{
946 CharOwningContainer c;
947 emitrs_json(t, id, opts, &c);
948 return c;
949}
950
951
952// emit from root -------------------------
953
954/** (1) emit+resize: YAML to the given `std::string`/`std::vector`-like
955 * container, resizing it as needed to fit the emitted YAML.
956 * @return a substr trimmed to the new emitted contents. */
957template<class CharOwningContainer>
958substr emitrs_yaml(Tree const& t, EmitOptions const& opts, CharOwningContainer * cont, bool append=false)
959{
960 if(t.empty())
961 return {};
962 return emitrs_yaml(t, t.root_id(), opts, cont, append);
963}
964/** (2) like (1), but use default emit options */
965template<class CharOwningContainer>
966substr emitrs_yaml(Tree const& t, CharOwningContainer * cont, bool append=false)
967{
968 if(t.empty())
969 return {};
970 return emitrs_yaml(t, t.root_id(), EmitOptions{}, cont, append);
971}
972/** (1) emit+resize: JSON to the given `std::string`/`std::vector`-like
973 * container, resizing it as needed to fit the emitted JSON.
974 * @return a substr trimmed to the new emitted contents. */
975template<class CharOwningContainer>
976substr emitrs_json(Tree const& t, EmitOptions const& opts, CharOwningContainer * cont, bool append=false)
977{
978 if(t.empty())
979 return {};
980 return emitrs_json(t, t.root_id(), opts, cont, append);
981}
982/** (2) like (1), but use default emit options */
983template<class CharOwningContainer>
984substr emitrs_json(Tree const& t, CharOwningContainer * cont, bool append=false)
985{
986 if(t.empty())
987 return {};
988 return emitrs_json(t, t.root_id(), EmitOptions{}, cont, append);
989}
990
991
992/** (3) emit+resize: YAML to a newly-created `std::string`/`std::vector`-like container. */
993template<class CharOwningContainer>
994CharOwningContainer emitrs_yaml(Tree const& t, EmitOptions const& opts={})
995{
996 CharOwningContainer c;
997 if(t.empty())
998 return c;
999 emitrs_yaml(t, t.root_id(), opts, &c);
1000 return c;
1001}
1002/** (3) emit+resize: JSON to a newly-created `std::string`/`std::vector`-like container. */
1003template<class CharOwningContainer>
1004CharOwningContainer emitrs_json(Tree const& t, EmitOptions const& opts={})
1005{
1006 CharOwningContainer c;
1007 if(t.empty())
1008 return c;
1009 emitrs_json(t, t.root_id(), opts, &c);
1010 return c;
1011}
1012
1013
1014// emit from ConstNodeRef ------------------------
1015
1016
1017/** (1) emit+resize: YAML to the given `std::string`/`std::vector`-like container,
1018 * resizing it as needed to fit the emitted YAML.
1019 * @return a substr trimmed to the new emitted contents */
1020template<class CharOwningContainer>
1021substr emitrs_yaml(ConstNodeRef const& n, EmitOptions const& opts, CharOwningContainer * cont, bool append=false)
1022{
1023 if(!n.readable())
1024 return {};
1025 return emitrs_yaml(*n.tree(), n.id(), opts, cont, append);
1026}
1027/** (2) like (1), but use default emit options */
1028template<class CharOwningContainer>
1029substr emitrs_yaml(ConstNodeRef const& n, CharOwningContainer * cont, bool append=false)
1030{
1031 if(!n.readable())
1032 return {};
1033 return emitrs_yaml(*n.tree(), n.id(), EmitOptions{}, cont, append);
1034}
1035/** (1) emit+resize: JSON to the given `std::string`/`std::vector`-like container,
1036 * resizing it as needed to fit the emitted JSON.
1037 * @return a substr trimmed to the new emitted contents */
1038template<class CharOwningContainer>
1039substr emitrs_json(ConstNodeRef const& n, EmitOptions const& opts, CharOwningContainer * cont, bool append=false)
1040{
1041 if(!n.readable())
1042 return {};
1043 return emitrs_json(*n.tree(), n.id(), opts, cont, append);
1044}
1045/** (2) like (1), but use default emit options */
1046template<class CharOwningContainer>
1047substr emitrs_json(ConstNodeRef const& n, CharOwningContainer * cont, bool append=false)
1048{
1049 if(!n.readable())
1050 return {};
1051 return emitrs_json(*n.tree(), n.id(), EmitOptions{}, cont, append);
1052}
1053
1054
1055/** (3) emit+resize: YAML to a newly-created `std::string`/`std::vector`-like container. */
1056template<class CharOwningContainer>
1057CharOwningContainer emitrs_yaml(ConstNodeRef const& n, EmitOptions const& opts={})
1058{
1059 if(!n.readable())
1060 return {};
1061 CharOwningContainer c;
1062 emitrs_yaml(*n.tree(), n.id(), opts, &c);
1063 return c;
1064}
1065/** (3) emit+resize: JSON to a newly-created `std::string`/`std::vector`-like container. */
1066template<class CharOwningContainer>
1067CharOwningContainer emitrs_json(ConstNodeRef const& n, EmitOptions const& opts={})
1068{
1069 if(!n.readable())
1070 return {};
1071 CharOwningContainer c;
1072 emitrs_json(*n.tree(), n.id(), opts, &c);
1073 return c;
1074}
1075
1076
1077/** @} */
1078
1079
1080//-----------------------------------------------------------------------------
1081
1082/** @cond dev */
1083
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")
1090
1091// workaround for Qt emit which is a macro;
1092// see https://github.com/biojppm/rapidyaml/issues/120.
1093// emit is defined in qobjectdefs.h (as an empty define).
1094#ifdef emit
1095#define RYML_TMP_EMIT_
1096#undef emit
1097#endif
1098
1099RYML_DEPRECATE_EMIT inline size_t emit(Tree const& t, id_type id, FILE *f)
1100{
1101 return emit_yaml(t, id, f);
1102}
1103RYML_DEPRECATE_EMIT inline size_t emit(Tree const& t, FILE *f=nullptr)
1104{
1105 return emit_yaml(t, f);
1106}
1107RYML_DEPRECATE_EMIT inline size_t emit(ConstNodeRef const& r, FILE *f=nullptr)
1108{
1109 return emit_yaml(r, f);
1110}
1111
1112RYML_DEPRECATE_EMIT inline substr emit(Tree const& t, id_type id, substr buf, bool error_on_excess=true)
1113{
1114 return emit_yaml(t, id, buf, error_on_excess);
1115}
1116RYML_DEPRECATE_EMIT inline substr emit(Tree const& t, substr buf, bool error_on_excess=true)
1117{
1118 return emit_yaml(t, buf, error_on_excess);
1119}
1120RYML_DEPRECATE_EMIT inline substr emit(ConstNodeRef const& r, substr buf, bool error_on_excess=true)
1121{
1122 return emit_yaml(r, buf, error_on_excess);
1123}
1124
1125#ifdef RYML_TMP_EMIT_
1126#define emit
1127#undef RYML_TMP_EMIT_
1128#endif
1129
1130template<class CharOwningContainer>
1131RYML_DEPRECATE_EMITRS substr emitrs(Tree const& t, id_type id, CharOwningContainer * cont)
1132{
1133 return emitrs_yaml(t, id, cont);
1134}
1135template<class CharOwningContainer>
1136RYML_DEPRECATE_EMITRS CharOwningContainer emitrs(Tree const& t, id_type id)
1137{
1138 return emitrs_yaml<CharOwningContainer>(t, id);
1139}
1140template<class CharOwningContainer>
1141RYML_DEPRECATE_EMITRS substr emitrs(Tree const& t, CharOwningContainer * cont)
1142{
1143 return emitrs_yaml(t, cont);
1144}
1145template<class CharOwningContainer>
1146RYML_DEPRECATE_EMITRS CharOwningContainer emitrs(Tree const& t)
1147{
1148 return emitrs_yaml<CharOwningContainer>(t);
1149}
1150template<class CharOwningContainer>
1151RYML_DEPRECATE_EMITRS substr emitrs(ConstNodeRef const& n, CharOwningContainer * cont)
1152{
1153 return emitrs_yaml(n, cont);
1154}
1155template<class CharOwningContainer>
1156RYML_DEPRECATE_EMITRS CharOwningContainer emitrs(ConstNodeRef const& n)
1157{
1158 return emitrs_yaml<CharOwningContainer>(n);
1159}
1160
1161/** @endcond */
1162
1163
1164} // namespace yml
1165} // namespace c4
1166
1167// NOLINTEND(modernize-avoid-c-style-cast)
1168C4_SUPPRESS_WARNING_GCC_CLANG_POP
1169
1170#undef RYML_DEPRECATE_EMIT
1171#undef RYML_DEPRECATE_EMITRS
1172
1173#include "c4/yml/emit.def.hpp" // NOLINT
1174
1175#endif /* _C4_YML_EMIT_HPP_ */
Holds a pointer to an existing tree, and a node id.
Definition node.hpp:832
id_type id() const noexcept
Definition node.hpp:904
Tree const * tree() const noexcept
Definition node.hpp:903
bool readable() const noexcept
because a ConstNodeRef cannot be used to write to the tree, readable() has the same meaning as !...
Definition node.hpp:889
A stateful emitter, for use with a writer such as WriterBuf, WriterFile, or WriterOStream.
Definition emit.hpp:204
id_type root_id() const
Get the id of the root node. The tree must not be empty.
Definition tree.hpp:337
bool empty() const
Definition tree.hpp:284
Definitions for emit functions.
id_type max_depth() const noexcept
get the max depth for emitted trees (to prevent a stack overflow)
Definition emit.hpp:284
substr emit_as(EmitType_e type, ConstNodeRef const &n, bool error_on_excess=true)
emit starting at the given node
Definition emit.hpp:267
EmitOptions const & options() const noexcept
get the emit options for this object
Definition emit.hpp:277
bool emit_nonroot_key() const noexcept
Definition emit.hpp:127
id_type max_cols() const noexcept
Definition emit.hpp:112
bool json_err_on_tag() const noexcept
Definition emit.hpp:151
bool force_flow_spc() const noexcept
Definition emit.hpp:105
void max_depth(id_type max_depth) noexcept
set the max depth for emitted trees (to prevent a stack overflow)
Definition emit.hpp:282
as_yaml(Tree const &t, EmitOptions const &opts={})
Definition emit.hpp:689
Tree const * tree
Definition emit.hpp:686
void options(EmitOptions opts) noexcept
set the emit options for this object
Definition emit.hpp:279
static constexpr const id_type max_cols_default
Definition emit.hpp:113
substr emit_as(EmitType_e type, Tree const &t, bool error_on_excess=true)
emit starting at the root node
Definition emit.hpp:260
EmitOptions & max_cols(id_type cols) noexcept
Set max columns for the emitted YAML in FLOW_MLN mode.
Definition emit.hpp:111
bool json_err_on_anchor() const noexcept
Definition emit.hpp:156
id_type max_depth() const noexcept
Definition emit.hpp:173
void start(NodeType ty, size_t max_cols_) noexcept
Tree const * tree
Definition emit.hpp:665
as_yaml(Tree const &t, id_type id, EmitOptions const &opts={})
Definition emit.hpp:690
Emitter(WriterArgs &&...args)
Construct the emitter and its internal Writer state, using default emit options.
Definition emit.hpp:228
EmitOptions options
Definition emit.hpp:688
Emitter(EmitOptions const &opts, WriterArgs &&...args)
Construct the emitter and its internal Writer state.
Definition emit.hpp:213
substr emit_as(EmitType_e type, Tree const &t, id_type id, bool error_on_excess)
emit!
Definition emit.def.hpp:20
EmitOptions & json_err_on_tag(bool enabled) noexcept
Whether to trigger an error (or ignore the tag) when finding a tag in json mode.
Definition emit.hpp:150
EmitOptions & max_depth(id_type d) noexcept
Definition emit.hpp:174
Pws_e next_pws(size_t col) const noexcept
Definition emit.hpp:327
bool json_err_on_stream() const noexcept
Definition emit.hpp:146
EmitOptions options
Definition emit.hpp:667
EmitOptions & json_err_on_stream(bool enabled) noexcept
Whether to trigger an error when findind a stream in json mode.
Definition emit.hpp:145
as_json(Tree const &t, EmitOptions const &opts={})
Definition emit.hpp:668
EmitOptions & indent_flow_ml(bool enabled) noexcept
Definition emit.hpp:98
as_yaml(ConstNodeRef const &n, EmitOptions const &opts={})
Definition emit.hpp:691
bool indent_flow_ml() const noexcept
Indent the contents of FLOW_ML1 and FLOW_MLN containers.
Definition emit.hpp:97
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.
Definition emit.hpp:126
EmitOptions & json_err_on_anchor(bool enabled) noexcept
Whether to trigger an error (or ignore the anchor) when finding an anchor in json mode.
Definition emit.hpp:155
bool emit_nonroot_dash() const noexcept
Definition emit.hpp:133
as_json(ConstNodeRef const &n, EmitOptions const &opts={})
Definition emit.hpp:670
EmitOptions & emit_nonroot_dash(bool enabled) noexcept
When emit starts on a node which is not the root node, emit a leading dash.
Definition emit.hpp:132
void stop() noexcept
Definition emit.hpp:332
EmitOptions & force_flow_spc(bool enabled) noexcept
Force everywhere a space after comma in flow mode, overriding the FLOW_SPC status of individual conta...
Definition emit.hpp:104
static constexpr const id_type max_depth_default
Definition emit.hpp:175
as_json(Tree const &t, id_type id, EmitOptions const &opts={})
Definition emit.hpp:669
id_type node
Definition emit.hpp:687
id_type node
Definition emit.hpp:666
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...
Definition emit.hpp:907
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...
Definition emit.hpp:877
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.
Definition emit.hpp:528
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.
Definition emit.hpp:541
Emitter< WriterBuf > EmitterBuf
Definition emit.hpp:40
Emitter< WriterFile > EmitterFile
Definition emit.hpp:39
Emitter< WriterOStream< OStream > > EmitterOStream
Definition emit.hpp:38
EmitType_e
Specifies the type of content to emit.
Definition emit.hpp:48
@ EMIT_YAML
emit YAML
Definition emit.hpp:49
@ EMIT_JSON
emit JSON
Definition emit.hpp:50
uint32_t type_bits
the integral type necessary to cover all the bits for NodeType_e
Definition node_type.hpp:30
@ KEY_DQUO
mark key scalar as double quoted "
@ FLOW_ML1
mark container with multi-line flow style, 1 element per line
Definition node_type.hpp:79
@ 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...
Definition node_type.hpp:94
@ 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
Definition substr.hpp:2377
basic_substring< char > substr
a mutable string view
Definition substr.hpp:2356
@ NONE
an index to none
Definition common.hpp:263
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:256
(Undefined by default) Use shorter error message from checks/asserts: do not show the check condition...
Definition common.cpp:14
Node classes.
size_t len
the length of the substring
Definition substr.hpp:218
C * str
a restricted pointer to the first character of the substring
Definition substr.hpp:216
A lightweight object containing options to be used when emitting.
Definition emit.hpp:60
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.
Definition emit.hpp:664
mark a tree or node to be emitted as yaml when using operator<< .
Definition emit.hpp:685