Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-07-12 08:21:21

0001 //
0002 // Copyright (c) 2019-2024 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)
0003 //
0004 // Distributed under the Boost Software License, Version 1.0. (See accompanying
0005 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
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/row_impl.hpp>
0014 
0015 namespace boost {
0016 namespace mysql {
0017 namespace detail {
0018 
0019 inline std::size_t get_string_size(field_view f)
0020 {
0021     switch (f.kind())
0022     {
0023     case field_kind::string: return f.get_string().size();
0024     case field_kind::blob: return f.get_blob().size();
0025     default: return 0;
0026     }
0027 }
0028 
0029 inline unsigned char* copy_string(unsigned char* buffer_it, field_view& f)
0030 {
0031     auto str = f.get_string();
0032     if (!str.empty())
0033     {
0034         std::memcpy(buffer_it, str.data(), str.size());
0035         f = field_view(string_view(reinterpret_cast<const char*>(buffer_it), str.size()));
0036         buffer_it += str.size();
0037     }
0038     return buffer_it;
0039 }
0040 
0041 inline unsigned char* copy_blob(unsigned char* buffer_it, field_view& f)
0042 {
0043     auto b = f.get_blob();
0044     if (!b.empty())
0045     {
0046         std::memcpy(buffer_it, b.data(), b.size());
0047         f = field_view(blob_view(buffer_it, b.size()));
0048         buffer_it += b.size();
0049     }
0050     return buffer_it;
0051 }
0052 
0053 inline std::size_t copy_string_as_offset(unsigned char* buffer_first, std::size_t offset, field_view& f)
0054 {
0055     auto str = f.get_string();
0056     if (!str.empty())
0057     {
0058         std::memcpy(buffer_first + offset, str.data(), str.size());
0059         f = detail::access::construct<field_view>(detail::string_view_offset{offset, str.size()}, false);
0060         return str.size();
0061     }
0062     return 0;
0063 }
0064 
0065 inline std::size_t copy_blob_as_offset(unsigned char* buffer_first, std::size_t offset, field_view& f)
0066 {
0067     auto str = f.get_blob();
0068     if (!str.empty())
0069     {
0070         std::memcpy(buffer_first + offset, str.data(), str.size());
0071         f = detail::access::construct<field_view>(detail::string_view_offset{offset, str.size()}, true);
0072         return str.size();
0073     }
0074     return 0;
0075 }
0076 
0077 inline void copy_strings(std::vector<field_view>& fields, std::vector<unsigned char>& string_buffer)
0078 {
0079     // Calculate the required size for the new strings
0080     std::size_t size = 0;
0081     for (auto f : fields)
0082     {
0083         size += get_string_size(f);
0084     }
0085 
0086     // Make space. The previous fields should be in offset form
0087     string_buffer.resize(string_buffer.size() + size);
0088 
0089     // Copy strings and blobs
0090     unsigned char* buffer_it = string_buffer.data();
0091     for (auto& f : fields)
0092     {
0093         switch (f.kind())
0094         {
0095         case field_kind::string: buffer_it = copy_string(buffer_it, f); break;
0096         case field_kind::blob: buffer_it = copy_blob(buffer_it, f); break;
0097         default: break;
0098         }
0099     }
0100     BOOST_ASSERT(buffer_it == string_buffer.data() + size);
0101 }
0102 
0103 inline field_view offset_to_string_view(field_view fv, const std::uint8_t* buffer_first)
0104 {
0105     auto& impl = detail::access::get_impl(fv);
0106     if (impl.is_string_offset())
0107     {
0108         return field_view(string_view(
0109             reinterpret_cast<const char*>(buffer_first) + impl.repr.sv_offset_.offset,
0110             impl.repr.sv_offset_.size
0111         ));
0112     }
0113     else if (impl.is_blob_offset())
0114     {
0115         return field_view(blob_view(buffer_first + impl.repr.sv_offset_.offset, impl.repr.sv_offset_.size));
0116     }
0117     else
0118     {
0119         return fv;
0120     }
0121 }
0122 
0123 }  // namespace detail
0124 }  // namespace mysql
0125 }  // namespace boost
0126 
0127 boost::mysql::detail::row_impl::row_impl(const field_view* fields, std::size_t size)
0128     : fields_(fields, fields + size)
0129 {
0130     copy_strings(fields_, string_buffer_);
0131 }
0132 
0133 boost::mysql::detail::row_impl::row_impl(const row_impl& rhs) : fields_(rhs.fields_)
0134 {
0135     copy_strings(fields_, string_buffer_);
0136 }
0137 
0138 boost::mysql::detail::row_impl& boost::mysql::detail::row_impl::operator=(const row_impl& rhs)
0139 {
0140     assign(rhs.fields_.data(), rhs.fields_.size());
0141     return *this;
0142 }
0143 
0144 void boost::mysql::detail::row_impl::assign(const field_view* fields, std::size_t size)
0145 {
0146     // Protect against self-assignment. This is valid as long as we
0147     // don't implement sub-range operators (e.g. row_view[2:4])
0148     if (fields_.data() == fields)
0149     {
0150         BOOST_ASSERT(fields_.size() == size);
0151     }
0152     else
0153     {
0154         fields_.assign(fields, fields + size);
0155         string_buffer_.clear();
0156         copy_strings(fields_, string_buffer_);
0157     }
0158 }
0159 
0160 void boost::mysql::detail::row_impl::copy_strings_as_offsets(std::size_t first, std::size_t num_fields)
0161 {
0162     // Preconditions
0163     BOOST_ASSERT(first <= fields_.size());
0164     BOOST_ASSERT(first + num_fields <= fields_.size());
0165 
0166     // Calculate the required size for the new strings
0167     std::size_t size = 0;
0168     for (std::size_t i = first; i < first + num_fields; ++i)
0169     {
0170         size += get_string_size(fields_[i]);
0171     }
0172 
0173     // Make space. The previous fields should be in offset form
0174     std::size_t old_string_buffer_size = string_buffer_.size();
0175     string_buffer_.resize(old_string_buffer_size + size);
0176 
0177     // Copy strings and blobs
0178     std::size_t offset = old_string_buffer_size;
0179     for (std::size_t i = first; i < first + num_fields; ++i)
0180     {
0181         auto& f = fields_[i];
0182         switch (f.kind())
0183         {
0184         case field_kind::string: offset += copy_string_as_offset(string_buffer_.data(), offset, f); break;
0185         case field_kind::blob: offset += copy_blob_as_offset(string_buffer_.data(), offset, f); break;
0186         default: break;
0187         }
0188     }
0189     BOOST_ASSERT(offset == string_buffer_.size());
0190 }
0191 
0192 void boost::mysql::detail::row_impl::offsets_to_string_views()
0193 {
0194     for (auto& f : fields_)
0195         f = offset_to_string_view(f, string_buffer_.data());
0196 }
0197 
0198 #endif