sbo_buffer.hpp 3.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189
  1. //
  2. // Copyright (c) 2023 Dmitry Arkhipov ([email protected])
  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. #ifndef BOOST_JSON_DETAIL_SBO_BUFFER_HPP
  10. #define BOOST_JSON_DETAIL_SBO_BUFFER_HPP
  11. #include <boost/json/detail/config.hpp>
  12. #include <boost/json/detail/except.hpp>
  13. #include <string>
  14. #include <array>
  15. namespace boost {
  16. namespace json {
  17. namespace detail {
  18. template< std::size_t N >
  19. class sbo_buffer
  20. {
  21. struct size_ptr_pair
  22. {
  23. std::size_t size;
  24. char* ptr;
  25. };
  26. BOOST_STATIC_ASSERT( N >= sizeof(size_ptr_pair) );
  27. union {
  28. std::array<char, N> buffer_;
  29. std::size_t capacity_;
  30. };
  31. char* data_ = buffer_.data();
  32. std::size_t size_ = 0;
  33. bool
  34. is_small() const noexcept
  35. {
  36. return data_ == buffer_.data();
  37. }
  38. void
  39. dispose()
  40. {
  41. if( is_small() )
  42. return;
  43. delete[] data_;
  44. #if defined(__GNUC__)
  45. # pragma GCC diagnostic push
  46. # pragma GCC diagnostic ignored "-Wmissing-field-initializers"
  47. #endif
  48. buffer_ = {};
  49. #if defined(__GNUC__)
  50. # pragma GCC diagnostic pop
  51. #endif
  52. data_ = buffer_.data();
  53. }
  54. static constexpr
  55. std::size_t
  56. max_size() noexcept
  57. {
  58. return BOOST_JSON_MAX_STRING_SIZE;
  59. }
  60. public:
  61. sbo_buffer()
  62. : buffer_()
  63. {}
  64. sbo_buffer( sbo_buffer&& other ) noexcept
  65. : size_(other.size_)
  66. {
  67. if( other.is_small() )
  68. {
  69. buffer_ = other.buffer_;
  70. data_ = buffer_.data();
  71. }
  72. else
  73. {
  74. data_ = other.data_;
  75. other.data_ = other.buffer_.data();
  76. }
  77. BOOST_ASSERT( other.is_small() );
  78. }
  79. sbo_buffer&
  80. operator=( sbo_buffer&& other ) noexcept
  81. {
  82. if( &other == this )
  83. return this;
  84. if( other.is_small() )
  85. {
  86. buffer_ = other.buffer_;
  87. data_ = buffer_.data();
  88. }
  89. else
  90. {
  91. data_ = other.data_;
  92. other.data_ = other.buffer_.data();
  93. }
  94. size_ = other.size_;
  95. other.size_ = 0;
  96. return *this;
  97. }
  98. ~sbo_buffer()
  99. {
  100. if( !is_small() )
  101. delete[] data_;
  102. }
  103. std::size_t
  104. capacity() const noexcept
  105. {
  106. return is_small() ? buffer_.size() : capacity_;
  107. }
  108. void
  109. reset() noexcept
  110. {
  111. dispose();
  112. clear();
  113. }
  114. void
  115. clear()
  116. {
  117. size_ = 0;
  118. }
  119. void
  120. grow( std::size_t size )
  121. {
  122. if( !size )
  123. return;
  124. if( max_size() - size_ < size )
  125. {
  126. BOOST_STATIC_CONSTEXPR source_location loc = BOOST_CURRENT_LOCATION;
  127. detail::throw_system_error( error::number_too_large, &loc );
  128. }
  129. std::size_t const old_capacity = this->capacity();
  130. std::size_t new_capacity = size_ + size;
  131. // growth factor 2
  132. if( old_capacity <= max_size() - old_capacity ) // check for overflow
  133. new_capacity = (std::max)(old_capacity * 2, new_capacity);
  134. char* new_data = new char[new_capacity];
  135. std::memcpy(new_data, data_, size_);
  136. dispose();
  137. data_ = new_data;
  138. capacity_ = new_capacity;
  139. }
  140. char*
  141. append( char const* ptr, std::size_t size )
  142. {
  143. grow(size);
  144. if(BOOST_JSON_LIKELY( size ))
  145. std::memcpy( data_ + size_, ptr, size );
  146. size_ += size;
  147. return data_;
  148. }
  149. std::size_t
  150. size() noexcept
  151. {
  152. return size_;
  153. }
  154. };
  155. } // namespace detail
  156. } // namespace json
  157. } // namespace boost
  158. #endif // BOOST_JSON_DETAIL_SBO_BUFFER_HPP