row_impl.ipp 5.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198
  1. //
  2. // Copyright (c) 2019-2024 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)
  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. #ifndef BOOST_MYSQL_IMPL_ROW_IMPL_IPP
  8. #define BOOST_MYSQL_IMPL_ROW_IMPL_IPP
  9. #pragma once
  10. #include <boost/mysql/detail/row_impl.hpp>
  11. namespace boost {
  12. namespace mysql {
  13. namespace detail {
  14. inline std::size_t get_string_size(field_view f)
  15. {
  16. switch (f.kind())
  17. {
  18. case field_kind::string: return f.get_string().size();
  19. case field_kind::blob: return f.get_blob().size();
  20. default: return 0;
  21. }
  22. }
  23. inline unsigned char* copy_string(unsigned char* buffer_it, field_view& f)
  24. {
  25. auto str = f.get_string();
  26. if (!str.empty())
  27. {
  28. std::memcpy(buffer_it, str.data(), str.size());
  29. f = field_view(string_view(reinterpret_cast<const char*>(buffer_it), str.size()));
  30. buffer_it += str.size();
  31. }
  32. return buffer_it;
  33. }
  34. inline unsigned char* copy_blob(unsigned char* buffer_it, field_view& f)
  35. {
  36. auto b = f.get_blob();
  37. if (!b.empty())
  38. {
  39. std::memcpy(buffer_it, b.data(), b.size());
  40. f = field_view(blob_view(buffer_it, b.size()));
  41. buffer_it += b.size();
  42. }
  43. return buffer_it;
  44. }
  45. inline std::size_t copy_string_as_offset(unsigned char* buffer_first, std::size_t offset, field_view& f)
  46. {
  47. auto str = f.get_string();
  48. if (!str.empty())
  49. {
  50. std::memcpy(buffer_first + offset, str.data(), str.size());
  51. f = detail::access::construct<field_view>(detail::string_view_offset{offset, str.size()}, false);
  52. return str.size();
  53. }
  54. return 0;
  55. }
  56. inline std::size_t copy_blob_as_offset(unsigned char* buffer_first, std::size_t offset, field_view& f)
  57. {
  58. auto str = f.get_blob();
  59. if (!str.empty())
  60. {
  61. std::memcpy(buffer_first + offset, str.data(), str.size());
  62. f = detail::access::construct<field_view>(detail::string_view_offset{offset, str.size()}, true);
  63. return str.size();
  64. }
  65. return 0;
  66. }
  67. inline void copy_strings(std::vector<field_view>& fields, std::vector<unsigned char>& string_buffer)
  68. {
  69. // Calculate the required size for the new strings
  70. std::size_t size = 0;
  71. for (auto f : fields)
  72. {
  73. size += get_string_size(f);
  74. }
  75. // Make space. The previous fields should be in offset form
  76. string_buffer.resize(string_buffer.size() + size);
  77. // Copy strings and blobs
  78. unsigned char* buffer_it = string_buffer.data();
  79. for (auto& f : fields)
  80. {
  81. switch (f.kind())
  82. {
  83. case field_kind::string: buffer_it = copy_string(buffer_it, f); break;
  84. case field_kind::blob: buffer_it = copy_blob(buffer_it, f); break;
  85. default: break;
  86. }
  87. }
  88. BOOST_ASSERT(buffer_it == string_buffer.data() + size);
  89. }
  90. inline field_view offset_to_string_view(field_view fv, const std::uint8_t* buffer_first)
  91. {
  92. auto& impl = detail::access::get_impl(fv);
  93. if (impl.is_string_offset())
  94. {
  95. return field_view(string_view(
  96. reinterpret_cast<const char*>(buffer_first) + impl.repr.sv_offset_.offset,
  97. impl.repr.sv_offset_.size
  98. ));
  99. }
  100. else if (impl.is_blob_offset())
  101. {
  102. return field_view(blob_view(buffer_first + impl.repr.sv_offset_.offset, impl.repr.sv_offset_.size));
  103. }
  104. else
  105. {
  106. return fv;
  107. }
  108. }
  109. } // namespace detail
  110. } // namespace mysql
  111. } // namespace boost
  112. boost::mysql::detail::row_impl::row_impl(const field_view* fields, std::size_t size)
  113. : fields_(fields, fields + size)
  114. {
  115. copy_strings(fields_, string_buffer_);
  116. }
  117. boost::mysql::detail::row_impl::row_impl(const row_impl& rhs) : fields_(rhs.fields_)
  118. {
  119. copy_strings(fields_, string_buffer_);
  120. }
  121. boost::mysql::detail::row_impl& boost::mysql::detail::row_impl::operator=(const row_impl& rhs)
  122. {
  123. assign(rhs.fields_.data(), rhs.fields_.size());
  124. return *this;
  125. }
  126. void boost::mysql::detail::row_impl::assign(const field_view* fields, std::size_t size)
  127. {
  128. // Protect against self-assignment. This is valid as long as we
  129. // don't implement sub-range operators (e.g. row_view[2:4])
  130. if (fields_.data() == fields)
  131. {
  132. BOOST_ASSERT(fields_.size() == size);
  133. }
  134. else
  135. {
  136. fields_.assign(fields, fields + size);
  137. string_buffer_.clear();
  138. copy_strings(fields_, string_buffer_);
  139. }
  140. }
  141. void boost::mysql::detail::row_impl::copy_strings_as_offsets(std::size_t first, std::size_t num_fields)
  142. {
  143. // Preconditions
  144. BOOST_ASSERT(first <= fields_.size());
  145. BOOST_ASSERT(first + num_fields <= fields_.size());
  146. // Calculate the required size for the new strings
  147. std::size_t size = 0;
  148. for (std::size_t i = first; i < first + num_fields; ++i)
  149. {
  150. size += get_string_size(fields_[i]);
  151. }
  152. // Make space. The previous fields should be in offset form
  153. std::size_t old_string_buffer_size = string_buffer_.size();
  154. string_buffer_.resize(old_string_buffer_size + size);
  155. // Copy strings and blobs
  156. std::size_t offset = old_string_buffer_size;
  157. for (std::size_t i = first; i < first + num_fields; ++i)
  158. {
  159. auto& f = fields_[i];
  160. switch (f.kind())
  161. {
  162. case field_kind::string: offset += copy_string_as_offset(string_buffer_.data(), offset, f); break;
  163. case field_kind::blob: offset += copy_blob_as_offset(string_buffer_.data(), offset, f); break;
  164. default: break;
  165. }
  166. }
  167. BOOST_ASSERT(offset == string_buffer_.size());
  168. }
  169. void boost::mysql::detail::row_impl::offsets_to_string_views()
  170. {
  171. for (auto& f : fields_)
  172. f = offset_to_string_view(f, string_buffer_.data());
  173. }
  174. #endif