100.00% Lines (44/44)
100.00% Functions (10/10)
| TLA | Baseline | Branch | ||||||
|---|---|---|---|---|---|---|---|---|
| Line | Hits | Code | Line | Hits | Code | |||
| 1 | // | 1 | // | |||||
| 2 | // Copyright (c) 2023 Dmitry Arkhipov (grisumbras@yandex.ru) | 2 | // Copyright (c) 2023 Dmitry Arkhipov (grisumbras@yandex.ru) | |||||
| 3 | // | 3 | // | |||||
| 4 | // Distributed under the Boost Software License, Version 1.0. (See accompanying | 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) | 5 | // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) | |||||
| 6 | // | 6 | // | |||||
| 7 | // Official repository: https://github.com/boostorg/json | 7 | // Official repository: https://github.com/boostorg/json | |||||
| 8 | // | 8 | // | |||||
| 9 | 9 | |||||||
| 10 | 10 | |||||||
| 11 | #ifndef BOOST_JSON_DETAIL_SBO_BUFFER_HPP | 11 | #ifndef BOOST_JSON_DETAIL_SBO_BUFFER_HPP | |||||
| 12 | #define BOOST_JSON_DETAIL_SBO_BUFFER_HPP | 12 | #define BOOST_JSON_DETAIL_SBO_BUFFER_HPP | |||||
| 13 | 13 | |||||||
| 14 | #include <boost/core/detail/static_assert.hpp> | 14 | #include <boost/core/detail/static_assert.hpp> | |||||
| 15 | #include <boost/json/detail/config.hpp> | 15 | #include <boost/json/detail/config.hpp> | |||||
| 16 | #include <boost/json/detail/except.hpp> | 16 | #include <boost/json/detail/except.hpp> | |||||
| 17 | #include <string> | 17 | #include <string> | |||||
| 18 | #include <array> | 18 | #include <array> | |||||
| 19 | 19 | |||||||
| 20 | namespace boost { | 20 | namespace boost { | |||||
| 21 | namespace json { | 21 | namespace json { | |||||
| 22 | namespace detail { | 22 | namespace detail { | |||||
| 23 | 23 | |||||||
| 24 | template< std::size_t N > | 24 | template< std::size_t N > | |||||
| 25 | class sbo_buffer | 25 | class sbo_buffer | |||||
| 26 | { | 26 | { | |||||
| 27 | struct size_ptr_pair | 27 | struct size_ptr_pair | |||||
| 28 | { | 28 | { | |||||
| 29 | std::size_t size; | 29 | std::size_t size; | |||||
| 30 | char* ptr; | 30 | char* ptr; | |||||
| 31 | }; | 31 | }; | |||||
| 32 | BOOST_CORE_STATIC_ASSERT( N >= sizeof(size_ptr_pair) ); | 32 | BOOST_CORE_STATIC_ASSERT( N >= sizeof(size_ptr_pair) ); | |||||
| 33 | 33 | |||||||
| 34 | union { | 34 | union { | |||||
| 35 | std::array<char, N> buffer_; | 35 | std::array<char, N> buffer_; | |||||
| 36 | std::size_t capacity_; | 36 | std::size_t capacity_; | |||||
| 37 | }; | 37 | }; | |||||
| 38 | char* data_ = buffer_.data(); | 38 | char* data_ = buffer_.data(); | |||||
| 39 | std::size_t size_ = 0; | 39 | std::size_t size_ = 0; | |||||
| 40 | 40 | |||||||
| 41 | bool | 41 | bool | |||||
| HITCBC | 42 | 2183146 | is_small() const noexcept | 42 | 2183146 | is_small() const noexcept | ||
| 43 | { | 43 | { | |||||
| HITCBC | 44 | 2183146 | return data_ == buffer_.data(); | 44 | 2183146 | return data_ == buffer_.data(); | ||
| 45 | } | 45 | } | |||||
| 46 | 46 | |||||||
| 47 | void | 47 | void | |||||
| HITCBC | 48 | 9271 | dispose() | 48 | 9271 | dispose() | ||
| 49 | { | 49 | { | |||||
| HITCBC | 50 | 9271 | if( is_small() ) | 50 | 9271 | if( is_small() ) | ||
| HITCBC | 51 | 4771 | return; | 51 | 4771 | return; | ||
| 52 | 52 | |||||||
| HITCBC | 53 | 4500 | delete[] data_; | 53 | 4500 | delete[] data_; | ||
| 54 | #if defined(__GNUC__) | 54 | #if defined(__GNUC__) | |||||
| 55 | # pragma GCC diagnostic push | 55 | # pragma GCC diagnostic push | |||||
| 56 | # pragma GCC diagnostic ignored "-Wmissing-field-initializers" | 56 | # pragma GCC diagnostic ignored "-Wmissing-field-initializers" | |||||
| 57 | #endif | 57 | #endif | |||||
| HITCBC | 58 | 4500 | buffer_ = {}; | 58 | 4500 | buffer_ = {}; | ||
| 59 | #if defined(__GNUC__) | 59 | #if defined(__GNUC__) | |||||
| 60 | # pragma GCC diagnostic pop | 60 | # pragma GCC diagnostic pop | |||||
| 61 | #endif | 61 | #endif | |||||
| HITCBC | 62 | 9000 | data_ = buffer_.data(); | 62 | 9000 | data_ = buffer_.data(); | ||
| 63 | } | 63 | } | |||||
| 64 | 64 | |||||||
| 65 | static constexpr | 65 | static constexpr | |||||
| 66 | std::size_t | 66 | std::size_t | |||||
| HITCBC | 67 | 18543 | max_size() noexcept | 67 | 18543 | max_size() noexcept | ||
| 68 | { | 68 | { | |||||
| HITCBC | 69 | 18543 | return BOOST_JSON_MAX_STRING_SIZE; | 69 | 18543 | return BOOST_JSON_MAX_STRING_SIZE; | ||
| 70 | } | 70 | } | |||||
| 71 | 71 | |||||||
| 72 | public: | 72 | public: | |||||
| HITCBC | 73 | 2164604 | sbo_buffer() | 73 | 2164604 | sbo_buffer() | ||
| HITCBC | 74 | 2164604 | : buffer_() | 74 | 2164604 | : buffer_() | ||
| HITCBC | 75 | 2164604 | {} | 75 | 2164604 | {} | ||
| 76 | 76 | |||||||
| 77 | sbo_buffer( sbo_buffer&& other ) noexcept | 77 | sbo_buffer( sbo_buffer&& other ) noexcept | |||||
| 78 | : size_(other.size_) | 78 | : size_(other.size_) | |||||
| 79 | { | 79 | { | |||||
| 80 | if( other.is_small() ) | 80 | if( other.is_small() ) | |||||
| 81 | { | 81 | { | |||||
| 82 | buffer_ = other.buffer_; | 82 | buffer_ = other.buffer_; | |||||
| 83 | data_ = buffer_.data(); | 83 | data_ = buffer_.data(); | |||||
| 84 | } | 84 | } | |||||
| 85 | else | 85 | else | |||||
| 86 | { | 86 | { | |||||
| 87 | data_ = other.data_; | 87 | data_ = other.data_; | |||||
| 88 | other.data_ = other.buffer_.data(); | 88 | other.data_ = other.buffer_.data(); | |||||
| 89 | } | 89 | } | |||||
| 90 | BOOST_ASSERT( other.is_small() ); | 90 | BOOST_ASSERT( other.is_small() ); | |||||
| 91 | } | 91 | } | |||||
| 92 | 92 | |||||||
| 93 | sbo_buffer& | 93 | sbo_buffer& | |||||
| 94 | operator=( sbo_buffer&& other ) noexcept | 94 | operator=( sbo_buffer&& other ) noexcept | |||||
| 95 | { | 95 | { | |||||
| 96 | if( &other == this ) | 96 | if( &other == this ) | |||||
| 97 | return this; | 97 | return this; | |||||
| 98 | 98 | |||||||
| 99 | if( other.is_small() ) | 99 | if( other.is_small() ) | |||||
| 100 | { | 100 | { | |||||
| 101 | buffer_ = other.buffer_; | 101 | buffer_ = other.buffer_; | |||||
| 102 | data_ = buffer_.data(); | 102 | data_ = buffer_.data(); | |||||
| 103 | } | 103 | } | |||||
| 104 | else | 104 | else | |||||
| 105 | { | 105 | { | |||||
| 106 | data_ = other.data_; | 106 | data_ = other.data_; | |||||
| 107 | other.data_ = other.buffer_.data(); | 107 | other.data_ = other.buffer_.data(); | |||||
| 108 | } | 108 | } | |||||
| 109 | 109 | |||||||
| 110 | size_ = other.size_; | 110 | size_ = other.size_; | |||||
| 111 | other.size_ = 0; | 111 | other.size_ = 0; | |||||
| 112 | 112 | |||||||
| 113 | return *this; | 113 | return *this; | |||||
| 114 | } | 114 | } | |||||
| 115 | 115 | |||||||
| HITCBC | 116 | 2164604 | ~sbo_buffer() | 116 | 2164604 | ~sbo_buffer() | ||
| 117 | { | 117 | { | |||||
| HITCBC | 118 | 2164604 | if( !is_small() ) | 118 | 2164604 | if( !is_small() ) | ||
| HITCBC | 119 | 4771 | delete[] data_; | 119 | 4771 | delete[] data_; | ||
| HITCBC | 120 | 2164604 | } | 120 | 2164604 | } | ||
| 121 | 121 | |||||||
| 122 | std::size_t | 122 | std::size_t | |||||
| HITCBC | 123 | 9271 | capacity() const noexcept | 123 | 9271 | capacity() const noexcept | ||
| 124 | { | 124 | { | |||||
| HITCBC | 125 | 14042 | return is_small() ? buffer_.size() : capacity_; | 125 | 14042 | return is_small() ? buffer_.size() : capacity_; | ||
| 126 | } | 126 | } | |||||
| 127 | 127 | |||||||
| 128 | void | 128 | void | |||||
| 129 | reset() noexcept | 129 | reset() noexcept | |||||
| 130 | { | 130 | { | |||||
| 131 | dispose(); | 131 | dispose(); | |||||
| 132 | clear(); | 132 | clear(); | |||||
| 133 | } | 133 | } | |||||
| 134 | 134 | |||||||
| 135 | void | 135 | void | |||||
| HITCBC | 136 | 6242824 | clear() | 136 | 6242824 | clear() | ||
| 137 | { | 137 | { | |||||
| HITCBC | 138 | 6242824 | size_ = 0; | 138 | 6242824 | size_ = 0; | ||
| HITCBC | 139 | 6242824 | } | 139 | 6242824 | } | ||
| 140 | 140 | |||||||
| 141 | void | 141 | void | |||||
| HITCBC | 142 | 11794 | grow( std::size_t size ) | 142 | 11794 | grow( std::size_t size ) | ||
| 143 | { | 143 | { | |||||
| HITCBC | 144 | 11794 | if( !size ) | 144 | 11794 | if( !size ) | ||
| HITCBC | 145 | 2522 | return; | 145 | 2522 | return; | ||
| 146 | 146 | |||||||
| HITCBC | 147 | 9272 | if( max_size() - size_ < size ) | 147 | 9272 | if( max_size() - size_ < size ) | ||
| 148 | { | 148 | { | |||||
| 149 | BOOST_STATIC_CONSTEXPR source_location loc = BOOST_CURRENT_LOCATION; | 149 | BOOST_STATIC_CONSTEXPR source_location loc = BOOST_CURRENT_LOCATION; | |||||
| HITCBC | 150 | 1 | detail::throw_system_error( error::number_too_large, &loc ); | 150 | 1 | detail::throw_system_error( error::number_too_large, &loc ); | ||
| 151 | } | 151 | } | |||||
| 152 | 152 | |||||||
| HITCBC | 153 | 9271 | std::size_t const old_capacity = this->capacity(); | 153 | 9271 | std::size_t const old_capacity = this->capacity(); | ||
| HITCBC | 154 | 9271 | std::size_t new_capacity = size_ + size; | 154 | 9271 | std::size_t new_capacity = size_ + size; | ||
| 155 | 155 | |||||||
| 156 | // growth factor 2 | 156 | // growth factor 2 | |||||
| HITCBC | 157 | 9271 | if( old_capacity <= max_size() - old_capacity ) // check for overflow | 157 | 9271 | if( old_capacity <= max_size() - old_capacity ) // check for overflow | ||
| HITCBC | 158 | 9271 | new_capacity = (std::max)(old_capacity * 2, new_capacity); | 158 | 9271 | new_capacity = (std::max)(old_capacity * 2, new_capacity); | ||
| 159 | 159 | |||||||
| HITCBC | 160 | 9271 | char* new_data = new char[new_capacity]; | 160 | 9271 | char* new_data = new char[new_capacity]; | ||
| HITCBC | 161 | 9271 | std::memcpy(new_data, data_, size_); | 161 | 9271 | std::memcpy(new_data, data_, size_); | ||
| 162 | 162 | |||||||
| HITCBC | 163 | 9271 | dispose(); | 163 | 9271 | dispose(); | ||
| HITCBC | 164 | 9271 | data_ = new_data; | 164 | 9271 | data_ = new_data; | ||
| HITCBC | 165 | 9271 | capacity_ = new_capacity; | 165 | 9271 | capacity_ = new_capacity; | ||
| 166 | } | 166 | } | |||||
| 167 | 167 | |||||||
| 168 | char* | 168 | char* | |||||
| HITCBC | 169 | 11794 | append( char const* ptr, std::size_t size ) | 169 | 11794 | append( char const* ptr, std::size_t size ) | ||
| 170 | { | 170 | { | |||||
| HITCBC | 171 | 11794 | grow(size); | 171 | 11794 | grow(size); | ||
| 172 | 172 | |||||||
| HITCBC | 173 | 11793 | if(BOOST_JSON_LIKELY( size )) | 173 | 11793 | if(BOOST_JSON_LIKELY( size )) | ||
| HITCBC | 174 | 9271 | std::memcpy( data_ + size_, ptr, size ); | 174 | 9271 | std::memcpy( data_ + size_, ptr, size ); | ||
| HITCBC | 175 | 11793 | size_ += size; | 175 | 11793 | size_ += size; | ||
| HITCBC | 176 | 11793 | return data_; | 176 | 11793 | return data_; | ||
| 177 | } | 177 | } | |||||
| 178 | 178 | |||||||
| 179 | std::size_t | 179 | std::size_t | |||||
| HITCBC | 180 | 3066342 | size() noexcept | 180 | 3066342 | size() noexcept | ||
| 181 | { | 181 | { | |||||
| HITCBC | 182 | 3066342 | return size_; | 182 | 3066342 | return size_; | ||
| 183 | } | 183 | } | |||||
| 184 | }; | 184 | }; | |||||
| 185 | 185 | |||||||
| 186 | } // namespace detail | 186 | } // namespace detail | |||||
| 187 | } // namespace json | 187 | } // namespace json | |||||
| 188 | } // namespace boost | 188 | } // namespace boost | |||||
| 189 | 189 | |||||||
| 190 | #endif // BOOST_JSON_DETAIL_SBO_BUFFER_HPP | 190 | #endif // BOOST_JSON_DETAIL_SBO_BUFFER_HPP | |||||