Coverage Report

Created: 2026-06-21 06:59

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/boost/boost/json/detail/string_impl.hpp
Line
Count
Source
1
//
2
// Copyright (c) 2019 Vinnie Falco (vinnie.falco@gmail.com)
3
// Copyright (c) 2020 Krystian Stasiowski (sdkrystian@gmail.com)
4
//
5
// Distributed under the Boost Software License, Version 1.0. (See accompanying
6
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
7
//
8
// Official repository: https://github.com/boostorg/json
9
//
10
11
#ifndef BOOST_JSON_DETAIL_STRING_IMPL_HPP
12
#define BOOST_JSON_DETAIL_STRING_IMPL_HPP
13
14
#include <boost/core/detail/static_assert.hpp>
15
#include <boost/json/detail/config.hpp>
16
#include <boost/json/kind.hpp>
17
#include <boost/json/storage_ptr.hpp>
18
#include <boost/json/detail/value.hpp>
19
#include <algorithm>
20
#include <iterator>
21
22
namespace boost {
23
namespace json {
24
25
class value;
26
class string;
27
28
namespace detail {
29
30
class string_impl
31
{
32
    struct table
33
    {
34
        std::uint32_t size;
35
        std::uint32_t capacity;
36
    };
37
38
#if BOOST_JSON_ARCH == 64
39
    static constexpr std::size_t sbo_chars_ = 14;
40
#elif BOOST_JSON_ARCH == 32
41
    static constexpr std::size_t sbo_chars_ = 10;
42
#else
43
# error Unknown architecture
44
#endif
45
46
    static
47
    constexpr
48
    kind
49
    short_string_ =
50
        static_cast<kind>(
51
            ((unsigned char)
52
            kind::string) | 0x80);
53
54
    static
55
    constexpr
56
    kind
57
    key_string_ =
58
        static_cast<kind>(
59
            ((unsigned char)
60
            kind::string) | 0x40);
61
62
    struct sbo
63
    {
64
        kind k; // must come first
65
        char buf[sbo_chars_ + 1];
66
    };
67
68
    struct pointer
69
    {
70
        kind k; // must come first
71
        table* t;
72
    };
73
74
    struct key
75
    {
76
        kind k; // must come first
77
        std::uint32_t n;
78
        char* s;
79
    };
80
81
    union
82
    {
83
        sbo s_;
84
        pointer p_;
85
        key k_;
86
    };
87
88
#if BOOST_JSON_ARCH == 64
89
    BOOST_CORE_STATIC_ASSERT( sizeof(sbo) <= 16 );
90
    BOOST_CORE_STATIC_ASSERT( sizeof(pointer) <= 16 );
91
    BOOST_CORE_STATIC_ASSERT( sizeof(key) <= 16 );
92
#elif BOOST_JSON_ARCH == 32
93
    BOOST_CORE_STATIC_ASSERT( sizeof(sbo) <= 24 );
94
    BOOST_CORE_STATIC_ASSERT( sizeof(pointer) <= 24 );
95
    BOOST_CORE_STATIC_ASSERT( sizeof(key) <= 24 );
96
#endif
97
98
public:
99
    static
100
    constexpr
101
    std::size_t
102
    max_size() noexcept
103
45.9k
    {
104
        // max_size depends on the address model
105
45.9k
        using min = std::integral_constant<std::size_t,
106
45.9k
            std::size_t(-1) - sizeof(table)>;
107
45.9k
        return min::value < BOOST_JSON_MAX_STRING_SIZE ?
108
45.9k
            min::value : BOOST_JSON_MAX_STRING_SIZE;
109
45.9k
    }
110
111
    BOOST_JSON_DECL
112
    string_impl() noexcept;
113
114
    BOOST_JSON_DECL
115
    string_impl(
116
        std::size_t new_size,
117
        storage_ptr const& sp);
118
119
    BOOST_JSON_DECL
120
    string_impl(
121
        key_t,
122
        string_view s,
123
        storage_ptr const& sp);
124
125
    BOOST_JSON_DECL
126
    string_impl(
127
        key_t,
128
        string_view s1,
129
        string_view s2,
130
        storage_ptr const& sp);
131
132
    BOOST_JSON_DECL
133
    string_impl(
134
        char** dest,
135
        std::size_t len,
136
        storage_ptr const& sp);
137
138
    template<class InputIt>
139
    string_impl(
140
        InputIt first,
141
        InputIt last,
142
        storage_ptr const& sp,
143
        std::random_access_iterator_tag)
144
        : string_impl(last - first, sp)
145
    {
146
        char* out = data();
147
#if defined(_MSC_VER) && _MSC_VER <= 1900
148
        while( first != last )
149
            *out++ = *first++;
150
#else
151
        std::copy(first, last, out);
152
#endif
153
    }
154
155
    template<class InputIt>
156
    string_impl(
157
        InputIt first,
158
        InputIt last,
159
        storage_ptr const& sp,
160
        std::input_iterator_tag)
161
0
        : string_impl(0, sp)
162
0
    {
163
0
        struct undo
164
0
        {
165
0
            string_impl* s;
166
0
            storage_ptr const& sp;
167
168
0
            ~undo()
169
0
            {
170
0
                if(s)
171
0
                    s->destroy(sp);
172
0
            }
173
0
        };
174
175
0
        undo u{this, sp};
176
0
        auto dest = data();
177
0
        while(first != last)
178
0
        {
179
0
            if(size() < capacity())
180
0
                size(size() + 1);
181
0
            else
182
0
                dest = append(1, sp);
183
0
            *dest++ = *first++;
184
0
        }
185
0
        term(size());
186
0
        u.s = nullptr;
187
0
    }
188
189
    std::size_t
190
    size() const noexcept
191
32.5k
    {
192
32.5k
        return s_.k == kind::string ?
193
12.6k
            p_.t->size :
194
32.5k
            sbo_chars_ -
195
19.9k
                s_.buf[sbo_chars_];
196
32.5k
    }
197
198
    std::size_t
199
    capacity() const noexcept
200
66.6k
    {
201
66.6k
        return s_.k == kind::string ?
202
0
            p_.t->capacity :
203
66.6k
            sbo_chars_;
204
66.6k
    }
205
206
    void
207
    size(std::size_t n)
208
4.55k
    {
209
4.55k
        if(s_.k == kind::string)
210
4.55k
            p_.t->size = static_cast<
211
4.55k
                std::uint32_t>(n);
212
0
        else
213
0
            s_.buf[sbo_chars_] =
214
0
                static_cast<char>(
215
0
                    sbo_chars_ - n);
216
4.55k
    }
217
218
    BOOST_JSON_DECL
219
    static
220
    std::uint32_t
221
    growth(
222
        std::size_t new_size,
223
        std::size_t capacity);
224
225
    char const*
226
    release_key(
227
        std::size_t& n) noexcept
228
1.50M
    {
229
1.50M
        BOOST_ASSERT(
230
1.50M
            k_.k == key_string_);
231
1.50M
        n = k_.n;
232
1.50M
        auto const s = k_.s;
233
        // prevent deallocate
234
1.50M
        k_.k = short_string_;
235
1.50M
        return s;
236
1.50M
    }
237
238
    void
239
    destroy(
240
        storage_ptr const& sp) noexcept
241
421k
    {
242
421k
        if(s_.k == kind::string)
243
8.45k
        {
244
8.45k
            sp->deallocate(p_.t,
245
8.45k
                sizeof(table) +
246
8.45k
                    p_.t->capacity + 1,
247
8.45k
                alignof(table));
248
8.45k
        }
249
413k
        else if(s_.k != key_string_)
250
45.1k
        {
251
            // do nothing
252
45.1k
        }
253
368k
        else
254
368k
        {
255
368k
            BOOST_ASSERT(
256
368k
                s_.k == key_string_);
257
            // VFALCO unfortunately the key string
258
            // kind increases the cost of the destructor.
259
            // This function should be skipped when using
260
            // monotonic_resource.
261
368k
            sp->deallocate(k_.s, k_.n + 1);
262
368k
        }
263
421k
    }
264
265
    BOOST_JSON_DECL
266
    char*
267
    assign(
268
        std::size_t new_size,
269
        storage_ptr const& sp);
270
271
    BOOST_JSON_DECL
272
    char*
273
    append(
274
        std::size_t n,
275
        storage_ptr const& sp);
276
277
    BOOST_JSON_DECL
278
    void
279
    insert(
280
        std::size_t pos,
281
        const char* s,
282
        std::size_t n,
283
        storage_ptr const& sp);
284
285
    BOOST_JSON_DECL
286
    char*
287
    insert_unchecked(
288
        std::size_t pos,
289
        std::size_t n,
290
        storage_ptr const& sp);
291
292
    BOOST_JSON_DECL
293
    void
294
    replace(
295
        std::size_t pos,
296
        std::size_t n1,
297
        const char* s,
298
        std::size_t n2,
299
        storage_ptr const& sp);
300
301
    BOOST_JSON_DECL
302
    char*
303
    replace_unchecked(
304
        std::size_t pos,
305
        std::size_t n1,
306
        std::size_t n2,
307
        storage_ptr const& sp);
308
309
    BOOST_JSON_DECL
310
    void
311
    shrink_to_fit(
312
        storage_ptr const& sp) noexcept;
313
314
    void
315
    term(std::size_t n) noexcept
316
50.5k
    {
317
50.5k
        if(s_.k == short_string_)
318
39.1k
        {
319
39.1k
            s_.buf[sbo_chars_] =
320
39.1k
                static_cast<char>(
321
39.1k
                    sbo_chars_ - n);
322
39.1k
            s_.buf[n] = 0;
323
39.1k
        }
324
11.4k
        else
325
11.4k
        {
326
11.4k
            p_.t->size = static_cast<
327
11.4k
                std::uint32_t>(n);
328
11.4k
            data()[n] = 0;
329
11.4k
        }
330
50.5k
    }
331
332
    char*
333
    data() noexcept
334
92.1k
    {
335
92.1k
        if(s_.k == short_string_)
336
48.6k
            return s_.buf;
337
43.5k
        return reinterpret_cast<
338
43.5k
            char*>(p_.t + 1);
339
92.1k
    }
340
341
    char const*
342
    data() const noexcept
343
13.9k
    {
344
13.9k
        if(s_.k == short_string_)
345
5.86k
            return s_.buf;
346
8.09k
        return reinterpret_cast<
347
8.09k
            char const*>(p_.t + 1);
348
13.9k
    }
349
350
    char*
351
    end() noexcept
352
0
    {
353
0
        return data() + size();
354
0
    }
355
356
    char const*
357
    end() const noexcept
358
0
    {
359
0
        return data() + size();
360
0
    }
361
};
362
363
template<class T>
364
string_view
365
to_string_view(T const& t) noexcept
366
{
367
    return string_view(t);
368
}
369
370
template<class T, class U>
371
using string_and_stringlike = std::integral_constant<bool,
372
    std::is_same<T, string>::value &&
373
    std::is_convertible<U const&, string_view>::value>;
374
375
template<class T, class U>
376
using string_comp_op_requirement
377
    = typename std::enable_if<
378
        string_and_stringlike<T, U>::value ||
379
        string_and_stringlike<U, T>::value,
380
        bool>::type;
381
382
} // detail
383
} // namespace json
384
} // namespace boost
385
386
#endif