Coverage Report

Created: 2026-09-13 07:10

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/boost/boost/json/detail/sbo_buffer.hpp
Line
Count
Source
1
//
2
// Copyright (c) 2023 Dmitry Arkhipov (grisumbras@yandex.ru)
3
//
4
// Distributed under the Boost Software License, Version 1.0. (See accompanying
5
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
6
//
7
// Official repository: https://github.com/boostorg/json
8
//
9
10
11
#ifndef BOOST_JSON_DETAIL_SBO_BUFFER_HPP
12
#define BOOST_JSON_DETAIL_SBO_BUFFER_HPP
13
14
#include <boost/core/detail/static_assert.hpp>
15
#include <boost/json/detail/config.hpp>
16
#include <boost/json/detail/except.hpp>
17
#include <string>
18
#include <array>
19
20
namespace boost {
21
namespace json {
22
namespace detail {
23
24
template< std::size_t N >
25
class sbo_buffer
26
{
27
    struct size_ptr_pair
28
    {
29
        std::size_t size;
30
        char* ptr;
31
    };
32
    BOOST_CORE_STATIC_ASSERT( N >= sizeof(size_ptr_pair) );
33
34
    union {
35
        std::array<char, N> buffer_;
36
        std::size_t capacity_;
37
    };
38
    char* data_ = buffer_.data();
39
    std::size_t size_ = 0;
40
41
    bool
42
    is_small() const noexcept
43
47.3k
    {
44
47.3k
        return data_ == buffer_.data();
45
47.3k
    }
46
47
    void
48
    dispose()
49
652
    {
50
652
        if( is_small() )
51
652
            return;
52
53
0
        delete[] data_;
54
0
#if defined(__GNUC__)
55
0
# pragma GCC diagnostic push
56
0
# pragma GCC diagnostic ignored "-Wmissing-field-initializers"
57
0
#endif
58
0
        buffer_ = {};
59
0
#if defined(__GNUC__)
60
0
# pragma GCC diagnostic pop
61
0
#endif
62
0
        data_ = buffer_.data();
63
0
    }
64
65
    static constexpr
66
    std::size_t
67
    max_size() noexcept
68
8.54k
    {
69
8.54k
        return BOOST_JSON_MAX_STRING_SIZE;
70
8.54k
    }
71
72
public:
73
    sbo_buffer()
74
38.7k
        : buffer_()
75
38.7k
    {}
76
77
    sbo_buffer( sbo_buffer&& other ) noexcept
78
        : size_(other.size_)
79
    {
80
        if( other.is_small() )
81
        {
82
            buffer_ = other.buffer_;
83
            data_ = buffer_.data();
84
        }
85
        else
86
        {
87
            data_ = other.data_;
88
            other.data_ = other.buffer_.data();
89
        }
90
        BOOST_ASSERT( other.is_small() );
91
    }
92
93
    sbo_buffer&
94
    operator=( sbo_buffer&& other ) noexcept
95
    {
96
        if( &other == this )
97
            return this;
98
99
        if( other.is_small() )
100
        {
101
            buffer_ = other.buffer_;
102
            data_ = buffer_.data();
103
        }
104
        else
105
        {
106
            data_ = other.data_;
107
            other.data_ = other.buffer_.data();
108
        }
109
110
        size_ = other.size_;
111
        other.size_ = 0;
112
113
        return *this;
114
    }
115
116
    ~sbo_buffer()
117
38.7k
    {
118
38.7k
        if( !is_small() )
119
652
            delete[] data_;
120
38.7k
    }
121
122
    std::size_t
123
    capacity() const noexcept
124
7.89k
    {
125
7.89k
        return is_small() ? buffer_.size() : capacity_;
126
7.89k
    }
127
128
    void
129
    reset() noexcept
130
    {
131
        dispose();
132
        clear();
133
    }
134
135
    void
136
    clear()
137
13.6M
    {
138
13.6M
        size_ = 0;
139
13.6M
    }
140
141
    void
142
    grow( std::size_t size )
143
7.89k
    {
144
7.89k
        if( max_size() - size_ < size )
145
0
        {
146
0
            BOOST_STATIC_CONSTEXPR source_location loc = BOOST_CURRENT_LOCATION;
147
0
            detail::throw_system_error( error::number_too_large, &loc );
148
0
        }
149
150
7.89k
        std::size_t const old_capacity = this->capacity();
151
7.89k
        std::size_t new_capacity = size_ + size;
152
7.89k
        if( new_capacity <= old_capacity )
153
7.24k
            return;
154
155
        // growth factor 2
156
652
        if( old_capacity <= max_size() - old_capacity ) // check for overflow
157
652
            new_capacity = (std::max)(old_capacity * 2, new_capacity);
158
159
652
        char* new_data = new char[new_capacity];
160
652
        std::memcpy(new_data, data_, size_);
161
162
652
        dispose();
163
652
        data_ = new_data;
164
652
        capacity_ = new_capacity;
165
652
    }
166
167
    char*
168
    append( char const* ptr, std::size_t size )
169
7.89k
    {
170
7.89k
        grow(size);
171
172
7.89k
        if(BOOST_JSON_LIKELY( size ))
173
4.25k
            std::memcpy( data_ + size_, ptr, size );
174
7.89k
        size_ += size;
175
7.89k
        return data_;
176
7.89k
    }
177
178
    std::size_t
179
    size() noexcept
180
329k
    {
181
329k
        return size_;
182
329k
    }
183
};
184
185
} // namespace detail
186
} // namespace json
187
} // namespace boost
188
189
#endif // BOOST_JSON_DETAIL_SBO_BUFFER_HPP