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

biojppm / rapidyaml / 18162524607

01 Oct 2025 12:42PM UTC coverage: 97.638% (-0.01%) from 97.65%
18162524607

Pull #503

github

web-flow
Merge 4bf898896 into 653eac974
Pull Request #503: Improve error model, callbacks

1795 of 1842 new or added lines in 32 files covered. (97.45%)

38 existing lines in 4 files now uncovered.

13597 of 13926 relevant lines covered (97.64%)

534874.49 hits per line

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

84.52
/src_extra/c4/yml/extra/string.hpp
1
#ifndef _C4_YML_EXTRA_STRING_HPP_
2
#define _C4_YML_EXTRA_STRING_HPP_
3

4
#ifndef RYML_SINGLE_HEADER
5
#ifndef _C4_YML_COMMON_HPP_
6
#include "c4/yml/common.hpp"
7
#endif
8
#endif
9

10
#include <new>
11

12
C4_SUPPRESS_WARNING_GCC_CLANG_PUSH
13
C4_SUPPRESS_WARNING_GCC_CLANG("-Wold-style-cast")
14
C4_SUPPRESS_WARNING_GCC("-Wuseless-cast")
15

16
#ifndef RYML_STRING_SSO_SIZE
17
#define RYML_STRING_SSO_SIZE 128
18
#endif
19

20
#ifndef RYML_STRING_LIST_SSO_SIZE
21
#define RYML_STRING_LIST_SSO_SIZE 66
22
#endif
23

24
namespace c4 {
25
namespace yml {
26
namespace extra {
27

28
/** an owning string class used by the yaml std event handler (and the
29
 * YamlScript handler). we use this instead of std::string because:
30
 *  1) this spares the dependency on the standard library
31
 *  2) enables possibility of adding borrowing semantics (in the future) */
32
struct string
33
{
34
    enum : id_type { sso_size = RYML_STRING_SSO_SIZE };
35
    char m_buf[sso_size];
36
    char *C4_RESTRICT m_str;
37
    id_type m_size;
38
    id_type m_capacity;
39

40
public:
41

42
    string()
1,178,456✔
43
        : m_buf()
152,020,824✔
44
        , m_str(m_buf)
1,178,456✔
45
        , m_size(0)
1,178,456✔
46
        , m_capacity(sso_size)
1,178,456✔
47
    {}
1,178,456✔
48
    ~string() noexcept
1,177,414✔
49
    {
50
        _free();
1,177,414✔
51
    }
1,177,414✔
52

53
    string(string const& that) RYML_NOEXCEPT : string()
54
    {
55
        resize(that.m_size);
56
        _cp(&that);
57
    }
58

59
    string(string &&that) noexcept : string()
×
60
    {
61
        _mv(&that);
×
62
    }
×
63

64
    string& operator= (string const& that) RYML_NOEXCEPT
65
    {
66
        resize(that.m_size);
67
        _cp(&that);
68
        return *this;
69
    }
70

71
    string& operator= (string &&that) noexcept
4✔
72
    {
73
        _mv(&that);
4✔
74
        return *this;
4✔
75
    }
76

77
public:
78

79
    C4_ALWAYS_INLINE C4_HOT operator csubstr() const noexcept { return {m_str, m_size}; }
579,784✔
80
    C4_ALWAYS_INLINE C4_HOT operator substr() noexcept { return {m_str, m_size}; }
367,500✔
81

82
public:
83

84
    const char* data() const noexcept { return m_str; }
4✔
85
    id_type size() const noexcept { return m_size; }
407,596✔
86
    id_type capacity() const noexcept { return m_capacity; }
182,828✔
87

88
    void clear()
550,356✔
89
    {
90
        m_size = 0;
550,356✔
91
    }
550,356✔
92

93
    void resize(id_type sz)
877,260✔
94
    {
95
        reserve(sz);
877,260✔
96
        m_size = sz;
877,260✔
97
    }
877,260✔
98

99
    void reserve(id_type sz)
1,157,404✔
100
    {
101
        if(sz <= m_capacity)
1,157,404✔
102
            return;
501,144✔
103
        id_type cap = m_capacity < string::sso_size ? string::sso_size : 2 * m_capacity;
656,260✔
104
        cap = cap > sz ? cap : sz;
656,260✔
105
        if(cap <= sso_size)
656,260✔
106
            return;
×
107
        Callbacks cb = get_callbacks();
656,260✔
108
        char *buf = (char*) _RYML_CB_ALLOC(cb, char, cap);
656,260✔
109
        if(m_size)
656,260✔
110
            memcpy(buf, m_str, (size_t)m_size);
18,332✔
111
        if(m_str != m_buf)
656,260✔
112
        {
113
            _RYML_CB_FREE(cb, m_str, char, m_size);
4,876✔
114
        }
115
        m_str = buf;
656,260✔
116
        m_capacity = cap;
656,260✔
117
    }
118

119
public:
120

121
    C4_ALWAYS_INLINE C4_HOT void append(char c)
122
    {
123
        if(C4_UNLIKELY(m_size == m_capacity))
636,916✔
124
            reserve(m_size + 1);
744✔
125
        m_str[m_size++] = c;
636,916✔
126
    }
636,916✔
127
    C4_ALWAYS_INLINE C4_HOT void append(csubstr cs)
128
    {
129
        if(cs.len)
755,728✔
130
        {
131
            const id_type ilen = (id_type)cs.len;
751,160✔
132
            if(C4_UNLIKELY(m_size + ilen > m_capacity))
751,160✔
133
                reserve(m_size + ilen);
26,484✔
134
            memcpy(m_str + m_size, cs.str, cs.len);
751,160✔
135
            m_size += ilen;
751,160✔
136
        }
137
    }
755,728✔
138
    C4_ALWAYS_INLINE void insert(char c, id_type pos)
139
    {
140
        _RYML_ASSERT_BASIC(pos <= m_size);
141
        if(pos < m_size)
142
        {
143
            if(C4_UNLIKELY(m_size == m_capacity))
144
                reserve(m_size + 1);
145
            char *C4_RESTRICT src = m_str + pos;
146
            memmove(src + 1, src, m_size - pos);
147
            *src = c;
148
            ++m_size;
149
        }
150
        else
151
        {
152
            append(c);
153
        }
154
    }
155
    C4_NO_INLINE void insert(csubstr cs, id_type pos)
124✔
156
    {
157
        _RYML_ASSERT_BASIC(pos <= m_size);
124✔
158
        if(cs.len)
124✔
159
        {
160
            if(pos < m_size)
124✔
161
            {
162
                const id_type ilen = (id_type)cs.len;
124✔
163
                if(C4_UNLIKELY(m_size + ilen > m_capacity))
124✔
164
                    reserve(m_size + ilen);
×
165
                char *C4_RESTRICT src = m_str + pos;
124✔
166
                memmove(src + cs.len, src, m_size - pos);
124✔
167
                memcpy(src, cs.str, cs.len);
124✔
168
                m_size += ilen;
124✔
169
            }
170
            else
171
            {
172
                append(cs);
×
173
            }
174
        }
175
    }
124✔
176
    C4_NO_INLINE size_t find_last(csubstr pattern) RYML_NOEXCEPT
148✔
177
    {
178
        _RYML_ASSERT_BASIC(pattern.len);
148✔
179
        if(m_size >= pattern.len)
148✔
180
        {
181
            for(size_t i = m_size - pattern.len; i != (size_t)-1; --i)
6,500✔
182
            {
183
                if(m_str[i] == pattern[0])
12,952✔
184
                {
185
                    bool gotit = true;
308✔
186
                    for(size_t j = 1; j < pattern.len; ++j)
972✔
187
                    {
188
                        if(m_str[i + j] != pattern[j])
1,696✔
189
                        {
190
                            gotit = false;
184✔
191
                            break;
184✔
192
                        }
193
                    }
194
                    if(gotit)
308✔
195
                        return i;
124✔
196
                }
197
            }
198
        }
199
        return npos;
24✔
200
    }
201

202
public:
203

204
    void _free()
1,177,414✔
205
    {
206
        _RYML_ASSERT_BASIC(m_str != nullptr); // this structure cannot be memset() to zero
1,177,414✔
207
        if(m_str != m_buf)
1,177,414✔
208
        {
209
            _RYML_CB_FREE(get_callbacks(), m_str, char, (size_t)m_capacity);
650,930✔
210
            m_str = m_buf;
650,930✔
211
            m_capacity = sso_size;
650,930✔
212
        }
213
        _RYML_ASSERT_BASIC(m_capacity == sso_size);
1,177,414✔
214
        m_size = 0;
1,177,414✔
215
    }
1,177,414✔
216

217
    void _cp(string const* C4_RESTRICT that)
218
    {
219
        #if RYML_USE_ASSERT
220
        if(that->m_str != that->m_buf)
221
        {
222
            _RYML_ASSERT_BASIC(that->m_capacity > sso_size);
223
            _RYML_ASSERT_BASIC(that->m_size <= that->m_capacity);
224
        }
225
        else
226
        {
227
            _RYML_ASSERT_BASIC(that->m_capacity <= sso_size);
228
            _RYML_ASSERT_BASIC(that->m_size <= that->m_capacity);
229
        }
230
        #endif
231
        memcpy(m_str, that->m_str, that->m_size);
232
        m_size = that->m_size;
233
        m_capacity = that->m_size < sso_size ? sso_size : that->m_size;
234
    }
235

236
    void _mv(string *C4_RESTRICT that)
4✔
237
    {
238
        if(that->m_str != that->m_buf)
4✔
239
        {
NEW
240
            _RYML_ASSERT_BASIC(that->m_capacity > sso_size);
×
NEW
241
            _RYML_ASSERT_BASIC(that->m_size <= that->m_capacity);
×
UNCOV
242
            m_str = that->m_str;
×
243
        }
244
        else
245
        {
246
            _RYML_ASSERT_BASIC(that->m_capacity <= sso_size);
4✔
247
            _RYML_ASSERT_BASIC(that->m_size <= that->m_capacity);
4✔
248
            memcpy(m_buf, that->m_buf, that->m_size);
4✔
249
            m_str = m_buf;
4✔
250
        }
251
        m_size = that->m_size;
4✔
252
        m_capacity = that->m_capacity;
4✔
253
        // make sure no deallocation happens on destruction
254
        _RYML_ASSERT_BASIC(that->m_str != this->m_buf);
4✔
255
        that->m_str = that->m_buf;
4✔
256
        that->m_capacity = sso_size;
4✔
257
        that->m_size = 0;
4✔
258
    }
4✔
259
};
260

261

262
//-----------------------------------------------------------------------------
263
//-----------------------------------------------------------------------------
264
//-----------------------------------------------------------------------------
265

266
/** a string collection used by the event handler. using this instead of
267
 * std::vector spares the dependency on the standard library. */
268
struct string_vector
269
{
270
    enum : id_type { sso_size = RYML_STRING_LIST_SSO_SIZE };
271
    union {
272
        alignas(string) string m_buf[sso_size];
273
        alignas(string) char   m_buf_bytes[sso_size * sizeof(string)];
274
    };
275
    string *C4_RESTRICT m_arr;
276
    id_type m_size;
277
    id_type m_capacity;
278

279
public:
280

281
    string_vector()
209,216✔
282
        : m_arr(m_buf)
209,216✔
283
        , m_size(0)
209,216✔
284
        , m_capacity(sso_size)
209,216✔
285
    {}
209,216✔
286
    ~string_vector() noexcept
209,065✔
287
    {
288
        _free();
209,065✔
289
    }
209,065✔
290

291
    string_vector(string_vector const& that) RYML_NOEXCEPT : string_vector()
292
    {
293
        reserve(that.m_size);
294
        m_size = that.m_size;
295
        for(id_type i = 0; i < that.m_size; ++i)
296
            new ((void*)(m_arr+i)) string(that.m_arr[i]);
297
    }
298

299
    string_vector(string_vector &&that) noexcept : string_vector()
300
    {
301
        reserve(that.m_size);
302
        m_size = that.m_size;
303
        for(id_type i = 0; i < that.m_size; ++i)
304
            new ((void*)(m_arr+i)) string(std::move(that.m_arr[i]));
305
        that.~string_vector();
306
    }
307

308
    string_vector& operator= (string_vector const& that) RYML_NOEXCEPT
309
    {
310
        _free();
311
        reserve(that.m_size);
312
        for(id_type i = 0; i < that.m_size; ++i)
313
            m_arr[i].operator=(that.m_arr[i]);
314
        m_size = that.m_size;
315
        return *this;
316
    }
317

318
    string_vector& operator= (string_vector &&that) noexcept
319
    {
320
        _free();
321
        reserve(that.m_size);
322
        for(id_type i = 0; i < that.m_size; ++i)
323
            m_arr[i].operator=(std::move(that.m_arr[i]));
324
        m_size = that.m_size;
325
        that.~string_vector();
326
        return *this;
327
    }
328

329
    void _free()
209,065✔
330
    {
331
        _RYML_ASSERT_BASIC(m_arr != nullptr); // this structure cannot be memset() to zero
209,065✔
332
        for(id_type i = 0; i < m_size; ++i)
506,506✔
333
            m_arr[i].~string();
297,441✔
334
        if(m_arr != m_buf)
209,065✔
335
        {
336
            _RYML_CB_FREE(get_callbacks(), m_arr, string, (size_t)m_capacity);
×
337
            m_arr = m_buf;
×
338
            m_capacity = sso_size;
×
339
        }
340
        _RYML_ASSERT_BASIC(m_capacity == sso_size);
209,065✔
341
        m_size = 0;
209,065✔
342
    }
209,065✔
343

344
public:
345

346
    id_type size() const noexcept { return m_size; }
1,864,140✔
347
    id_type capacity() const noexcept { return m_capacity; }
348

349
    void clear()
252,916✔
350
    {
351
        resize(0);
252,916✔
352
    }
252,916✔
353

354
    void resize(id_type sz)
559,104✔
355
    {
356
        reserve(sz);
559,104✔
357
        if(sz >= m_size)
559,104✔
358
        {
359
            for(id_type i = m_size; i < sz; ++i)
856,980✔
360
                new ((void*)(m_arr + i)) string();
341,576✔
361
        }
362
        else
363
        {
364
            for(id_type i = sz; i < m_size; ++i)
87,400✔
365
                m_arr[i].~string();
43,700✔
366
        }
367
        m_size = sz;
559,104✔
368
    }
559,104✔
369

370
    void reserve(id_type sz)
559,104✔
371
    {
372
        if(sz <= m_capacity)
559,104✔
373
            return;
559,104✔
374
        id_type cap = m_capacity < string::sso_size ? string::sso_size : 2 * m_capacity;
×
375
        cap = cap > sz ? cap : sz;
×
376
        if(cap <= sso_size)
×
377
            return;
×
378
        Callbacks cb = get_callbacks();
×
379
        string *buf = (string*) _RYML_CB_ALLOC(cb, string, cap);
×
380
        for(id_type i = 0; i < m_size; ++i)
×
381
            new ((void*)(buf + i)) string(std::move(m_arr[i]));
×
382
        if(m_arr != m_buf)
×
383
        {
384
            _RYML_CB_FREE(cb, m_arr, string, m_size);
×
385
        }
386
        m_arr = buf;
×
387
        m_capacity = cap;
×
388
    }
389

390
public:
391

392
    string& emplace_back()
393
    {
394
        _RYML_ASSERT_BASIC(m_size < m_capacity);
395
        if(m_size == m_capacity)
396
            reserve(m_size + 1);
397
        string& ret = m_arr[m_size++];
398
        new ((void*)&ret) string();
399
        return ret;
400
    }
401
    string& operator[] (id_type i)
1,788,988✔
402
    {
403
        _RYML_ASSERT_BASIC(m_size <= m_capacity);
1,788,988✔
404
        _RYML_ASSERT_BASIC(i < m_size);
1,788,988✔
405
        return m_arr[i];
1,788,988✔
406
    }
407
    string const& operator[] (id_type i) const
408
    {
409
        _RYML_ASSERT_BASIC(m_size <= m_capacity);
410
        _RYML_ASSERT_BASIC(i < m_size);
411
        return m_arr[i];
412
    }
413
};
414

415
} // namespace extra
416
} // namespace yml
417
} // namespace c4
418

419
C4_SUPPRESS_WARNING_GCC_POP
420

421
#endif /* _C4_YML_EXTRA_STRING_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

© 2026 Coveralls, Inc