Coverage Report

Created: 2026-03-23 06:12

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
45.7k
    {
44
45.7k
        return data_ == buffer_.data();
45
45.7k
    }
46
47
    void
48
    dispose()
49
4.02k
    {
50
4.02k
        if( is_small() )
51
4.02k
            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.04k
    {
69
8.04k
        return BOOST_JSON_MAX_STRING_SIZE;
70
8.04k
    }
71
72
public:
73
    sbo_buffer()
74
37.7k
        : buffer_()
75
37.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
37.7k
    {
118
37.7k
        if( !is_small() )
119
4.02k
            delete[] data_;
120
37.7k
    }
121
122
    std::size_t
123
    capacity() const noexcept
124
4.02k
    {
125
4.02k
        return is_small() ? buffer_.size() : capacity_;
126
4.02k
    }
127
128
    void
129
    reset() noexcept
130
    {
131
        dispose();
132
        clear();
133
    }
134
135
    void
136
    clear()
137
14.4M
    {
138
14.4M
        size_ = 0;
139
14.4M
    }
140
141
    void
142
    grow( std::size_t size )
143
7.49k
    {
144
7.49k
        if( !size )
145
3.47k
            return;
146
147
4.02k
        if( max_size() - size_ < size )
148
0
        {
149
0
            BOOST_STATIC_CONSTEXPR source_location loc = BOOST_CURRENT_LOCATION;
150
0
            detail::throw_system_error( error::number_too_large, &loc );
151
0
        }
152
153
4.02k
        std::size_t const old_capacity = this->capacity();
154
4.02k
        std::size_t new_capacity = size_ + size;
155
156
        // growth factor 2
157
4.02k
        if( old_capacity <= max_size() - old_capacity ) // check for overflow
158
4.02k
            new_capacity = (std::max)(old_capacity * 2, new_capacity);
159
160
4.02k
        char* new_data = new char[new_capacity];
161
4.02k
        std::memcpy(new_data, data_, size_);
162
163
4.02k
        dispose();
164
4.02k
        data_ = new_data;
165
4.02k
        capacity_ = new_capacity;
166
4.02k
    }
167
168
    char*
169
    append( char const* ptr, std::size_t size )
170
7.49k
    {
171
7.49k
        grow(size);
172
173
7.49k
        if(BOOST_JSON_LIKELY( size ))
174
4.02k
            std::memcpy( data_ + size_, ptr, size );
175
7.49k
        size_ += size;
176
7.49k
        return data_;
177
7.49k
    }
178
179
    std::size_t
180
    size() noexcept
181
170k
    {
182
170k
        return size_;
183
170k
    }
184
};
185
186
} // namespace detail
187
} // namespace json
188
} // namespace boost
189
190
#endif // BOOST_JSON_DETAIL_SBO_BUFFER_HPP