rapidyaml 0.15.2
parse and emit YAML, and do it fast
Loading...
Searching...
No Matches
emitter.hpp
Go to the documentation of this file.
1#ifndef _C4_YML_EMITTER_HPP_
2#define _C4_YML_EMITTER_HPP_
3
4/** @file emitter.hpp */
5
6#ifndef _C4_YML_EMIT_OPTIONS_HPP_
8#endif
9#ifndef _C4_YML_NODE_TYPE_HPP_
10#include "c4/yml/node_type.hpp"
11#endif
12
13
14namespace c4 {
15namespace yml {
16
17
18/** @cond dev */
19// fwd declarations
20class Tree;
21/** Specifies the type of content to emit */
22typedef enum { // NOLINT
23 EMIT_YAML = 0, ///< emit YAML
24 EMIT_JSON = 1, ///< emit JSON
25} EmitType_e;
26/** @endcond */
27
28
29/** A YAML/JSON emitter, templated on a writer class such as @ref WriterBuf,
30 * @ref WriterFile, or @ref WriterOStream
31 * @ingroup doc_emit
32 */
33template<class Writer>
34class Emitter : public Writer
35{
36public:
37
38 /** Construct the emitter and its internal Writer state.
39 *
40 * @param opts @ref EmitOptions
41 * @param args arguments to be forwarded to the constructor of the writer.
42 */
43 template<class ...WriterArgs>
44 Emitter(EmitOptions const& opts, WriterArgs &&...args) noexcept
45 : Writer(std::forward<WriterArgs>(args)...)
46 , m_tree()
47 , m_opts(opts)
48 , m_col()
49 , m_depth()
50 , m_ilevel()
51 , m_pws()
52 , m_flow_pws()
53 {}
54
55public:
56
57 /** emit!
58 *
59 * @param type specify what to emit (YAML or JSON)
60 * @param tree the tree to emit
61 * @param id the id of the node to emit
62 */
63 void emit_as(EmitType_e type, Tree const* tree, id_type id=NONE);
64
65public:
66
67 /** get the emit options for this object */
68 EmitOptions const& options() const noexcept { return m_opts; }
69
70private: // pending whitespace
71
72 /// pending whitespace
73 typedef enum : uint32_t { _PWS_NONE = 0u, _PWS_SPACE = 1u, _PWS_NEWL = 2u } Pws_e; // NOLINT
74
75 /// set pending whitespace, ignoring pending
76 C4_ALWAYS_INLINE void pend_none_() noexcept // LCOV_EXCL_LINE
77 {
78 m_pws = _PWS_NONE;
79 }
80 /// set pending whitespace, ignoring pending
81 C4_ALWAYS_INLINE void pend_newl_() noexcept // LCOV_EXCL_LINE
82 {
83 m_pws = _PWS_NEWL;
84 }
85 /// set pending whitespace, ignoring pending
86 C4_ALWAYS_INLINE void pend_space_() noexcept // LCOV_EXCL_LINE
87 {
88 m_pws = _PWS_SPACE;
89 }
90 /// write pending whitespace, and then set the next pending whitespace
91 C4_ALWAYS_INLINE void write_pws_and_pend_(Pws_e next=_PWS_NONE) noexcept // LCOV_EXCL_LINE
92 {
93 if(m_pws == _PWS_SPACE)
94 {
95 write_(' ');
96 }
97 else if(m_pws == _PWS_NEWL)
98 {
99 newl_();
100 indent_(m_ilevel);
101 }
102 m_pws = next;
103 }
104
105 /// specs for obtaining pending whitespace in flow mode
106 struct flow_pws
107 {
108 size_t max_cols = 0; // leave this member first to avoid padding
109 Pws_e pend_after_comma = _PWS_NONE;
110 bool active = false;
111 C4_ALWAYS_INLINE Pws_e next_pws(size_t col) const noexcept // LCOV_EXCL_LINE
112 {
113 return (active && col >= max_cols) ? _PWS_NEWL : pend_after_comma;
114 }
115 void start(NodeType ty, size_t max_cols_) noexcept;
116 void stop() noexcept { active = false; }
117 };
118
119 C4_NODISCARD bool maybe_start_flow_pws_ml_(id_type node) noexcept;
120 C4_NODISCARD flow_pws setup_flow_pws_sl_(id_type node) noexcept;
121
122private:
123
124 void emit_yaml_(id_type id);
125
126 void visit_stream_(id_type id);
127 void visit_doc_(id_type id);
128 void visit_doc_val_(id_type id);
129 void visit_blck_container_(id_type id);
130 void visit_flow_container_(id_type id);
131
132 void visit_flow_sl_(id_type id);
133 void visit_flow_sl_seq_(id_type id);
134 void visit_flow_sl_map_(id_type id);
135
136 void visit_flow_ml_(id_type id);
137 void visit_flow_ml_seq_(id_type id);
138 void visit_flow_ml_map_(id_type id);
139
140 void visit_blck_(id_type id);
141 void visit_blck_seq_(id_type id);
142 void visit_blck_map_(id_type id);
143
144 void top_open_entry_(id_type id);
145 void top_close_entry_(id_type id);
146 void blck_seq_open_entry_(id_type id);
147 void blck_map_open_entry_(id_type id);
148 void blck_close_entry_(id_type id);
149 void blck_write_scalar_(csubstr str, type_bits type);
150
151 void flow_seq_open_entry_(id_type id);
152 void flow_map_open_entry_(id_type id);
153 void flow_close_entry_sl_(id_type id, id_type last_sibling, Pws_e pend_after);
154 void flow_close_entry_ml_(id_type id, id_type last_sibling, Pws_e pend_after);
155 void flow_write_scalar_(csubstr str, type_bits type);
156
157private:
158
159 void json_emit_(id_type id);
160 void write_scalar_literal_(csubstr s, id_type level);
161 void write_scalar_folded_(csubstr s, id_type level);
162 void write_scalar_squo_(csubstr s, id_type level);
163 void write_scalar_dquo_(csubstr s, id_type level);
164 void write_scalar_plain_(csubstr s, id_type level);
165
166 size_t write_escaped_newlines_(csubstr s, size_t i);
167 size_t write_indented_block_(csubstr s, size_t i, id_type level);
168
169private:
170
171 void json_visit_ml_(id_type id, NodeType ty, id_type depth);
172 void json_visit_sl_(id_type id, NodeType ty, id_type depth);
173 bool json_maybe_write_naninf_(csubstr s);
174 void json_writek_(id_type id, NodeType ty);
175 void json_writev_(id_type id, NodeType ty);
176 void json_write_scalar_dquo_(csubstr s);
177 void json_write_number_(csubstr s);
178
179private:
180
181 void write_tag_(csubstr tag)
182 {
183 if(!tag.begins_with('!'))
184 write_('!');
185 write_(tag);
186 }
187 void write_ref_(csubstr ref)
188 {
189 if(ref != "<<")
190 {
191 if(!ref.begins_with('*'))
192 write_('*');
193 write_(ref);
194 }
195 }
196
197private:
198
199 template<size_t N>
200 C4_ALWAYS_INLINE void write_(const char (&a)[N]) // LCOV_EXCL_LINE
201 {
202 this->Writer::append(std::forward<const char (&)[N]>(a));
203 m_col += N-1;
204 }
205 C4_ALWAYS_INLINE void write_(csubstr s) // LCOV_EXCL_LINE
206 {
207 this->Writer::append(s);
208 m_col += s.len;
209 }
210 C4_ALWAYS_INLINE void write_(char c) // LCOV_EXCL_LINE
211 {
212 this->Writer::append(c);
213 ++m_col;
214 }
215
216 C4_ALWAYS_INLINE void indent_(id_type level) // LCOV_EXCL_LINE
217 {
218 C4_SUPPRESS_WARNING_GCC_WITH_PUSH("-Wuseless-cast")
219 size_t num = static_cast<size_t>(2u * level);
220 this->Writer::append(' ', num);
221 m_col += num;
222 C4_SUPPRESS_WARNING_GCC_POP
223 }
224
225 /// write a newline and reset the column
226 C4_ALWAYS_INLINE void newl_() // LCOV_EXCL_LINE
227 {
228 this->Writer::append('\n');
229 m_col = 0;
230 }
231
232private:
233
234 Tree const* C4_RESTRICT m_tree;
235 EmitOptions m_opts;
236 size_t m_col;
237 id_type m_depth;
238 id_type m_ilevel;
239 Pws_e m_pws;
240 flow_pws m_flow_pws;
241
242public: // deprecated methods
243
244 /** @cond dev */ // LCOV_EXCL_START
245 RYML_DEPRECATED("create a new emitter") void options(EmitOptions) noexcept { ; }
246 RYML_DEPRECATED("use .options()") void max_depth(id_type max_depth) noexcept { m_opts.max_depth(max_depth); }
247 RYML_DEPRECATED("use .options()") id_type max_depth() const noexcept { return m_opts.max_depth(); }
248 /** @endcond */ // LCOV_EXCL_STOP
249
250};
251
252} // namespace yml
253} // namespace c4
254
255#endif /* _C4_YML_EMITTTER_HPP_ */
void emit_as(EmitType_e type, Tree const *tree, id_type id=NONE)
emit!
EmitOptions const & options() const noexcept
get the emit options for this object
Definition emitter.hpp:68
Emitter(EmitOptions const &opts, WriterArgs &&...args) noexcept
Construct the emitter and its internal Writer state.
Definition emitter.hpp:44
uint32_t type_bits
the integral type necessary to cover all the bits for NodeType_e
Definition node_type.hpp:30
basic_substring< const char > csubstr
an immutable string view
Definition substr.hpp:2357
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:305
@ NONE
an index to none
Definition common.hpp:312
(Undefined by default) Use shorter error message from checks/asserts: do not show the check condition...
Definition common.cpp:14
A lightweight object containing options to be used when emitting.