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