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 2183159 : is_small() const noexcept
43 : {
44 2183159 : return data_ == buffer_.data();
45 : }
46 :
47 : void
48 9271 : dispose()
49 : {
50 9271 : if( is_small() )
51 4771 : return;
52 :
53 4500 : delete[] data_;
54 : #if defined(__GNUC__)
55 : # pragma GCC diagnostic push
56 : # pragma GCC diagnostic ignored "-Wmissing-field-initializers"
57 : #endif
58 4500 : buffer_ = {};
59 : #if defined(__GNUC__)
60 : # pragma GCC diagnostic pop
61 : #endif
62 9000 : data_ = buffer_.data();
63 : }
64 :
65 : static constexpr
66 : std::size_t
67 18543 : max_size() noexcept
68 : {
69 18543 : return BOOST_JSON_MAX_STRING_SIZE;
70 : }
71 :
72 : public:
73 2164617 : sbo_buffer()
74 2164617 : : buffer_()
75 2164617 : {}
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 2164617 : ~sbo_buffer()
117 : {
118 2164617 : if( !is_small() )
119 4771 : delete[] data_;
120 2164617 : }
121 :
122 : std::size_t
123 9271 : capacity() const noexcept
124 : {
125 14042 : return is_small() ? buffer_.size() : capacity_;
126 : }
127 :
128 : void
129 : reset() noexcept
130 : {
131 : dispose();
132 : clear();
133 : }
134 :
135 : void
136 6242889 : clear()
137 : {
138 6242889 : size_ = 0;
139 6242889 : }
140 :
141 : void
142 11794 : grow( std::size_t size )
143 : {
144 11794 : if( !size )
145 2522 : return;
146 :
147 9272 : 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 9271 : std::size_t const old_capacity = this->capacity();
154 9271 : std::size_t new_capacity = size_ + size;
155 :
156 : // growth factor 2
157 9271 : if( old_capacity <= max_size() - old_capacity ) // check for overflow
158 9271 : new_capacity = (std::max)(old_capacity * 2, new_capacity);
159 :
160 9271 : char* new_data = new char[new_capacity];
161 9271 : std::memcpy(new_data, data_, size_);
162 :
163 9271 : dispose();
164 9271 : data_ = new_data;
165 9271 : capacity_ = new_capacity;
166 : }
167 :
168 : char*
169 11794 : append( char const* ptr, std::size_t size )
170 : {
171 11794 : grow(size);
172 :
173 11793 : if(BOOST_JSON_LIKELY( size ))
174 9271 : std::memcpy( data_ + size_, ptr, size );
175 11793 : size_ += size;
176 11793 : return data_;
177 : }
178 :
179 : std::size_t
180 3066342 : size() noexcept
181 : {
182 3066342 : return size_;
183 : }
184 : };
185 :
186 : } // namespace detail
187 : } // namespace json
188 : } // namespace boost
189 :
190 : #endif // BOOST_JSON_DETAIL_SBO_BUFFER_HPP
|