Coverage Report

Created: 2025-06-13 06:26

/src/boost/boost/json/detail/sbo_buffer.hpp
Line
Count
Source (jump to first uncovered line)
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/json/detail/config.hpp>
15
#include <boost/json/detail/except.hpp>
16
#include <string>
17
#include <array>
18
19
namespace boost {
20
namespace json {
21
namespace detail {
22
23
template< std::size_t N >
24
class sbo_buffer
25
{
26
    struct size_ptr_pair
27
    {
28
        std::size_t size;
29
        char* ptr;
30
    };
31
    BOOST_STATIC_ASSERT( N >= sizeof(size_ptr_pair) );
32
33
    union {
34
        std::array<char, N> buffer_;
35
        std::size_t capacity_;
36
    };
37
    char* data_ = buffer_.data();
38
    std::size_t size_ = 0;
39
40
    bool
41
    is_small() const noexcept
42
46.1k
    {
43
46.1k
        return data_ == buffer_.data();
44
46.1k
    }
45
46
    void
47
    dispose()
48
4.35k
    {
49
4.35k
        if( is_small() )
50
4.35k
            return;
51
52
0
        delete[] data_;
53
0
#if defined(__GNUC__)
54
0
# pragma GCC diagnostic push
55
0
# pragma GCC diagnostic ignored "-Wmissing-field-initializers"
56
0
#endif
57
0
        buffer_ = {};
58
0
#if defined(__GNUC__)
59
0
# pragma GCC diagnostic pop
60
0
#endif
61
0
        data_ = buffer_.data();
62
0
    }
63
64
    static constexpr
65
    std::size_t
66
    max_size() noexcept
67
8.70k
    {
68
8.70k
        return BOOST_JSON_MAX_STRING_SIZE;
69
8.70k
    }
70
71
public:
72
    sbo_buffer()
73
37.4k
        : buffer_()
74
37.4k
    {}
75
76
    sbo_buffer( sbo_buffer&& other ) noexcept
77
        : size_(other.size_)
78
    {
79
        if( other.is_small() )
80
        {
81
            buffer_ = other.buffer_;
82
            data_ = buffer_.data();
83
        }
84
        else
85
        {
86
            data_ = other.data_;
87
            other.data_ = other.buffer_.data();
88
        }
89
        BOOST_ASSERT( other.is_small() );
90
    }
91
92
    sbo_buffer&
93
    operator=( sbo_buffer&& other ) noexcept
94
    {
95
        if( &other == this )
96
            return this;
97
98
        if( other.is_small() )
99
        {
100
            buffer_ = other.buffer_;
101
            data_ = buffer_.data();
102
        }
103
        else
104
        {
105
            data_ = other.data_;
106
            other.data_ = other.buffer_.data();
107
        }
108
109
        size_ = other.size_;
110
        other.size_ = 0;
111
112
        return *this;
113
    }
114
115
    ~sbo_buffer()
116
37.4k
    {
117
37.4k
        if( !is_small() )
118
4.35k
            delete[] data_;
119
37.4k
    }
120
121
    std::size_t
122
    capacity() const noexcept
123
4.35k
    {
124
4.35k
        return is_small() ? buffer_.size() : capacity_;
125
4.35k
    }
126
127
    void
128
    reset() noexcept
129
    {
130
        dispose();
131
        clear();
132
    }
133
134
    void
135
    clear()
136
13.5M
    {
137
13.5M
        size_ = 0;
138
13.5M
    }
139
140
    void
141
    grow( std::size_t size )
142
8.09k
    {
143
8.09k
        if( !size )
144
3.73k
            return;
145
146
4.35k
        if( max_size() - size_ < size )
147
0
        {
148
0
            BOOST_STATIC_CONSTEXPR source_location loc = BOOST_CURRENT_LOCATION;
149
0
            detail::throw_system_error( error::number_too_large, &loc );
150
0
        }
151
152
4.35k
        std::size_t const old_capacity = this->capacity();
153
4.35k
        std::size_t new_capacity = size_ + size;
154
155
        // growth factor 2
156
4.35k
        if( old_capacity <= max_size() - old_capacity ) // check for overflow
157
4.35k
            new_capacity = (std::max)(old_capacity * 2, new_capacity);
158
159
4.35k
        char* new_data = new char[new_capacity];
160
4.35k
        std::memcpy(new_data, data_, size_);
161
162
4.35k
        dispose();
163
4.35k
        data_ = new_data;
164
4.35k
        capacity_ = new_capacity;
165
4.35k
    }
166
167
    char*
168
    append( char const* ptr, std::size_t size )
169
8.09k
    {
170
8.09k
        grow(size);
171
172
8.09k
        if(BOOST_JSON_LIKELY( size ))
173
4.35k
            std::memcpy( data_ + size_, ptr, size );
174
8.09k
        size_ += size;
175
8.09k
        return data_;
176
8.09k
    }
177
178
    std::size_t
179
    size() noexcept
180
267k
    {
181
267k
        return size_;
182
267k
    }
183
};
184
185
} // namespace detail
186
} // namespace json
187
} // namespace boost
188
189
#endif // BOOST_JSON_DETAIL_SBO_BUFFER_HPP