TLA Line data Source code
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 HIT 2180028 : is_small() const noexcept
43 : {
44 2180028 : return data_ == buffer_.data();
45 : }
46 :
47 : void
48 6097 : dispose()
49 : {
50 6097 : if( is_small() )
51 3272 : return;
52 :
53 2825 : delete[] data_;
54 : #if defined(__GNUC__)
55 : # pragma GCC diagnostic push
56 : # pragma GCC diagnostic ignored "-Wmissing-field-initializers"
57 : #endif
58 2825 : buffer_ = {};
59 : #if defined(__GNUC__)
60 : # pragma GCC diagnostic pop
61 : #endif
62 5650 : data_ = buffer_.data();
63 : }
64 :
65 : static constexpr
66 : std::size_t
67 15412 : max_size() noexcept
68 : {
69 15412 : return BOOST_JSON_MAX_STRING_SIZE;
70 : }
71 :
72 : public:
73 2164607 : sbo_buffer()
74 2164607 : : buffer_()
75 2164607 : {}
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 2164607 : ~sbo_buffer()
117 : {
118 2164607 : if( !is_small() )
119 3271 : delete[] data_;
120 2164607 : }
121 :
122 : std::size_t
123 9324 : capacity() const noexcept
124 : {
125 15734 : return is_small() ? buffer_.size() : capacity_;
126 : }
127 :
128 : void
129 1 : reset() noexcept
130 : {
131 1 : dispose();
132 1 : clear();
133 1 : }
134 :
135 : void
136 6242866 : clear()
137 : {
138 6242866 : size_ = 0;
139 6242866 : }
140 :
141 : void
142 11838 : grow( std::size_t size )
143 : {
144 11838 : if( !size )
145 5741 : return;
146 :
147 9316 : if( max_size() - size_ < size )
148 : {
149 : BOOST_STATIC_CONSTEXPR source_location loc = BOOST_CURRENT_LOCATION;
150 1 : detail::throw_system_error( error::number_too_large, &loc );
151 : }
152 :
153 9315 : std::size_t const old_capacity = this->capacity();
154 9315 : if( size <= old_capacity - size_ )
155 3219 : return;
156 :
157 6096 : std::size_t new_capacity = size_ + size;
158 :
159 : // growth factor 2
160 6096 : if( old_capacity <= max_size() - old_capacity ) // check for overflow
161 6096 : new_capacity = (std::max)(old_capacity * 2, new_capacity);
162 :
163 6096 : char* new_data = new char[new_capacity];
164 6096 : std::memcpy(new_data, data_, size_);
165 :
166 6096 : dispose();
167 6096 : data_ = new_data;
168 6096 : capacity_ = new_capacity;
169 : }
170 :
171 : char*
172 11838 : append( char const* ptr, std::size_t size )
173 : {
174 11838 : grow(size);
175 :
176 11837 : if(BOOST_JSON_LIKELY( size ))
177 9315 : std::memcpy( data_ + size_, ptr, size );
178 11837 : size_ += size;
179 11837 : return data_;
180 : }
181 :
182 : std::size_t
183 3066431 : size() noexcept
184 : {
185 3066431 : return size_;
186 : }
187 : };
188 :
189 : } // namespace detail
190 : } // namespace json
191 : } // namespace boost
192 :
193 : #endif // BOOST_JSON_DETAIL_SBO_BUFFER_HPP
|