• 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

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,179,464✔
43
        : m_buf()
152,150,856✔
44
        , m_str(m_buf)
1,179,464✔
45
        , m_size(0)
1,179,464✔
46
        , m_capacity(sso_size)
1,179,464✔
47
    {}
1,179,464✔
48
    ~string() noexcept
1,178,422✔
49
    {
50
        _free();
1,178,422✔
51
    }
1,178,422✔
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}; }
580,752✔
80
    C4_ALWAYS_INLINE C4_HOT operator substr() noexcept { return {m_str, m_size}; }
367,864✔
81

82
public:
83

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

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

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

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

119
public:
120

121
    C4_ALWAYS_INLINE C4_HOT void append(char c)
122
    {
123
        if(C4_UNLIKELY(m_size == m_capacity))
637,620✔
124
            reserve(m_size + 1);
744✔
125
        m_str[m_size++] = c;
637,620✔
126
    }
637,620✔
127
    C4_ALWAYS_INLINE C4_HOT void append(csubstr cs)
128
    {
129
        if(cs.len)
757,352✔
130
        {
131
            const id_type ilen = (id_type)cs.len;
752,704✔
132
            if(C4_UNLIKELY(m_size + ilen > m_capacity))
752,704✔
133
                reserve(m_size + ilen);
26,484✔
134
            memcpy(m_str + m_size, cs.str, cs.len);
752,704✔
135
            m_size += ilen;
752,704✔
136
        }
137
    }
757,352✔
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,178,422✔
205
    {
206
        _RYML_ASSERT_BASIC(m_str != nullptr); // this structure cannot be memset() to zero
1,178,422✔
207
        if(m_str != m_buf)
1,178,422✔
208
        {
209
            _RYML_CB_FREE(get_callbacks(), m_str, char, (size_t)m_capacity);
651,278✔
210
            m_str = m_buf;
651,278✔
211
            m_capacity = sso_size;
651,278✔
212
        }
213
        _RYML_ASSERT_BASIC(m_capacity == sso_size);
1,178,422✔
214
        m_size = 0;
1,178,422✔
215
    }
1,178,422✔
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,332✔
282
        : m_arr(m_buf)
209,332✔
283
        , m_size(0)
209,332✔
284
        , m_capacity(sso_size)
209,332✔
285
    {}
209,332✔
286
    ~string_vector() noexcept
209,181✔
287
    {
288
        _free();
209,181✔
289
    }
209,181✔
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,181✔
330
    {
331
        _RYML_ASSERT_BASIC(m_arr != nullptr); // this structure cannot be memset() to zero
209,181✔
332
        for(id_type i = 0; i < m_size; ++i)
507,050✔
333
            m_arr[i].~string();
297,869✔
334
        if(m_arr != m_buf)
209,181✔
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,181✔
341
        m_size = 0;
209,181✔
342
    }
209,181✔
343

344
public:
345

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

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

354
    void resize(id_type sz)
559,764✔
355
    {
356
        reserve(sz);
559,764✔
357
        if(sz >= m_size)
559,764✔
358
        {
359
            for(id_type i = m_size; i < sz; ++i)
858,068✔
360
                new ((void*)(m_arr + i)) string();
342,120✔
361
        }
362
        else
363
        {
364
            for(id_type i = sz; i < m_size; ++i)
87,632✔
365
                m_arr[i].~string();
43,816✔
366
        }
367
        m_size = sz;
559,764✔
368
    }
559,764✔
369

370
    void reserve(id_type sz)
559,764✔
371
    {
372
        if(sz <= m_capacity)
559,764✔
373
            return;
559,764✔
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,791,988✔
402
    {
403
        _RYML_ASSERT_BASIC(m_size <= m_capacity);
1,791,988✔
404
        _RYML_ASSERT_BASIC(i < m_size);
1,791,988✔
405
        return m_arr[i];
1,791,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