Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
stenzek
GitHub Repository: stenzek/duckstation
Path: blob/master/dep/rapidyaml/include/c4/yml/emit.hpp
4264 views
1
#ifndef _C4_YML_EMIT_HPP_
2
#define _C4_YML_EMIT_HPP_
3
4
#ifndef _C4_YML_WRITER_HPP_
5
#include "./writer.hpp"
6
#endif
7
8
#ifndef _C4_YML_TREE_HPP_
9
#include "./tree.hpp"
10
#endif
11
12
#ifndef _C4_YML_NODE_HPP_
13
#include "./node.hpp"
14
#endif
15
16
17
#define RYML_DEPRECATE_EMIT \
18
RYML_DEPRECATED("use emit_yaml() instead. See https://github.com/biojppm/rapidyaml/issues/120")
19
#ifdef emit
20
#error "emit is defined, likely from a Qt include. This will cause a compilation error. See https://github.com/biojppm/rapidyaml/issues/120"
21
#endif
22
#define RYML_DEPRECATE_EMITRS \
23
RYML_DEPRECATED("use emitrs_yaml() instead. See https://github.com/biojppm/rapidyaml/issues/120")
24
25
26
//-----------------------------------------------------------------------------
27
//-----------------------------------------------------------------------------
28
//-----------------------------------------------------------------------------
29
30
namespace c4 {
31
namespace yml {
32
33
template<class Writer> class Emitter;
34
35
template<class OStream>
36
using EmitterOStream = Emitter<WriterOStream<OStream>>;
37
using EmitterFile = Emitter<WriterFile>;
38
using EmitterBuf = Emitter<WriterBuf>;
39
40
typedef enum {
41
EMIT_YAML = 0,
42
EMIT_JSON = 1
43
} EmitType_e;
44
45
46
/** mark a tree or node to be emitted as json */
47
struct as_json
48
{
49
Tree const* tree;
50
size_t node;
51
as_json(Tree const& t) : tree(&t), node(t.empty() ? NONE : t.root_id()) {}
52
as_json(Tree const& t, size_t id) : tree(&t), node(id) {}
53
as_json(ConstNodeRef const& n) : tree(n.tree()), node(n.id()) {}
54
};
55
56
57
//-----------------------------------------------------------------------------
58
//-----------------------------------------------------------------------------
59
//-----------------------------------------------------------------------------
60
61
template<class Writer>
62
class Emitter : public Writer
63
{
64
public:
65
66
using Writer::Writer;
67
68
/** emit!
69
*
70
* When writing to a buffer, returns a substr of the emitted YAML.
71
* If the given buffer has insufficient space, the returned span will
72
* be null and its size will be the needed space. No writes are done
73
* after the end of the buffer.
74
*
75
* When writing to a file, the returned substr will be null, but its
76
* length will be set to the number of bytes written. */
77
substr emit_as(EmitType_e type, Tree const& t, size_t id, bool error_on_excess);
78
/** emit starting at the root node */
79
substr emit_as(EmitType_e type, Tree const& t, bool error_on_excess=true);
80
/** emit the given node */
81
substr emit_as(EmitType_e type, ConstNodeRef const& n, bool error_on_excess=true);
82
83
private:
84
85
Tree const* C4_RESTRICT m_tree;
86
87
void _emit_yaml(size_t id);
88
void _do_visit_flow_sl(size_t id, size_t ilevel=0);
89
void _do_visit_flow_ml(size_t id, size_t ilevel=0, size_t do_indent=1);
90
void _do_visit_block(size_t id, size_t ilevel=0, size_t do_indent=1);
91
void _do_visit_block_container(size_t id, size_t next_level, size_t do_indent);
92
void _do_visit_json(size_t id);
93
94
private:
95
96
void _write(NodeScalar const& C4_RESTRICT sc, NodeType flags, size_t level);
97
void _write_json(NodeScalar const& C4_RESTRICT sc, NodeType flags);
98
99
void _write_doc(size_t id);
100
void _write_scalar(csubstr s, bool was_quoted);
101
void _write_scalar_json(csubstr s, bool as_key, bool was_quoted);
102
void _write_scalar_literal(csubstr s, size_t level, bool as_key, bool explicit_indentation=false);
103
void _write_scalar_folded(csubstr s, size_t level, bool as_key);
104
void _write_scalar_squo(csubstr s, size_t level);
105
void _write_scalar_dquo(csubstr s, size_t level);
106
void _write_scalar_plain(csubstr s, size_t level);
107
108
void _write_tag(csubstr tag)
109
{
110
if(!tag.begins_with('!'))
111
this->Writer::_do_write('!');
112
this->Writer::_do_write(tag);
113
}
114
115
enum : type_bits {
116
_keysc = (KEY|KEYREF|KEYANCH|KEYQUO|_WIP_KEY_STYLE) | ~(VAL|VALREF|VALANCH|VALQUO|_WIP_VAL_STYLE),
117
_valsc = ~(KEY|KEYREF|KEYANCH|KEYQUO|_WIP_KEY_STYLE) | (VAL|VALREF|VALANCH|VALQUO|_WIP_VAL_STYLE),
118
_keysc_json = (KEY) | ~(VAL),
119
_valsc_json = ~(KEY) | (VAL),
120
};
121
122
C4_ALWAYS_INLINE void _writek(size_t id, size_t level) { _write(m_tree->keysc(id), m_tree->_p(id)->m_type.type & ~_valsc, level); }
123
C4_ALWAYS_INLINE void _writev(size_t id, size_t level) { _write(m_tree->valsc(id), m_tree->_p(id)->m_type.type & ~_keysc, level); }
124
125
C4_ALWAYS_INLINE void _writek_json(size_t id) { _write_json(m_tree->keysc(id), m_tree->_p(id)->m_type.type & ~(VAL)); }
126
C4_ALWAYS_INLINE void _writev_json(size_t id) { _write_json(m_tree->valsc(id), m_tree->_p(id)->m_type.type & ~(KEY)); }
127
128
};
129
130
131
//-----------------------------------------------------------------------------
132
//-----------------------------------------------------------------------------
133
//-----------------------------------------------------------------------------
134
135
/** emit YAML to the given file. A null file defaults to stdout.
136
* Return the number of bytes written. */
137
inline size_t emit_yaml(Tree const& t, size_t id, FILE *f)
138
{
139
EmitterFile em(f);
140
return em.emit_as(EMIT_YAML, t, id, /*error_on_excess*/true).len;
141
}
142
RYML_DEPRECATE_EMIT inline size_t emit(Tree const& t, size_t id, FILE *f)
143
{
144
return emit_yaml(t, id, f);
145
}
146
147
/** emit JSON to the given file. A null file defaults to stdout.
148
* Return the number of bytes written. */
149
inline size_t emit_json(Tree const& t, size_t id, FILE *f)
150
{
151
EmitterFile em(f);
152
return em.emit_as(EMIT_JSON, t, id, /*error_on_excess*/true).len;
153
}
154
155
156
/** emit YAML to the given file. A null file defaults to stdout.
157
* Return the number of bytes written.
158
* @overload */
159
inline size_t emit_yaml(Tree const& t, FILE *f=nullptr)
160
{
161
EmitterFile em(f);
162
return em.emit_as(EMIT_YAML, t, /*error_on_excess*/true).len;
163
}
164
RYML_DEPRECATE_EMIT inline size_t emit(Tree const& t, FILE *f=nullptr)
165
{
166
return emit_yaml(t, f);
167
}
168
169
/** emit JSON to the given file. A null file defaults to stdout.
170
* Return the number of bytes written.
171
* @overload */
172
inline size_t emit_json(Tree const& t, FILE *f=nullptr)
173
{
174
EmitterFile em(f);
175
return em.emit_as(EMIT_JSON, t, /*error_on_excess*/true).len;
176
}
177
178
179
/** emit YAML to the given file. A null file defaults to stdout.
180
* Return the number of bytes written.
181
* @overload */
182
inline size_t emit_yaml(ConstNodeRef const& r, FILE *f=nullptr)
183
{
184
EmitterFile em(f);
185
return em.emit_as(EMIT_YAML, r, /*error_on_excess*/true).len;
186
}
187
RYML_DEPRECATE_EMIT inline size_t emit(ConstNodeRef const& r, FILE *f=nullptr)
188
{
189
return emit_yaml(r, f);
190
}
191
192
/** emit JSON to the given file. A null file defaults to stdout.
193
* Return the number of bytes written.
194
* @overload */
195
inline size_t emit_json(ConstNodeRef const& r, FILE *f=nullptr)
196
{
197
EmitterFile em(f);
198
return em.emit_as(EMIT_JSON, r, /*error_on_excess*/true).len;
199
}
200
201
202
//-----------------------------------------------------------------------------
203
204
/** emit YAML to an STL-like ostream */
205
template<class OStream>
206
inline OStream& operator<< (OStream& s, Tree const& t)
207
{
208
EmitterOStream<OStream> em(s);
209
em.emit_as(EMIT_YAML, t);
210
return s;
211
}
212
213
/** emit YAML to an STL-like ostream
214
* @overload */
215
template<class OStream>
216
inline OStream& operator<< (OStream& s, ConstNodeRef const& n)
217
{
218
EmitterOStream<OStream> em(s);
219
em.emit_as(EMIT_YAML, n);
220
return s;
221
}
222
223
/** emit json to an STL-like stream */
224
template<class OStream>
225
inline OStream& operator<< (OStream& s, as_json const& j)
226
{
227
EmitterOStream<OStream> em(s);
228
em.emit_as(EMIT_JSON, *j.tree, j.node, true);
229
return s;
230
}
231
232
233
//-----------------------------------------------------------------------------
234
235
236
/** emit YAML to the given buffer. Return a substr trimmed to the emitted YAML.
237
* @param error_on_excess Raise an error if the space in the buffer is insufficient.
238
* @overload */
239
inline substr emit_yaml(Tree const& t, size_t id, substr buf, bool error_on_excess=true)
240
{
241
EmitterBuf em(buf);
242
return em.emit_as(EMIT_YAML, t, id, error_on_excess);
243
}
244
RYML_DEPRECATE_EMIT inline substr emit(Tree const& t, size_t id, substr buf, bool error_on_excess=true)
245
{
246
return emit_yaml(t, id, buf, error_on_excess);
247
}
248
249
/** emit JSON to the given buffer. Return a substr trimmed to the emitted JSON.
250
* @param error_on_excess Raise an error if the space in the buffer is insufficient.
251
* @overload */
252
inline substr emit_json(Tree const& t, size_t id, substr buf, bool error_on_excess=true)
253
{
254
EmitterBuf em(buf);
255
return em.emit_as(EMIT_JSON, t, id, error_on_excess);
256
}
257
258
259
/** emit YAML to the given buffer. Return a substr trimmed to the emitted YAML.
260
* @param error_on_excess Raise an error if the space in the buffer is insufficient.
261
* @overload */
262
inline substr emit_yaml(Tree const& t, substr buf, bool error_on_excess=true)
263
{
264
EmitterBuf em(buf);
265
return em.emit_as(EMIT_YAML, t, error_on_excess);
266
}
267
RYML_DEPRECATE_EMIT inline substr emit(Tree const& t, substr buf, bool error_on_excess=true)
268
{
269
return emit_yaml(t, buf, error_on_excess);
270
}
271
272
/** emit JSON to the given buffer. Return a substr trimmed to the emitted JSON.
273
* @param error_on_excess Raise an error if the space in the buffer is insufficient.
274
* @overload */
275
inline substr emit_json(Tree const& t, substr buf, bool error_on_excess=true)
276
{
277
EmitterBuf em(buf);
278
return em.emit_as(EMIT_JSON, t, error_on_excess);
279
}
280
281
282
/** emit YAML to the given buffer. Return a substr trimmed to the emitted YAML.
283
* @param error_on_excess Raise an error if the space in the buffer is insufficient.
284
* @overload
285
*/
286
inline substr emit_yaml(ConstNodeRef const& r, substr buf, bool error_on_excess=true)
287
{
288
EmitterBuf em(buf);
289
return em.emit_as(EMIT_YAML, r, error_on_excess);
290
}
291
RYML_DEPRECATE_EMIT inline substr emit(ConstNodeRef const& r, substr buf, bool error_on_excess=true)
292
{
293
return emit_yaml(r, buf, error_on_excess);
294
}
295
296
/** emit JSON to the given buffer. Return a substr trimmed to the emitted JSON.
297
* @param error_on_excess Raise an error if the space in the buffer is insufficient.
298
* @overload
299
*/
300
inline substr emit_json(ConstNodeRef const& r, substr buf, bool error_on_excess=true)
301
{
302
EmitterBuf em(buf);
303
return em.emit_as(EMIT_JSON, r, error_on_excess);
304
}
305
306
307
//-----------------------------------------------------------------------------
308
309
/** emit+resize: emit YAML to the given std::string/std::vector-like
310
* container, resizing it as needed to fit the emitted YAML. */
311
template<class CharOwningContainer>
312
substr emitrs_yaml(Tree const& t, size_t id, CharOwningContainer * cont)
313
{
314
substr buf = to_substr(*cont);
315
substr ret = emit_yaml(t, id, buf, /*error_on_excess*/false);
316
if(ret.str == nullptr && ret.len > 0)
317
{
318
cont->resize(ret.len);
319
buf = to_substr(*cont);
320
ret = emit_yaml(t, id, buf, /*error_on_excess*/true);
321
}
322
return ret;
323
}
324
template<class CharOwningContainer>
325
RYML_DEPRECATE_EMITRS substr emitrs(Tree const& t, size_t id, CharOwningContainer * cont)
326
{
327
return emitrs_yaml(t, id, cont);
328
}
329
330
/** emit+resize: emit JSON to the given std::string/std::vector-like
331
* container, resizing it as needed to fit the emitted JSON. */
332
template<class CharOwningContainer>
333
substr emitrs_json(Tree const& t, size_t id, CharOwningContainer * cont)
334
{
335
substr buf = to_substr(*cont);
336
substr ret = emit_json(t, id, buf, /*error_on_excess*/false);
337
if(ret.str == nullptr && ret.len > 0)
338
{
339
cont->resize(ret.len);
340
buf = to_substr(*cont);
341
ret = emit_json(t, id, buf, /*error_on_excess*/true);
342
}
343
return ret;
344
}
345
346
347
/** emit+resize: emit YAML to the given std::string/std::vector-like
348
* container, resizing it as needed to fit the emitted YAML. */
349
template<class CharOwningContainer>
350
CharOwningContainer emitrs_yaml(Tree const& t, size_t id)
351
{
352
CharOwningContainer c;
353
emitrs_yaml(t, id, &c);
354
return c;
355
}
356
template<class CharOwningContainer>
357
RYML_DEPRECATE_EMITRS CharOwningContainer emitrs(Tree const& t, size_t id)
358
{
359
CharOwningContainer c;
360
emitrs_yaml(t, id, &c);
361
return c;
362
}
363
364
/** emit+resize: emit JSON to the given std::string/std::vector-like
365
* container, resizing it as needed to fit the emitted JSON. */
366
template<class CharOwningContainer>
367
CharOwningContainer emitrs_json(Tree const& t, size_t id)
368
{
369
CharOwningContainer c;
370
emitrs_json(t, id, &c);
371
return c;
372
}
373
374
375
/** emit+resize: YAML to the given std::string/std::vector-like
376
* container, resizing it as needed to fit the emitted YAML. */
377
template<class CharOwningContainer>
378
substr emitrs_yaml(Tree const& t, CharOwningContainer * cont)
379
{
380
if(t.empty())
381
return {};
382
return emitrs_yaml(t, t.root_id(), cont);
383
}
384
template<class CharOwningContainer>
385
RYML_DEPRECATE_EMITRS substr emitrs(Tree const& t, CharOwningContainer * cont)
386
{
387
return emitrs_yaml(t, cont);
388
}
389
390
/** emit+resize: JSON to the given std::string/std::vector-like
391
* container, resizing it as needed to fit the emitted JSON. */
392
template<class CharOwningContainer>
393
substr emitrs_json(Tree const& t, CharOwningContainer * cont)
394
{
395
if(t.empty())
396
return {};
397
return emitrs_json(t, t.root_id(), cont);
398
}
399
400
401
/** emit+resize: YAML to the given std::string/std::vector-like container,
402
* resizing it as needed to fit the emitted YAML. */
403
template<class CharOwningContainer>
404
CharOwningContainer emitrs_yaml(Tree const& t)
405
{
406
CharOwningContainer c;
407
if(t.empty())
408
return c;
409
emitrs_yaml(t, t.root_id(), &c);
410
return c;
411
}
412
template<class CharOwningContainer>
413
RYML_DEPRECATE_EMITRS CharOwningContainer emitrs(Tree const& t)
414
{
415
return emitrs_yaml<CharOwningContainer>(t);
416
}
417
418
/** emit+resize: JSON to the given std::string/std::vector-like container,
419
* resizing it as needed to fit the emitted JSON. */
420
template<class CharOwningContainer>
421
CharOwningContainer emitrs_json(Tree const& t)
422
{
423
CharOwningContainer c;
424
if(t.empty())
425
return c;
426
emitrs_json(t, t.root_id(), &c);
427
return c;
428
}
429
430
431
/** emit+resize: YAML to the given std::string/std::vector-like container,
432
* resizing it as needed to fit the emitted YAML. */
433
template<class CharOwningContainer>
434
substr emitrs_yaml(ConstNodeRef const& n, CharOwningContainer * cont)
435
{
436
_RYML_CB_CHECK(n.tree()->callbacks(), n.valid());
437
return emitrs_yaml(*n.tree(), n.id(), cont);
438
}
439
template<class CharOwningContainer>
440
RYML_DEPRECATE_EMITRS substr emitrs(ConstNodeRef const& n, CharOwningContainer * cont)
441
{
442
return emitrs_yaml(n, cont);
443
}
444
445
/** emit+resize: JSON to the given std::string/std::vector-like container,
446
* resizing it as needed to fit the emitted JSON. */
447
template<class CharOwningContainer>
448
substr emitrs_json(ConstNodeRef const& n, CharOwningContainer * cont)
449
{
450
_RYML_CB_CHECK(n.tree()->callbacks(), n.valid());
451
return emitrs_json(*n.tree(), n.id(), cont);
452
}
453
454
455
/** emit+resize: YAML to the given std::string/std::vector-like container,
456
* resizing it as needed to fit the emitted YAML. */
457
template<class CharOwningContainer>
458
CharOwningContainer emitrs_yaml(ConstNodeRef const& n)
459
{
460
_RYML_CB_CHECK(n.tree()->callbacks(), n.valid());
461
CharOwningContainer c;
462
emitrs_yaml(*n.tree(), n.id(), &c);
463
return c;
464
}
465
template<class CharOwningContainer>
466
RYML_DEPRECATE_EMITRS CharOwningContainer emitrs(ConstNodeRef const& n)
467
{
468
return emitrs_yaml<CharOwningContainer>(n);
469
}
470
471
/** emit+resize: JSON to the given std::string/std::vector-like container,
472
* resizing it as needed to fit the emitted JSON. */
473
template<class CharOwningContainer>
474
CharOwningContainer emitrs_json(ConstNodeRef const& n)
475
{
476
_RYML_CB_CHECK(n.tree()->callbacks(), n.valid());
477
CharOwningContainer c;
478
emitrs_json(*n.tree(), n.id(), &c);
479
return c;
480
}
481
482
} // namespace yml
483
} // namespace c4
484
485
#undef RYML_DEPRECATE_EMIT
486
#undef RYML_DEPRECATE_EMITRS
487
488
#include "c4/yml/emit.def.hpp"
489
490
#endif /* _C4_YML_EMIT_HPP_ */
491
492