• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

biojppm / rapidyaml / 18649960093

20 Oct 2025 11:02AM UTC coverage: 97.642% (-0.008%) from 97.65%
18649960093

Pull #503

github

web-flow
Merge 779b983dc into 48acea949
Pull Request #503: Improve error model, callbacks

1823 of 1870 new or added lines in 32 files covered. (97.49%)

38 existing lines in 4 files now uncovered.

13623 of 13952 relevant lines covered (97.64%)

537812.42 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

96.58
/src/c4/yml/emit.def.hpp
1
#ifndef _C4_YML_EMIT_DEF_HPP_
2
#define _C4_YML_EMIT_DEF_HPP_
3

4
#ifndef _C4_YML_EMIT_HPP_
5
#include "c4/yml/emit.hpp"
6
#endif
7

8
/** @file emit.def.hpp Definitions for emit functions. */
9
#ifndef _C4_YML_DETAIL_DBGPRINT_HPP_
10
#include "c4/yml/detail/dbgprint.hpp"
11
#endif
12

13
namespace c4 {
14
namespace yml {
15

16
template<class Writer>
17
substr Emitter<Writer>::emit_as(EmitType_e type, Tree const& tree, id_type id, bool error_on_excess)
1,623,186✔
18
{
19
    if(tree.empty())
1,623,186✔
20
    {
NEW
21
        _RYML_ASSERT_BASIC_(tree.callbacks(), id == NONE);
×
22
        return {};
×
23
    }
24
    if(id == NONE)
1,623,186✔
25
        id = tree.root_id();
1,020✔
26
    _RYML_CHECK_VISIT_(tree.callbacks(), id < tree.capacity(), &tree, id);
1,623,186✔
27
    m_tree = &tree;
1,623,186✔
28
    m_flow = false;
1,623,186✔
29
    if(type == EMIT_YAML)
1,623,186✔
30
        _emit_yaml(id);
1,119,942✔
31
    else if(type == EMIT_JSON)
503,244✔
32
        _do_visit_json(id, 0);
503,244✔
33
    else
NEW
34
        _RYML_ERR_BASIC_(m_tree->callbacks(), "unknown emit type");
×
35
    m_tree = nullptr;
1,621,890✔
36
    return this->Writer::_get(error_on_excess);
1,621,890✔
37
}
38

39

40
//-----------------------------------------------------------------------------
41

42
template<class Writer>
43
void Emitter<Writer>::_emit_yaml(id_type id)
1,119,942✔
44
{
45
    // save branches in the visitor by doing the initial stream/doc
46
    // logic here, sparing the need to check stream/val/keyval inside
47
    // the visitor functions
48
    auto dispatch = [this](id_type node){
1,789,956✔
49
        NodeType ty = m_tree->type(node);
879,442✔
50
        if(ty.is_flow_sl())
879,442✔
51
            _do_visit_flow_sl(node, 0);
176,920✔
52
        else if(ty.is_flow_ml())
702,522✔
53
            _do_visit_flow_ml(node, 0);
×
54
        else
55
        {
56
            _do_visit_block(node, 0);
702,522✔
57
        }
58
    };
59
    if(!m_tree->is_root(id))
1,119,942✔
60
    {
61
        if(m_tree->is_container(id) && !m_tree->type(id).is_flow())
21,174✔
62
        {
63
            id_type ilevel = 0;
3,690✔
64
            if(m_tree->has_key(id))
7,380✔
65
            {
66
                this->Writer::_do_write(m_tree->key(id));
3,294✔
67
                this->Writer::_do_write(":\n");
3,294✔
68
                ++ilevel;
3,294✔
69
            }
70
            _do_visit_block_container(id, 0, ilevel, ilevel);
3,690✔
71
            return;
3,450✔
72
        }
73
    }
74

75
    TagDirectiveRange tagds = m_tree->tag_directives();
1,116,252✔
76
    auto write_tag_directives = [&tagds, this](const id_type next_node){
1,805,548✔
77
        TagDirective const* C4_RESTRICT end = tagds.b;
344,648✔
78
        while(end < tagds.e)
356,708✔
79
        {
80
            if(end->next_node_id > next_node)
15,960✔
81
                break;
3,900✔
82
            ++end;
12,060✔
83
        }
84
        const id_type parent = m_tree->parent(next_node);
344,648✔
85
        for( ; tagds.b != end; ++tagds.b)
356,708✔
86
        {
87
            if(next_node != m_tree->first_child(parent))
12,060✔
88
                this->Writer::_do_write("...\n");
3,900✔
89
            this->Writer::_do_write("%TAG ");
12,060✔
90
            this->Writer::_do_write(tagds.b->handle);
12,060✔
91
            this->Writer::_do_write(' ');
12,060✔
92
            this->Writer::_do_write(tagds.b->prefix);
12,060✔
93
            this->Writer::_do_write('\n');
12,060✔
94
        }
95
    };
96
    if(m_tree->is_stream(id))
2,232,504✔
97
    {
98
        const id_type first_child = m_tree->first_child(id);
250,458✔
99
        if(first_child != NONE)
250,458✔
100
            write_tag_directives(first_child);
250,458✔
101
        for(id_type child = first_child; child != NONE; child = m_tree->next_sibling(child))
595,106✔
102
        {
103
            dispatch(child);
344,648✔
104
            if(m_tree->is_doc(child) && m_tree->type(child).is_flow_sl())
1,033,944✔
105
                this->Writer::_do_write('\n');
12,474✔
106
            if(m_tree->next_sibling(child) != NONE)
344,648✔
107
                write_tag_directives(m_tree->next_sibling(child));
94,190✔
108
        }
109
    }
110
    else if(m_tree->is_container(id))
1,731,588✔
111
    {
112
        dispatch(id);
534,794✔
113
    }
114
    else if(m_tree->is_doc(id))
662,000✔
115
    {
116
        _RYML_ASSERT_VISIT_(m_tree->callbacks(), !m_tree->is_container(id), m_tree, id); // checked above
12✔
117
        _RYML_ASSERT_VISIT_(m_tree->callbacks(), m_tree->is_val(id), m_tree, id); // so it must be a val
12✔
118
        _write_doc(id);
6✔
119
    }
120
    else if(m_tree->is_keyval(id))
661,988✔
121
    {
122
        _writek(id, 0);
123
        this->Writer::_do_write(": ");
1,362✔
124
        _writev(id, 0);
125
        if(!m_tree->type(id).is_flow())
2,724✔
126
            this->Writer::_do_write('\n');
690✔
127
    }
128
    else if(m_tree->is_val(id))
659,264✔
129
    {
130
        //this->Writer::_do_write("- ");
131
        _writev(id, 0);
132
        if(!m_tree->type(id).is_flow())
366,076✔
133
            this->Writer::_do_write('\n');
182,366✔
134
    }
135
    else if(m_tree->type(id) == NOTYPE)
293,188✔
136
    {
137
        ;
138
    }
139
    else
140
    {
NEW
141
        _RYML_ERR_VISIT_(m_tree->callbacks(), m_tree, id, "unknown type");
×
142
    }
143
}
144

145
#define _rymlindent_nextline() this->_indent(ilevel + 1);
146

147
template<class Writer>
148
void Emitter<Writer>::_write_doc(id_type id)
344,666✔
149
{
150
    const NodeType ty = m_tree->type(id);
344,666✔
151
    _RYML_ASSERT_VISIT_(m_tree->m_callbacks, ty.is_doc(), m_tree, id);
344,666✔
152
    _RYML_ASSERT_VISIT_(m_tree->m_callbacks, !ty.has_key(), m_tree, id);
344,666✔
153
    if(!m_tree->is_root(id))
344,666✔
154
    {
155
        _RYML_ASSERT_VISIT_(m_tree->m_callbacks, m_tree->is_stream(m_tree->parent(id)), m_tree, id);
689,296✔
156
        this->Writer::_do_write("---");
344,648✔
157
    }
158
    //
159
    if(!ty.has_val()) // this is more frequent
344,666✔
160
    {
161
        const bool tag = ty.has_val_tag();
167,824✔
162
        const bool anchor = ty.has_val_anchor();
167,824✔
163
        if(!tag && !anchor)
167,824✔
164
        {
165
            ;
166
        }
167
        else if(!tag && anchor)
29,104✔
168
        {
169
            if(!m_tree->is_root(id))
2,354✔
170
                this->Writer::_do_write(' ');
2,354✔
171
            this->Writer::_do_write('&');
2,354✔
172
            this->Writer::_do_write(m_tree->val_anchor(id));
2,354✔
173
            #ifdef RYML_NO_COVERAGE__TO_BE_DELETED
174
            if(m_tree->has_children(id) && m_tree->is_root(id))
175
                this->Writer::_do_write('\n');
176
            #endif
177
        }
178
        else if(tag && !anchor)
26,750✔
179
        {
180
            if(!m_tree->is_root(id))
23,880✔
181
                this->Writer::_do_write(' ');
23,880✔
182
            _write_tag(m_tree->val_tag(id));
23,880✔
183
            #ifdef RYML_NO_COVERAGE__TO_BE_DELETED
184
            if(m_tree->has_children(id) && m_tree->is_root(id))
185
                this->Writer::_do_write('\n');
186
            #endif
187
        }
188
        else // tag && anchor
189
        {
190
            if(!m_tree->is_root(id))
2,870✔
191
                this->Writer::_do_write(' ');
2,870✔
192
            _write_tag(m_tree->val_tag(id));
2,870✔
193
            this->Writer::_do_write(" &");
2,870✔
194
            this->Writer::_do_write(m_tree->val_anchor(id));
2,870✔
195
            #ifdef RYML_NO_COVERAGE__TO_BE_DELETED
196
            if(m_tree->has_children(id) && m_tree->is_root(id))
197
                this->Writer::_do_write('\n');
198
            #endif
199
        }
200
    }
201
    else // docval
202
    {
203
        _RYML_ASSERT_VISIT_(m_tree->callbacks(), ty.has_val(), m_tree, id);
176,842✔
204
        // some plain scalars such as '...' and '---' must not
205
        // appear at 0-indentation
206
        const csubstr val = m_tree->val(id);
176,842✔
207
        const bool preceded_by_3_dashes = !m_tree->is_root(id);
176,842✔
208
        const type_bits style_marks = ty & VAL_STYLE;
353,684✔
209
        const bool is_plain = ty.is_val_plain();
176,842✔
210
        const bool is_ambiguous = (is_plain || !style_marks)
90,012✔
211
            && ((val.begins_with("...") || val.begins_with("---"))
526,222✔
212
                ||
85,708✔
213
                (val.find('\n') != npos));
85,708✔
214
        if(preceded_by_3_dashes)
176,842✔
215
        {
216
            if(is_plain && val.len == 0 && !ty.has_val_anchor() && !ty.has_val_tag())
233,272✔
217
            {
218
                this->Writer::_do_write('\n');
27,966✔
219
                return;
27,966✔
220
            }
221
            else if(val.len && is_ambiguous)
148,870✔
222
            {
223
                this->Writer::_do_write('\n');
4,028✔
224
            }
225
            else
226
            {
227
                this->Writer::_do_write(' ');
144,842✔
228
            }
229
        }
230
        id_type ilevel = 0u;
148,876✔
231
        if(is_ambiguous)
148,876✔
232
        {
233
            _rymlindent_nextline();
4,028✔
234
            ++ilevel;
4,028✔
235
        }
236
        _writev(id, ilevel);
237
        if(val.len && m_tree->is_root(id))
148,876✔
238
            this->Writer::_do_write('\n');
6✔
239
    }
240
    if(!m_tree->is_root(id))
316,700✔
241
        this->Writer::_do_write('\n');
316,682✔
242
}
243

244
template<class Writer>
245
void Emitter<Writer>::_do_visit_flow_sl(id_type node, id_type depth, id_type ilevel)
432,500✔
246
{
247
    const bool prev_flow = m_flow;
432,500✔
248
    m_flow = true;
432,500✔
249
    _RYML_ASSERT_VISIT_(m_tree->callbacks(), !m_tree->is_stream(node), m_tree, node);
865,000✔
250
    _RYML_ASSERT_VISIT_(m_tree->callbacks(), m_tree->is_container(node) || m_tree->is_doc(node), m_tree, node);
865,000✔
251
    _RYML_ASSERT_VISIT_(m_tree->callbacks(), m_tree->is_root(node) || (m_tree->parent_is_map(node) || m_tree->parent_is_seq(node)), m_tree, node);
866,812✔
252
    if(C4_UNLIKELY(depth > m_opts.max_depth()))
865,000✔
253
        _RYML_ERR_VISIT_(m_tree->callbacks(), m_tree, node, "max depth exceeded");
144✔
254

255
    if(m_tree->is_doc(node))
864,712✔
256
    {
257
        _write_doc(node);
12,486✔
258
        #ifdef RYML_NO_COVERAGE__TO_BE_DELETED
259
        if(!m_tree->has_children(node))
260
            return;
261
        else
262
        #endif
263
        {
264
            if(m_tree->is_map(node))
24,972✔
265
            {
266
                this->Writer::_do_write('{');
10,236✔
267
            }
268
            else
269
            {
270
                _RYML_ASSERT_VISIT_(m_tree->callbacks(), m_tree->is_seq(node), m_tree, node);
4,500✔
271
                this->Writer::_do_write('[');
2,250✔
272
            }
273
        }
274
    }
275
    else if(m_tree->is_container(node))
839,740✔
276
    {
277
        _RYML_ASSERT_VISIT_(m_tree->callbacks(), m_tree->is_map(node) || m_tree->is_seq(node), m_tree, node);
1,009,132✔
278

279
        bool spc = false; // write a space
419,870✔
280

281
        if(m_tree->has_key(node))
839,740✔
282
        {
283
            _writek(node, ilevel);
284
            this->Writer::_do_write(':');
104,844✔
285
            spc = true;
104,844✔
286
        }
287

288
        if(m_tree->has_val_tag(node))
839,740✔
289
        {
290
            if(spc)
4,356✔
291
                this->Writer::_do_write(' ');
2,202✔
292
            _write_tag(m_tree->val_tag(node));
4,356✔
293
            spc = true;
4,356✔
294
        }
295

296
        if(m_tree->has_val_anchor(node))
839,740✔
297
        {
298
            if(spc)
5,558✔
299
                this->Writer::_do_write(' ');
2,114✔
300
            this->Writer::_do_write('&');
5,558✔
301
            this->Writer::_do_write(m_tree->val_anchor(node));
5,558✔
302
            spc = true;
5,558✔
303
        }
304

305
        if(spc)
419,870✔
306
            this->Writer::_do_write(' ');
110,442✔
307

308
        if(m_tree->is_map(node))
839,740✔
309
        {
310
            this->Writer::_do_write('{');
250,478✔
311
        }
312
        else
313
        {
314
            _RYML_ASSERT_VISIT_(m_tree->callbacks(), m_tree->is_seq(node), m_tree, node);
338,784✔
315
            this->Writer::_do_write('[');
169,392✔
316
        }
317
    } // container
318

319
    for(id_type child = m_tree->first_child(node), count = 0; child != NONE; child = m_tree->next_sibling(child))
1,307,616✔
320
    {
321
        if(count++)
875,404✔
322
            this->Writer::_do_write(',');
466,926✔
323
        if(m_tree->is_keyval(child))
1,750,808✔
324
        {
325
            _writek(child, ilevel);
326
            this->Writer::_do_write(": ");
393,616✔
327
            _writev(child, ilevel);
328
        }
329
        else if(m_tree->is_val(child))
963,576✔
330
        {
331
            _writev(child, ilevel);
332
        }
333
        else
334
        {
335
            // with single-line flow, we can never go back to block
336
            _do_visit_flow_sl(child, depth + 1, ilevel + 1);
182,462✔
337
        }
338
    }
339

340
    if(m_tree->is_map(node))
864,424✔
341
    {
342
        this->Writer::_do_write('}');
260,642✔
343
    }
344
    else if(m_tree->is_seq(node))
343,140✔
345
    {
346
        this->Writer::_do_write(']');
171,570✔
347
    }
348
    m_flow = prev_flow;
432,212✔
349
}
432,212✔
350

351
C4_SUPPRESS_WARNING_MSVC_WITH_PUSH(4702) // unreachable error, triggered by flow_ml not implemented
352

353
template<class Writer>
354
void Emitter<Writer>::_do_visit_flow_ml(id_type id, id_type depth, id_type ilevel, id_type do_indent)
×
355
{
356
    C4_UNUSED(id);
357
    C4_UNUSED(depth);
358
    C4_UNUSED(ilevel);
359
    C4_UNUSED(do_indent);
NEW
360
    c4::yml::err_basic(RYML_LOC_HERE(), "not implemented");
×
361
    #ifdef THIS_IS_A_WORK_IN_PROGRESS
362
    if(C4_UNLIKELY(depth > m_opts.max_depth()))
363
        _RYML_CB_ERR(m_tree->callbacks(), "max depth exceeded");
364
    const bool prev_flow = m_flow;
365
    m_flow = true;
366
    // do it...
367
    m_flow = prev_flow;
368
    #endif
369
}
370

371
template<class Writer>
372
void Emitter<Writer>::_do_visit_block_container(id_type node, id_type depth, id_type level, bool do_indent)
956,166✔
373
{
374
    if(m_tree->is_seq(node))
1,912,332✔
375
    {
376
        for(id_type child = m_tree->first_child(node); child != NONE; child = m_tree->next_sibling(child))
1,185,922✔
377
        {
378
            _RYML_ASSERT_VISIT_(m_tree->callbacks(), !m_tree->has_key(child), m_tree, node);
1,715,036✔
379
            if(m_tree->is_val(child))
1,715,036✔
380
            {
381
                _indent(level, do_indent);
576,962✔
382
                this->Writer::_do_write("- ");
576,962✔
383
                _writev(child, level);
384
                this->Writer::_do_write('\n');
576,962✔
385
            }
386
            else
387
            {
388
                _RYML_ASSERT_VISIT_(m_tree->callbacks(), m_tree->is_container(child), m_tree, node);
561,112✔
389
                NodeType ty = m_tree->type(child);
280,556✔
390
                if(ty.is_flow_sl())
280,556✔
391
                {
392
                    _indent(level, do_indent);
51,030✔
393
                    this->Writer::_do_write("- ");
51,030✔
394
                    _do_visit_flow_sl(child, depth+1, 0u);
51,030✔
395
                    this->Writer::_do_write('\n');
51,030✔
396
                }
397
                else if(ty.is_flow_ml())
229,526✔
398
                {
399
                    _indent(level, do_indent);
×
400
                    this->Writer::_do_write("- ");
×
401
                    _do_visit_flow_ml(child, depth+1, 0u, do_indent);
×
402
                    this->Writer::_do_write('\n');
×
403
                }
404
                else
405
                {
406
                    _do_visit_block(child, depth+1, level, do_indent); // same indentation level
229,526✔
407
                }
408
            }
409
            do_indent = true;
857,446✔
410
        }
411
    }
412
    else // map
413
    {
414
        _RYML_ASSERT_VISIT_(m_tree->callbacks(), m_tree->is_map(node), m_tree, node);
1,255,380✔
415
        for(id_type ich = m_tree->first_child(node); ich != NONE; ich = m_tree->next_sibling(ich))
1,906,244✔
416
        {
417
            _RYML_ASSERT_VISIT_(m_tree->callbacks(), m_tree->has_key(ich), m_tree, node);
2,557,972✔
418
            if(m_tree->is_keyval(ich))
2,557,972✔
419
            {
420
                _indent(level, do_indent);
1,059,010✔
421
                _writek(ich, level);
422
                this->Writer::_do_write(": ");
1,059,010✔
423
                _writev(ich, level);
424
                this->Writer::_do_write('\n');
1,059,010✔
425
            }
426
            else
427
            {
428
                _RYML_ASSERT_VISIT_(m_tree->callbacks(), m_tree->is_container(ich), m_tree, node);
439,952✔
429
                NodeType ty = m_tree->type(ich);
219,976✔
430
                if(ty.is_flow_sl())
219,976✔
431
                {
432
                    _indent(level, do_indent);
22,088✔
433
                    _do_visit_flow_sl(ich, depth+1, 0u);
22,088✔
434
                    this->Writer::_do_write('\n');
22,088✔
435
                }
436
                else if(ty.is_flow_ml())
197,888✔
437
                {
438
                    _indent(level, do_indent);
×
439
                    _do_visit_flow_ml(ich, depth+1, 0u);
×
440
                    this->Writer::_do_write('\n');
×
441
                }
442
                else
443
                {
444
                    _do_visit_block(ich, depth+1, level, do_indent); // same level!
197,888✔
445
                }
446
            } // keyval vs container
447
            do_indent = true;
1,278,554✔
448
        } // for children
449
    } // seq vs map
450
}
955,662✔
451

452
template<class Writer>
453
void Emitter<Writer>::_do_visit_block(id_type node, id_type depth, id_type ilevel, id_type do_indent)
1,129,936✔
454
{
455
    _RYML_ASSERT_VISIT_(m_tree->callbacks(), !m_tree->is_stream(node), m_tree, node);
2,259,872✔
456
    _RYML_ASSERT_VISIT_(m_tree->callbacks(), m_tree->is_container(node) || m_tree->is_doc(node), m_tree, node);
2,436,708✔
457
    _RYML_ASSERT_VISIT_(m_tree->callbacks(), m_tree->is_root(node) || (m_tree->parent_is_map(node) || m_tree->parent_is_seq(node)), m_tree, node);
2,451,224✔
458
    if(C4_UNLIKELY(depth > m_opts.max_depth()))
2,259,872✔
459
        _RYML_ERR_VISIT_(m_tree->callbacks(), m_tree, node, "max depth exceeded");
504✔
460
    if(m_tree->is_doc(node))
2,258,864✔
461
    {
462
        _write_doc(node);
332,174✔
463
        if(!m_tree->has_children(node))
332,174✔
464
            return;
176,836✔
465
    }
466
    else if(m_tree->is_container(node))
1,594,516✔
467
    {
468
        _RYML_ASSERT_VISIT_(m_tree->callbacks(), m_tree->is_map(node) || m_tree->is_seq(node), m_tree, node);
1,879,644✔
469
        bool spc = false; // write a space
797,258✔
470
        bool nl = false;  // write a newline
797,258✔
471
        if(m_tree->has_key(node))
1,594,516✔
472
        {
473
            _indent(ilevel, do_indent);
197,456✔
474
            _writek(node, ilevel);
475
            this->Writer::_do_write(':');
197,456✔
476
            spc = true;
197,456✔
477
        }
478
        else if(!m_tree->is_root(node))
599,802✔
479
        {
480
            _indent(ilevel, do_indent);
229,454✔
481
            this->Writer::_do_write('-');
229,454✔
482
            spc = true;
229,454✔
483
        }
484

485
        if(m_tree->has_val_tag(node))
1,594,516✔
486
        {
487
            if(spc)
32,766✔
488
                this->Writer::_do_write(' ');
29,632✔
489
            _write_tag(m_tree->val_tag(node));
32,766✔
490
            spc = true;
32,766✔
491
            nl = true;
32,766✔
492
        }
493

494
        if(m_tree->has_val_anchor(node))
1,594,516✔
495
        {
496
            if(spc)
38,906✔
497
                this->Writer::_do_write(' ');
35,260✔
498
            this->Writer::_do_write('&');
38,906✔
499
            this->Writer::_do_write(m_tree->val_anchor(node));
38,906✔
500
            spc = true;
38,906✔
501
            nl = true;
38,906✔
502
        }
503

504
        if(m_tree->has_children(node))
797,258✔
505
        {
506
            if(m_tree->has_key(node))
1,594,276✔
507
                nl = true;
197,336✔
508
            else
509
                if(!m_tree->is_root(node) && !nl)
599,802✔
510
                    spc = true;
209,982✔
511
        }
512
        else
513
        {
514
            if(m_tree->is_seq(node))
240✔
515
                this->Writer::_do_write(" []\n");
60✔
516
            else if(m_tree->is_map(node))
120✔
517
                this->Writer::_do_write(" {}\n");
60✔
518
            return;
120✔
519
        }
520

521
        if(spc && !nl)
797,138✔
522
            this->Writer::_do_write(' ');
209,982✔
523

524
        do_indent = 0;
797,138✔
525
        if(nl)
797,138✔
526
        {
527
            this->Writer::_do_write('\n');
223,588✔
528
            do_indent = 1;
223,588✔
529
        }
530
    } // container
531

532
    id_type next_level = ilevel + 1;
952,476✔
533
    if(m_tree->is_root(node) || m_tree->is_doc(node))
1,534,604✔
534
        next_level = ilevel; // do not indent at top level
525,686✔
535

536
    _do_visit_block_container(node, depth, next_level, do_indent);
952,476✔
537
}
538

539
C4_SUPPRESS_WARNING_MSVC_POP
540

541

542
template<class Writer>
543
void Emitter<Writer>::_do_visit_json(id_type id, id_type depth)
552,780✔
544
{
545
    _RYML_CHECK_VISIT_(m_tree->callbacks(), !m_tree->is_stream(id), m_tree, id); // JSON does not have streams
1,105,560✔
546
    if(C4_UNLIKELY(depth > m_opts.max_depth()))
1,105,560✔
547
        _RYML_ERR_VISIT_(m_tree->callbacks(), m_tree, id, "max depth exceeded");
648✔
548
    if(m_tree->is_keyval(id))
1,104,264✔
549
    {
550
        _writek_json(id);
551
        this->Writer::_do_write(": ");
15,048✔
552
        _writev_json(id);
553
    }
554
    else if(m_tree->is_val(id))
1,074,168✔
555
    {
556
        _writev_json(id);
557
    }
558
    else if(m_tree->is_container(id))
1,021,596✔
559
    {
560
        if(m_tree->has_key(id))
40,908✔
561
        {
562
            _writek_json(id);
563
            this->Writer::_do_write(": ");
9,054✔
564
        }
565
        if(m_tree->is_seq(id))
40,908✔
566
            this->Writer::_do_write('[');
7,224✔
567
        else if(m_tree->is_map(id))
26,460✔
568
            this->Writer::_do_write('{');
13,230✔
569
    }  // container
570

571
    for(id_type ich = m_tree->first_child(id); ich != NONE; ich = m_tree->next_sibling(ich))
601,020✔
572
    {
573
        if(ich != m_tree->first_child(id))
49,536✔
574
            this->Writer::_do_write(',');
29,082✔
575
        _do_visit_json(ich, depth+1);
49,536✔
576
    }
577

578
    if(m_tree->is_seq(id))
1,102,968✔
579
        this->Writer::_do_write(']');
7,080✔
580
    else if(m_tree->is_map(id))
1,088,808✔
581
        this->Writer::_do_write('}');
12,726✔
582
}
551,484✔
583

584
template<class Writer>
585
void Emitter<Writer>::_write(NodeScalar const& C4_RESTRICT sc, NodeType flags, id_type ilevel)
4,418,478✔
586
{
587
    if( ! sc.tag.empty())
8,836,956✔
588
    {
589
        _write_tag(sc.tag);
175,442✔
590
        this->Writer::_do_write(' ');
175,442✔
591
    }
592
    if(flags.has_anchor())
4,418,478✔
593
    {
594
        _RYML_ASSERT_VISIT_(m_tree->callbacks(), flags.is_ref() != flags.has_anchor(), m_tree, NONE);
285,104✔
595
        _RYML_ASSERT_VISIT_(m_tree->callbacks(),  ! sc.anchor.empty(), m_tree, NONE);
285,104✔
596
        this->Writer::_do_write('&');
142,552✔
597
        this->Writer::_do_write(sc.anchor);
142,552✔
598
        this->Writer::_do_write(' ');
142,552✔
599
    }
600
    else if(flags.is_ref())
4,275,926✔
601
    {
602
        if(sc.anchor != "<<")
108,336✔
603
            this->Writer::_do_write('*');
54,168✔
604
        this->Writer::_do_write(sc.anchor);
54,168✔
605
        if(flags.is_key_ref())
54,168✔
606
            this->Writer::_do_write(' ');
12,924✔
607
        return;
54,168✔
608
    }
609

610
    // ensure the style flags only have one of KEY or VAL
611
    _RYML_ASSERT_VISIT_(m_tree->callbacks(), ((flags & SCALAR_STYLE) == 0) || (((flags & KEY_STYLE) == 0) != ((flags & VAL_STYLE) == 0)), m_tree, NONE);
26,147,028✔
612
    type_bits style_marks = flags & SCALAR_STYLE;
4,364,310✔
613
    if(!style_marks)
4,364,310✔
614
        style_marks = scalar_style_choose(sc.scalar);
9,708✔
615
    if(style_marks & (KEY_LITERAL|VAL_LITERAL))
4,364,310✔
616
    {
617
        _write_scalar_literal(sc.scalar, ilevel, flags.has_key());
184,148✔
618
    }
619
    else if(style_marks & (KEY_FOLDED|VAL_FOLDED))
4,180,162✔
620
    {
621
        _write_scalar_folded(sc.scalar, ilevel, flags.has_key());
99,624✔
622
    }
623
    else if(style_marks & (KEY_SQUO|VAL_SQUO))
4,080,538✔
624
    {
625
        _write_scalar_squo(sc.scalar, ilevel);
120,104✔
626
    }
627
    else if(style_marks & (KEY_DQUO|VAL_DQUO))
3,960,434✔
628
    {
629
        _write_scalar_dquo(sc.scalar, ilevel);
864,738✔
630
    }
631
    else if(style_marks & (KEY_PLAIN|VAL_PLAIN))
3,095,696✔
632
    {
633
        if(C4_LIKELY(!(sc.scalar.begins_with(": ") || sc.scalar.begins_with(":\t"))))
3,095,696✔
634
            _write_scalar_plain(sc.scalar, ilevel);
3,095,444✔
635
        else
636
            _write_scalar_squo(sc.scalar, ilevel);
252✔
637
    }
638
    else
639
    {
NEW
640
        _RYML_ERR_VISIT_(m_tree->callbacks(), m_tree, NONE, "not implemented");
×
641
    }
642
}
643

644
template<class Writer>
645
void Emitter<Writer>::_write_json(NodeScalar const& C4_RESTRICT sc, NodeType flags)
65,436✔
646
{
647
    if(flags & (KEYTAG|VALTAG))
196,308✔
648
        if(m_opts.json_error_flags() & EmitOptions::JSON_ERR_ON_TAG)
×
NEW
649
            _RYML_ERR_VISIT_(m_tree->callbacks(), m_tree, NONE, "JSON does not have tags");
×
650
    if(C4_UNLIKELY(flags.has_anchor()))
65,436✔
651
        if(m_opts.json_error_flags() & EmitOptions::JSON_ERR_ON_ANCHOR)
×
NEW
652
            _RYML_ERR_VISIT_(m_tree->callbacks(), m_tree, NONE, "JSON does not have anchors");
×
653
    if(sc.scalar.len)
65,436✔
654
    {
655
        // use double quoted style...
656
        // if it is a key (mandatory in JSON)
657
        // if the style is marked quoted
658
        bool dquoted = ((flags & (KEY|VALQUO))
119,472✔
659
                        || (scalar_style_json_choose(sc.scalar) & SCALAR_DQUO)); // choose the style
100,770✔
660
        if(dquoted)
59,736✔
661
            _write_scalar_json_dquo(sc.scalar);
47,922✔
662
        else
663
            this->Writer::_do_write(sc.scalar);
11,814✔
664
    }
665
    else
666
    {
667
        if(sc.scalar.str || (flags & (KEY|VALQUO|KEYTAG|VALTAG)))
11,400✔
668
            this->Writer::_do_write("\"\"");
5,700✔
669
        else
670
            this->Writer::_do_write("null");
×
671
    }
672
}
65,436✔
673

674
template<class Writer>
675
size_t Emitter<Writer>::_write_escaped_newlines(csubstr s, size_t i)
70,512✔
676
{
677
    _RYML_ASSERT_BASIC_(m_tree->callbacks(), s.len > i);
70,512✔
678
    _RYML_ASSERT_BASIC_(m_tree->callbacks(), s.str[i] == '\n');
70,512✔
679
    //_c4dbgpf("nl@i={} rem=[{}]~~~{}~~~", i, s.sub(i).len, s.sub(i));
680
    // add an extra newline for each sequence of consecutive
681
    // newline/whitespace
682
    this->Writer::_do_write('\n');
70,512✔
683
    do
684
    {
685
        this->Writer::_do_write('\n'); // write the newline again
95,678✔
686
        ++i; // increase the outer loop counter!
95,678✔
687
    } while(i < s.len && s.str[i] == '\n');
95,678✔
688
    _RYML_ASSERT_BASIC_(m_tree->callbacks(), i > 0);
70,512✔
689
    --i;
70,512✔
690
    _RYML_ASSERT_BASIC_(m_tree->callbacks(), s.str[i] == '\n');
70,512✔
691
    return i;
70,512✔
692
}
693

694
inline bool _is_indented_block(csubstr s, size_t prev, size_t i) noexcept
52,306✔
695
{
696
    if(prev == 0 && s.begins_with_any(" \t"))
91,464✔
697
        return true;
4,172✔
698
    const size_t pos = s.first_not_of('\n', i);
48,134✔
699
    return (pos != npos) && (s.str[pos] == ' ' || s.str[pos] == '\t');
48,134✔
700
}
701

702
template<class Writer>
703
size_t Emitter<Writer>::_write_indented_block(csubstr s, size_t i, id_type ilevel)
13,008✔
704
{
705
    //_c4dbgpf("indblock@i={} rem=[{}]~~~\n{}~~~", i, s.sub(i).len, s.sub(i));
706
    _RYML_ASSERT_BASIC_(m_tree->callbacks(), i > 0);
13,008✔
707
    _RYML_ASSERT_BASIC_(m_tree->callbacks(), s.str[i-1] == '\n');
13,008✔
708
    _RYML_ASSERT_BASIC_(m_tree->callbacks(), i < s.len);
13,008✔
709
    _RYML_ASSERT_BASIC_(m_tree->callbacks(), s.str[i] == ' ' || s.str[i] == '\t' || s.str[i] == '\n');
13,008✔
710
again:
44,056✔
711
    size_t pos = s.find("\n ", i);
31,048✔
712
    if(pos == npos)
31,048✔
713
        pos = s.find("\n\t", i);
14,286✔
714
    if(pos != npos)
31,048✔
715
    {
716
        ++pos;
18,040✔
717
        //_c4dbgpf("indblock line@i={} rem=[{}]~~~\n{}~~~", i, s.range(i, pos).len, s.range(i, pos));
718
        _rymlindent_nextline();
18,040✔
719
        this->Writer::_do_write(s.range(i, pos));
36,080✔
720
        i = pos;
18,040✔
721
        goto again; // NOLINT
18,040✔
722
    }
723
    // consume the newlines after the indented block
724
    // to prevent them from being escaped
725
    pos = s.find('\n', i);
13,008✔
726
    if(pos != npos)
13,008✔
727
    {
728
        const size_t pos2 = s.first_not_of('\n', pos);
13,008✔
729
        pos = (pos2 != npos) ? pos2 : pos;
13,008✔
730
        //_c4dbgpf("indblock line@i={} rem=[{}]~~~\n{}~~~", i, s.range(i, pos).len, s.range(i, pos));
731
        _rymlindent_nextline();
13,008✔
732
        this->Writer::_do_write(s.range(i, pos));
26,016✔
733
        i = pos;
13,008✔
734
    }
735
    return i;
13,008✔
736
}
737

738
template<class Writer>
739
void Emitter<Writer>::_write_scalar_literal(csubstr s, id_type ilevel, bool explicit_key)
184,148✔
740
{
741
    _RYML_ASSERT_BASIC_(m_tree->callbacks(), s.find("\r") == csubstr::npos);
184,148✔
742
    if(explicit_key)
184,148✔
743
        this->Writer::_do_write("? ");
5,120✔
744
    csubstr trimmed = s.trimr('\n');
184,148✔
745
    const size_t numnewlines_at_end = s.len - trimmed.len;
184,148✔
746
    const bool is_newline_only = (trimmed.len == 0 && (s.len > 0));
184,148✔
747
    const bool explicit_indentation = s.triml("\n\r").begins_with_any(" \t");
368,296✔
748
    //
749
    this->Writer::_do_write('|');
184,148✔
750
    if(explicit_indentation)
184,148✔
751
        this->Writer::_do_write('2');
14,710✔
752
    //
753
    if(numnewlines_at_end > 1 || is_newline_only)
184,148✔
754
        this->Writer::_do_write('+');
22,782✔
755
    else if(numnewlines_at_end == 0)
161,366✔
756
        this->Writer::_do_write('-');
38,904✔
757
    //
758
    if(trimmed.len)
184,148✔
759
    {
760
        this->Writer::_do_write('\n');
157,842✔
761
        size_t pos = 0; // tracks the last character that was already written
157,842✔
762
        for(size_t i = 0; i < trimmed.len; ++i)
2,760,624✔
763
        {
764
            if(trimmed[i] != '\n')
2,602,782✔
765
                continue;
2,480,626✔
766
            // write everything up to this point
767
            csubstr since_pos = trimmed.range(pos, i+1); // include the newline
122,156✔
768
            _rymlindent_nextline()
122,156✔
769
            this->Writer::_do_write(since_pos);
122,156✔
770
            pos = i+1; // already written
122,156✔
771
        }
772
        if(pos < trimmed.len)
157,842✔
773
        {
774
            _rymlindent_nextline()
157,842✔
775
            this->Writer::_do_write(trimmed.sub(pos));
315,684✔
776
        }
777
    }
778
    for(size_t i = !is_newline_only; i < numnewlines_at_end; ++i)
217,654✔
779
        this->Writer::_do_write('\n');
33,506✔
780
    if(explicit_key)
184,148✔
781
    {
782
        this->Writer::_do_write('\n');
5,120✔
783
        this->_indent(ilevel);
5,120✔
784
    }
785
}
184,148✔
786

787
template<class Writer>
788
void Emitter<Writer>::_write_scalar_folded(csubstr s, id_type ilevel, bool explicit_key)
99,624✔
789
{
790
    if(explicit_key)
99,624✔
791
        this->Writer::_do_write("? ");
2,202✔
792
    _RYML_ASSERT_BASIC_(m_tree->callbacks(), s.find("\r") == csubstr::npos);
99,624✔
793
    csubstr trimmed = s.trimr('\n');
99,624✔
794
    const size_t numnewlines_at_end = s.len - trimmed.len;
99,624✔
795
    const bool is_newline_only = (trimmed.len == 0 && (s.len > 0));
99,624✔
796
    const bool explicit_indentation = s.triml("\n\r").begins_with_any(" \t");
199,248✔
797
    //
798
    this->Writer::_do_write('>');
99,624✔
799
    if(explicit_indentation)
99,624✔
800
        this->Writer::_do_write('2');
13,202✔
801
    //
802
    if(numnewlines_at_end == 0)
99,624✔
803
        this->Writer::_do_write('-');
19,902✔
804
    else if(numnewlines_at_end > 1 || is_newline_only)
79,722✔
805
        this->Writer::_do_write('+');
3,828✔
806
    //
807
    if(trimmed.len)
99,624✔
808
    {
809
        this->Writer::_do_write('\n');
88,974✔
810
        size_t pos = 0; // tracks the last character that was already written
88,974✔
811
        for(size_t i = 0; i < trimmed.len; ++i)
2,049,264✔
812
        {
813
            if(trimmed[i] != '\n')
1,960,290✔
814
                continue;
1,907,984✔
815
            // escape newline sequences
816
            if( ! _is_indented_block(s, pos, i))
52,306✔
817
            {
818
                if(pos < i)
35,126✔
819
                {
820
                    _rymlindent_nextline()
25,562✔
821
                    this->Writer::_do_write(s.range(pos, i));
51,124✔
822
                    i = _write_escaped_newlines(s, i);
25,562✔
823
                    pos = i+1;
25,562✔
824
                }
825
                else
826
                {
827
                    if(i+1 < s.len)
9,564✔
828
                    {
829
                        if(s.str[i+1] == '\n')
9,564✔
830
                        {
831
                            ++i;
5,866✔
832
                            i = _write_escaped_newlines(s, i);
5,866✔
833
                            pos = i+1;
5,866✔
834
                        }
835
                        else
836
                        {
837
                            this->Writer::_do_write('\n');
3,698✔
838
                            pos = i+1;
3,698✔
839
                        }
840
                    }
841
                }
842
            }
843
            else // do not escape newlines in indented blocks
844
            {
845
                ++i;
17,180✔
846
                _rymlindent_nextline()
17,180✔
847
                this->Writer::_do_write(s.range(pos, i));
34,360✔
848
                if(pos > 0 || !s.begins_with_any(" \t"))
30,662✔
849
                    i = _write_indented_block(s, i, ilevel);
13,008✔
850
                pos = i;
17,180✔
851
            }
852
        }
853
        if(pos < trimmed.len)
88,974✔
854
        {
855
            _rymlindent_nextline()
86,838✔
856
            this->Writer::_do_write(trimmed.sub(pos));
173,676✔
857
        }
858
    }
859
    for(size_t i = !is_newline_only; i < numnewlines_at_end; ++i)
105,684✔
860
        this->Writer::_do_write('\n');
6,060✔
861
    if(explicit_key)
99,624✔
862
    {
863
        this->Writer::_do_write('\n');
2,202✔
864
        this->_indent(ilevel);
2,202✔
865
    }
866
}
99,624✔
867

868
template<class Writer>
869
void Emitter<Writer>::_write_scalar_squo(csubstr s, id_type ilevel)
120,356✔
870
{
871
    size_t pos = 0; // tracks the last character that was already written
120,356✔
872
    this->Writer::_do_write('\'');
120,356✔
873
    for(size_t i = 0; i < s.len; ++i)
1,571,828✔
874
    {
875
        if(s[i] == '\n')
1,451,472✔
876
        {
877
            this->Writer::_do_write(s.range(pos, i));  // write everything up to (excluding) this char
47,744✔
878
            //_c4dbgpf("newline at {}. writing ~~~{}~~~", i, s.range(pos, i));
879
            i = _write_escaped_newlines(s, i);
23,872✔
880
            //_c4dbgpf("newline --> {}", i);
881
            if(i < s.len)
23,872✔
882
                _rymlindent_nextline()
23,872✔
883
            pos = i+1;
23,872✔
884
        }
885
        else if(s[i] == '\'')
1,427,600✔
886
        {
887
            csubstr sub = s.range(pos, i+1);
14,958✔
888
            //_c4dbgpf("squote at {}. writing ~~~{}~~~", i, sub);
889
            this->Writer::_do_write(sub); // write everything up to (including) this squote
14,958✔
890
            this->Writer::_do_write('\''); // write the squote again
14,958✔
891
            pos = i+1;
14,958✔
892
        }
893
    }
894
    // write missing characters at the end of the string
895
    if(pos < s.len)
120,356✔
896
        this->Writer::_do_write(s.sub(pos));
216,308✔
897
    this->Writer::_do_write('\'');
120,356✔
898
}
120,356✔
899

900
template<class Writer>
901
void Emitter<Writer>::_write_scalar_dquo(csubstr s, id_type ilevel)
864,738✔
902
{
903
    size_t pos = 0; // tracks the last character that was already written
864,738✔
904
    this->Writer::_do_write('"');
864,738✔
905
    for(size_t i = 0; i < s.len; ++i)
10,259,096✔
906
    {
907
        const char curr = s.str[i];
9,394,358✔
908
        switch(curr) // NOLINT
9,394,358✔
909
        {
910
        case '"':
36,062✔
911
        case '\\':
912
        {
913
            csubstr sub = s.range(pos, i);
36,062✔
914
            this->Writer::_do_write(sub);  // write everything up to (excluding) this char
36,062✔
915
            this->Writer::_do_write('\\'); // write the escape
36,062✔
916
            this->Writer::_do_write(curr); // write the char
36,062✔
917
            pos = i+1;
36,062✔
918
            break;
36,062✔
919
        }
920
#ifndef prefer_writing_newlines_as_double_newlines
921
        case '\n':
267,508✔
922
        {
923
            csubstr sub = s.range(pos, i);
267,508✔
924
            this->Writer::_do_write(sub);   // write everything up to (excluding) this char
267,508✔
925
            this->Writer::_do_write("\\n"); // write the escape
267,508✔
926
            pos = i+1;
267,508✔
927
            (void)ilevel;
928
            break;
267,508✔
929
        }
930
#else
931
        case '\n':
932
        {
933
            // write everything up to (excluding) this newline
934
            //_c4dbgpf("nl@i={} rem=[{}]~~~{}~~~", i, s.sub(i).len, s.sub(i));
935
            this->Writer::_do_write(s.range(pos, i));
936
            i = _write_escaped_newlines(s, i);
937
            ++i;
938
            pos = i;
939
            // as for the next line...
940
            if(i < s.len)
941
            {
942
                _rymlindent_nextline() // indent the next line
943
                // escape leading whitespace, and flush it
944
                size_t first = s.first_not_of(" \t", i);
945
                _c4dbgpf("@i={} first={} rem=[{}]~~~{}~~~", i, first, s.sub(i).len, s.sub(i));
946
                if(first > i)
947
                {
948
                    if(first == npos)
949
                        first = s.len;
950
                    this->Writer::_do_write('\\');
951
                    this->Writer::_do_write(s.range(i, first));
952
                    this->Writer::_do_write('\\');
953
                    i = first-1;
954
                    pos = first;
955
                }
956
            }
957
            break;
958
        }
959
        // escape trailing whitespace before a newline
960
        case ' ':
961
        case '\t':
962
        {
963
            const size_t next = s.first_not_of(" \t\r", i);
964
            if(next != npos && s.str[next] == '\n')
965
            {
966
                csubstr sub = s.range(pos, i);
967
                this->Writer::_do_write(sub);  // write everything up to (excluding) this char
968
                this->Writer::_do_write('\\'); // escape the whitespace
969
                pos = i;
970
            }
971
            break;
972
        }
973
#endif
974
        case '\r':
8,958✔
975
        {
976
            csubstr sub = s.range(pos, i);
8,958✔
977
            this->Writer::_do_write(sub);  // write everything up to (excluding) this char
8,958✔
978
            this->Writer::_do_write("\\r"); // write the escaped char
8,958✔
979
            pos = i+1;
8,958✔
980
            break;
8,958✔
981
        }
982
        case '\b':
6,018✔
983
        {
984
            csubstr sub = s.range(pos, i);
6,018✔
985
            this->Writer::_do_write(sub);  // write everything up to (excluding) this char
6,018✔
986
            this->Writer::_do_write("\\b"); // write the escaped char
6,018✔
987
            pos = i+1;
6,018✔
988
            break;
6,018✔
989
        }
990
        }
991
    }
992
    // write missing characters at the end of the string
993
    if(pos < s.len)
864,738✔
994
        this->Writer::_do_write(s.sub(pos));
1,518,672✔
995
    this->Writer::_do_write('"');
864,738✔
996
}
864,738✔
997

998
template<class Writer>
999
void Emitter<Writer>::_write_scalar_plain(csubstr s, id_type ilevel)
3,095,444✔
1000
{
1001
    if(C4_UNLIKELY(ilevel == 0 && (s.begins_with("...") || s.begins_with("---"))))
6,634,848✔
1002
    {
1003
        _rymlindent_nextline()     // indent the next line
3,558✔
1004
        ++ilevel;
3,558✔
1005
    }
1006
    size_t pos = 0; // tracks the last character that was already written
3,095,444✔
1007
    for(size_t i = 0; i < s.len; ++i)
19,029,398✔
1008
    {
1009
        const char curr = s.str[i];
15,933,954✔
1010
        if(curr == '\n')
15,933,954✔
1011
        {
1012
            csubstr sub = s.range(pos, i);
15,212✔
1013
            this->Writer::_do_write(sub);  // write everything up to (including) this newline
15,212✔
1014
            i = _write_escaped_newlines(s, i);
15,212✔
1015
            pos = i+1;
15,212✔
1016
            if(pos < s.len)
15,212✔
1017
                _rymlindent_nextline()     // indent the next line
15,212✔
1018
        }
1019
    }
1020
    // write missing characters at the end of the string
1021
    if(pos < s.len)
3,095,444✔
1022
        this->Writer::_do_write(s.sub(pos));
5,817,416✔
1023
}
3,095,444✔
1024

1025
#undef _rymlindent_nextline
1026

1027
template<class Writer>
1028
void Emitter<Writer>::_write_scalar_json_dquo(csubstr s)
47,922✔
1029
{
1030
    size_t pos = 0;
47,922✔
1031
    this->Writer::_do_write('"');
47,922✔
1032
    for(size_t i = 0; i < s.len; ++i)
263,040✔
1033
    {
1034
        switch(s.str[i])
215,118✔
1035
        {
1036
        case '"':
12✔
1037
            this->Writer ::_do_write(s.range(pos, i));
24✔
1038
            this->Writer ::_do_write("\\\"");
12✔
1039
            pos = i + 1;
12✔
1040
            break;
12✔
1041
        case '\n':
36✔
1042
            this->Writer ::_do_write(s.range(pos, i));
72✔
1043
            this->Writer ::_do_write("\\n");
36✔
1044
            pos = i + 1;
36✔
1045
            break;
36✔
1046
        case '\t':
12✔
1047
            this->Writer ::_do_write(s.range(pos, i));
24✔
1048
            this->Writer ::_do_write("\\t");
12✔
1049
            pos = i + 1;
12✔
1050
            break;
12✔
1051
        case '\\':
12✔
1052
            this->Writer ::_do_write(s.range(pos, i));
24✔
1053
            this->Writer ::_do_write("\\\\");
12✔
1054
            pos = i + 1;
12✔
1055
            break;
12✔
1056
        case '\r':
12✔
1057
            this->Writer ::_do_write(s.range(pos, i));
24✔
1058
            this->Writer ::_do_write("\\r");
12✔
1059
            pos = i + 1;
12✔
1060
            break;
12✔
1061
        case '\b':
12✔
1062
            this->Writer ::_do_write(s.range(pos, i));
24✔
1063
            this->Writer ::_do_write("\\b");
12✔
1064
            pos = i + 1;
12✔
1065
            break;
12✔
1066
        case '\f':
12✔
1067
            this->Writer ::_do_write(s.range(pos, i));
24✔
1068
            this->Writer ::_do_write("\\f");
12✔
1069
            pos = i + 1;
12✔
1070
            break;
12✔
1071
        }
1072
    }
1073
    if(pos < s.len)
47,922✔
1074
    {
1075
        csubstr sub = s.sub(pos);
31,940✔
1076
        this->Writer::_do_write(sub);
47,910✔
1077
    }
1078
    this->Writer::_do_write('"');
47,922✔
1079
}
47,922✔
1080

1081
} // namespace yml
1082
} // namespace c4
1083

1084
#endif /* _C4_YML_EMIT_DEF_HPP_ */
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc