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