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