123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189 |
- //
- // Copyright (c) 2023 Dmitry Arkhipov ([email protected])
- //
- // Distributed under the Boost Software License, Version 1.0. (See accompanying
- // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
- //
- // Official repository: https://github.com/boostorg/json
- //
- #ifndef BOOST_JSON_DETAIL_SBO_BUFFER_HPP
- #define BOOST_JSON_DETAIL_SBO_BUFFER_HPP
- #include <boost/json/detail/config.hpp>
- #include <boost/json/detail/except.hpp>
- #include <string>
- #include <array>
- namespace boost {
- namespace json {
- namespace detail {
- template< std::size_t N >
- class sbo_buffer
- {
- struct size_ptr_pair
- {
- std::size_t size;
- char* ptr;
- };
- BOOST_STATIC_ASSERT( N >= sizeof(size_ptr_pair) );
- union {
- std::array<char, N> buffer_;
- std::size_t capacity_;
- };
- char* data_ = buffer_.data();
- std::size_t size_ = 0;
- bool
- is_small() const noexcept
- {
- return data_ == buffer_.data();
- }
- void
- dispose()
- {
- if( is_small() )
- return;
- delete[] data_;
- #if defined(__GNUC__)
- # pragma GCC diagnostic push
- # pragma GCC diagnostic ignored "-Wmissing-field-initializers"
- #endif
- buffer_ = {};
- #if defined(__GNUC__)
- # pragma GCC diagnostic pop
- #endif
- data_ = buffer_.data();
- }
- static constexpr
- std::size_t
- max_size() noexcept
- {
- return BOOST_JSON_MAX_STRING_SIZE;
- }
- public:
- sbo_buffer()
- : buffer_()
- {}
- sbo_buffer( sbo_buffer&& other ) noexcept
- : size_(other.size_)
- {
- if( other.is_small() )
- {
- buffer_ = other.buffer_;
- data_ = buffer_.data();
- }
- else
- {
- data_ = other.data_;
- other.data_ = other.buffer_.data();
- }
- BOOST_ASSERT( other.is_small() );
- }
- sbo_buffer&
- operator=( sbo_buffer&& other ) noexcept
- {
- if( &other == this )
- return this;
- if( other.is_small() )
- {
- buffer_ = other.buffer_;
- data_ = buffer_.data();
- }
- else
- {
- data_ = other.data_;
- other.data_ = other.buffer_.data();
- }
- size_ = other.size_;
- other.size_ = 0;
- return *this;
- }
- ~sbo_buffer()
- {
- if( !is_small() )
- delete[] data_;
- }
- std::size_t
- capacity() const noexcept
- {
- return is_small() ? buffer_.size() : capacity_;
- }
- void
- reset() noexcept
- {
- dispose();
- clear();
- }
- void
- clear()
- {
- size_ = 0;
- }
- void
- grow( std::size_t size )
- {
- if( !size )
- return;
- if( max_size() - size_ < size )
- {
- BOOST_STATIC_CONSTEXPR source_location loc = BOOST_CURRENT_LOCATION;
- detail::throw_system_error( error::number_too_large, &loc );
- }
- std::size_t const old_capacity = this->capacity();
- std::size_t new_capacity = size_ + size;
- // growth factor 2
- if( old_capacity <= max_size() - old_capacity ) // check for overflow
- new_capacity = (std::max)(old_capacity * 2, new_capacity);
- char* new_data = new char[new_capacity];
- std::memcpy(new_data, data_, size_);
- dispose();
- data_ = new_data;
- capacity_ = new_capacity;
- }
- char*
- append( char const* ptr, std::size_t size )
- {
- grow(size);
- if(BOOST_JSON_LIKELY( size ))
- std::memcpy( data_ + size_, ptr, size );
- size_ += size;
- return data_;
- }
- std::size_t
- size() noexcept
- {
- return size_;
- }
- };
- } // namespace detail
- } // namespace json
- } // namespace boost
- #endif // BOOST_JSON_DETAIL_SBO_BUFFER_HPP
|