File indexing completed on 2025-01-18 09:42:42
0001
0002
0003
0004
0005
0006
0007
0008 #ifndef BOOST_MYSQL_IMPL_ROW_IMPL_IPP
0009 #define BOOST_MYSQL_IMPL_ROW_IMPL_IPP
0010
0011 #pragma once
0012
0013 #include <boost/mysql/detail/config.hpp>
0014 #include <boost/mysql/detail/row_impl.hpp>
0015
0016 namespace boost {
0017 namespace mysql {
0018 namespace detail {
0019
0020 BOOST_MYSQL_STATIC_OR_INLINE
0021 std::size_t get_string_size(field_view f) noexcept
0022 {
0023 switch (f.kind())
0024 {
0025 case field_kind::string: return f.get_string().size();
0026 case field_kind::blob: return f.get_blob().size();
0027 default: return 0;
0028 }
0029 }
0030
0031 BOOST_MYSQL_STATIC_OR_INLINE
0032 unsigned char* copy_string(unsigned char* buffer_it, field_view& f) noexcept
0033 {
0034 auto str = f.get_string();
0035 if (!str.empty())
0036 {
0037 std::memcpy(buffer_it, str.data(), str.size());
0038 f = field_view(string_view(reinterpret_cast<const char*>(buffer_it), str.size()));
0039 buffer_it += str.size();
0040 }
0041 return buffer_it;
0042 }
0043
0044 BOOST_MYSQL_STATIC_OR_INLINE
0045 unsigned char* copy_blob(unsigned char* buffer_it, field_view& f) noexcept
0046 {
0047 auto b = f.get_blob();
0048 if (!b.empty())
0049 {
0050 std::memcpy(buffer_it, b.data(), b.size());
0051 f = field_view(blob_view(buffer_it, b.size()));
0052 buffer_it += b.size();
0053 }
0054 return buffer_it;
0055 }
0056
0057 BOOST_MYSQL_STATIC_OR_INLINE
0058 std::size_t copy_string_as_offset(unsigned char* buffer_first, std::size_t offset, field_view& f) noexcept
0059 {
0060 auto str = f.get_string();
0061 if (!str.empty())
0062 {
0063 std::memcpy(buffer_first + offset, str.data(), str.size());
0064 f = detail::access::construct<field_view>(detail::string_view_offset{offset, str.size()}, false);
0065 return str.size();
0066 }
0067 return 0;
0068 }
0069
0070 BOOST_MYSQL_STATIC_OR_INLINE
0071 std::size_t copy_blob_as_offset(unsigned char* buffer_first, std::size_t offset, field_view& f) noexcept
0072 {
0073 auto str = f.get_blob();
0074 if (!str.empty())
0075 {
0076 std::memcpy(buffer_first + offset, str.data(), str.size());
0077 f = detail::access::construct<field_view>(detail::string_view_offset{offset, str.size()}, true);
0078 return str.size();
0079 }
0080 return 0;
0081 }
0082
0083 BOOST_MYSQL_STATIC_OR_INLINE
0084 void copy_strings(std::vector<field_view>& fields, std::vector<unsigned char>& string_buffer)
0085 {
0086
0087 std::size_t size = 0;
0088 for (auto f : fields)
0089 {
0090 size += get_string_size(f);
0091 }
0092
0093
0094 string_buffer.resize(string_buffer.size() + size);
0095
0096
0097 unsigned char* buffer_it = string_buffer.data();
0098 for (auto& f : fields)
0099 {
0100 switch (f.kind())
0101 {
0102 case field_kind::string: buffer_it = copy_string(buffer_it, f); break;
0103 case field_kind::blob: buffer_it = copy_blob(buffer_it, f); break;
0104 default: break;
0105 }
0106 }
0107 BOOST_ASSERT(buffer_it == string_buffer.data() + size);
0108 }
0109
0110 BOOST_MYSQL_STATIC_OR_INLINE
0111 field_view offset_to_string_view(field_view fv, const std::uint8_t* buffer_first) noexcept
0112 {
0113 auto& impl = detail::access::get_impl(fv);
0114 if (impl.is_string_offset())
0115 {
0116 return field_view(string_view(
0117 reinterpret_cast<const char*>(buffer_first) + impl.repr.sv_offset_.offset,
0118 impl.repr.sv_offset_.size
0119 ));
0120 }
0121 else if (impl.is_blob_offset())
0122 {
0123 return field_view(blob_view(buffer_first + impl.repr.sv_offset_.offset, impl.repr.sv_offset_.size));
0124 }
0125 else
0126 {
0127 return fv;
0128 }
0129 }
0130
0131 }
0132 }
0133 }
0134
0135 boost::mysql::detail::row_impl::row_impl(const field_view* fields, std::size_t size)
0136 : fields_(fields, fields + size)
0137 {
0138 copy_strings(fields_, string_buffer_);
0139 }
0140
0141 boost::mysql::detail::row_impl::row_impl(const row_impl& rhs) : fields_(rhs.fields_)
0142 {
0143 copy_strings(fields_, string_buffer_);
0144 }
0145
0146 boost::mysql::detail::row_impl& boost::mysql::detail::row_impl::operator=(const row_impl& rhs)
0147 {
0148 assign(rhs.fields_.data(), rhs.fields_.size());
0149 return *this;
0150 }
0151
0152 void boost::mysql::detail::row_impl::assign(const field_view* fields, std::size_t size)
0153 {
0154
0155
0156 if (fields_.data() == fields)
0157 {
0158 BOOST_ASSERT(fields_.size() == size);
0159 }
0160 else
0161 {
0162 fields_.assign(fields, fields + size);
0163 string_buffer_.clear();
0164 copy_strings(fields_, string_buffer_);
0165 }
0166 }
0167
0168 void boost::mysql::detail::row_impl::copy_strings_as_offsets(std::size_t first, std::size_t num_fields)
0169 {
0170
0171 BOOST_ASSERT(first <= fields_.size());
0172 BOOST_ASSERT(first + num_fields <= fields_.size());
0173
0174
0175 std::size_t size = 0;
0176 for (std::size_t i = first; i < first + num_fields; ++i)
0177 {
0178 size += get_string_size(fields_[i]);
0179 }
0180
0181
0182 std::size_t old_string_buffer_size = string_buffer_.size();
0183 string_buffer_.resize(old_string_buffer_size + size);
0184
0185
0186 std::size_t offset = old_string_buffer_size;
0187 for (std::size_t i = first; i < first + num_fields; ++i)
0188 {
0189 auto& f = fields_[i];
0190 switch (f.kind())
0191 {
0192 case field_kind::string: offset += copy_string_as_offset(string_buffer_.data(), offset, f); break;
0193 case field_kind::blob: offset += copy_blob_as_offset(string_buffer_.data(), offset, f); break;
0194 default: break;
0195 }
0196 }
0197 BOOST_ASSERT(offset == string_buffer_.size());
0198 }
0199
0200 void boost::mysql::detail::row_impl::offsets_to_string_views()
0201 {
0202 for (auto& f : fields_)
0203 f = offset_to_string_view(f, string_buffer_.data());
0204 }
0205
0206 #endif