Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-01-18 09:42:42

0001 //
0002 // Copyright (c) 2019-2023 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/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     // Calculate the required size for the new strings
0087     std::size_t size = 0;
0088     for (auto f : fields)
0089     {
0090         size += get_string_size(f);
0091     }
0092 
0093     // Make space. The previous fields should be in offset form
0094     string_buffer.resize(string_buffer.size() + size);
0095 
0096     // Copy strings and blobs
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 }  // namespace detail
0132 }  // namespace mysql
0133 }  // namespace boost
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     // Protect against self-assignment. This is valid as long as we
0155     // don't implement sub-range operators (e.g. row_view[2:4])
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     // Preconditions
0171     BOOST_ASSERT(first <= fields_.size());
0172     BOOST_ASSERT(first + num_fields <= fields_.size());
0173 
0174     // Calculate the required size for the new strings
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     // Make space. The previous fields should be in offset form
0182     std::size_t old_string_buffer_size = string_buffer_.size();
0183     string_buffer_.resize(old_string_buffer_size + size);
0184 
0185     // Copy strings and blobs
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