Coverage Report

Created: 2025-06-24 06:38

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