File indexing completed on 2025-01-18 09:38:59
0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011 #ifndef BOOST_JSON_DETAIL_SBO_BUFFER_HPP
0012 #define BOOST_JSON_DETAIL_SBO_BUFFER_HPP
0013
0014 #include <boost/json/detail/config.hpp>
0015 #include <boost/json/detail/except.hpp>
0016 #include <string>
0017 #include <array>
0018
0019 namespace boost {
0020 namespace json {
0021 namespace detail {
0022
0023 template< std::size_t N >
0024 class sbo_buffer
0025 {
0026 struct size_ptr_pair
0027 {
0028 std::size_t size;
0029 char* ptr;
0030 };
0031 BOOST_STATIC_ASSERT( N >= sizeof(size_ptr_pair) );
0032
0033 union {
0034 std::array<char, N> buffer_;
0035 std::size_t capacity_;
0036 };
0037 char* data_ = buffer_.data();
0038 std::size_t size_ = 0;
0039
0040 bool
0041 is_small() const noexcept
0042 {
0043 return data_ == buffer_.data();
0044 }
0045
0046 void
0047 dispose()
0048 {
0049 if( is_small() )
0050 return;
0051
0052 delete[] data_;
0053 #if defined(__GNUC__)
0054 # pragma GCC diagnostic push
0055 # pragma GCC diagnostic ignored "-Wmissing-field-initializers"
0056 #endif
0057 buffer_ = {};
0058 #if defined(__GNUC__)
0059 # pragma GCC diagnostic pop
0060 #endif
0061 data_ = buffer_.data();
0062 }
0063
0064 static constexpr
0065 std::size_t
0066 max_size() noexcept
0067 {
0068 return BOOST_JSON_MAX_STRING_SIZE;
0069 }
0070
0071 public:
0072 sbo_buffer()
0073 : buffer_()
0074 {}
0075
0076 sbo_buffer( sbo_buffer&& other ) noexcept
0077 : size_(other.size_)
0078 {
0079 if( other.is_small() )
0080 {
0081 buffer_ = other.buffer_;
0082 data_ = buffer_.data();
0083 }
0084 else
0085 {
0086 data_ = other.data_;
0087 other.data_ = other.buffer_.data();
0088 }
0089 BOOST_ASSERT( other.is_small() );
0090 }
0091
0092 sbo_buffer&
0093 operator=( sbo_buffer&& other ) noexcept
0094 {
0095 if( &other == this )
0096 return this;
0097
0098 if( other.is_small() )
0099 {
0100 buffer_ = other.buffer_;
0101 data_ = buffer_.data();
0102 }
0103 else
0104 {
0105 data_ = other.data_;
0106 other.data_ = other.buffer_.data();
0107 }
0108
0109 size_ = other.size_;
0110 other.size_ = 0;
0111
0112 return *this;
0113 }
0114
0115 ~sbo_buffer()
0116 {
0117 if( !is_small() )
0118 delete[] data_;
0119 }
0120
0121 std::size_t
0122 capacity() const noexcept
0123 {
0124 return is_small() ? buffer_.size() : capacity_;
0125 }
0126
0127 void
0128 reset() noexcept
0129 {
0130 dispose();
0131 clear();
0132 }
0133
0134 void
0135 clear()
0136 {
0137 size_ = 0;
0138 }
0139
0140 void
0141 grow( std::size_t size )
0142 {
0143 if( !size )
0144 return;
0145
0146 if( max_size() - size_ < size )
0147 {
0148 BOOST_STATIC_CONSTEXPR source_location loc = BOOST_CURRENT_LOCATION;
0149 detail::throw_system_error( error::number_too_large, &loc );
0150 }
0151
0152 std::size_t const old_capacity = this->capacity();
0153 std::size_t new_capacity = size_ + size;
0154
0155
0156 if( old_capacity <= max_size() - old_capacity )
0157 new_capacity = (std::max)(old_capacity * 2, new_capacity);
0158
0159 char* new_data = new char[new_capacity];
0160 std::memcpy(new_data, data_, size_);
0161
0162 dispose();
0163 data_ = new_data;
0164 capacity_ = new_capacity;
0165 }
0166
0167 char*
0168 append( char const* ptr, std::size_t size )
0169 {
0170 grow(size);
0171
0172 if(BOOST_JSON_LIKELY( size ))
0173 std::memcpy( data_ + size_, ptr, size );
0174 size_ += size;
0175 return data_;
0176 }
0177
0178 std::size_t
0179 size() noexcept
0180 {
0181 return size_;
0182 }
0183 };
0184
0185 }
0186 }
0187 }
0188
0189 #endif