rapidyaml  0.16.0
parseandemitYAML,anddoitfast
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 
14 namespace c4 {
15 namespace yml {
16 
17 
18 /** @cond dev */
19 // fwd declarations
20 class Tree;
21 /** Specifies the type of content to emit */
22 typedef 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  */
33 template<class Writer>
34 class Emitter : public Writer
35 {
36 public:
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 
55 public:
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 
65 public:
66 
67  /** get the emit options for this object */
68  EmitOptions const& options() const noexcept { return m_opts; }
69 
70 private: // 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 
122 private:
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 
157 private:
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 
169 private:
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 
179 private:
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 
197 private:
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 
232 private:
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 
242 public: // 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_ */
EmitOptions const & options() const noexcept
get the emit options for this object
Definition: emitter.hpp:68
an index to none
Definition: common.hpp:131
A YAML/JSON emitter, templated on a writer class such as WriterBuf, WriterFile, or WriterOStream...
Definition: emitter.hpp:34
const char * str
Definition: node_type.cpp:70
Emitter(EmitOptions const &opts, WriterArgs &&...args) noexcept
Construct the emitter and its internal Writer state.
Definition: emitter.hpp:44
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:124
void emit_as(EmitType_e type, Tree const *tree, id_type id=NONE)
emit!
Definition: emitter.def.hpp:48
basic_substring< const char > csubstr
an immutable string view
Definition: substr.hpp:2356
A lightweight object containing options to be used when emitting.
uint32_t type_bits
the integral type necessary to cover all the bits for NodeType_e
Definition: node_type.hpp:26
id_type max_depth() const noexcept