row_impl.ipp 5.8 KB

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