2
0
mirror of https://github.com/boostorg/mysql.git synced 2026-02-14 12:52:17 +00:00

row_view, row, field_ptr

This commit is contained in:
Ruben Perez
2022-08-17 19:35:56 +02:00
parent b92e25e6e0
commit afd3842f14
5 changed files with 195 additions and 146 deletions

View File

@@ -0,0 +1,105 @@
//
// Copyright (c) 2019-2022 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
#ifndef BOOST_MYSQL_DETAIL_AUXILIAR_FIELD_PTR_HPP_HPP
#define BOOST_MYSQL_DETAIL_AUXILIAR_FIELD_PTR_HPP_HPP
#include <vector>
#include <cstdint>
#include <boost/mysql/field.hpp>
#include <boost/mysql/field_view.hpp>
namespace boost {
namespace mysql {
namespace detail {
class field_ptr
{
enum class type
{
field_view,
field
};
type type_ {type::field_view};
const void* ptr_ {};
const void* incremented(std::ptrdiff_t n) const noexcept
{
if (type_ == type::field_view)
{
return static_cast<const field_view*>(ptr_) + n;
}
else
{
return static_cast<const field*>(ptr_) + n;
}
}
field_view dereference() const noexcept
{
if (type_ == type::field_view)
{
return *static_cast<const field_view*>(ptr_);
}
else
{
return *static_cast<const field*>(ptr_);
}
}
field_ptr(type t, const void* ptr) noexcept : type_(t), ptr_(ptr) {}
public:
using value_type = field;
using reference = field_view;
using pointer = void const*;
using difference_type = std::ptrdiff_t;
using iterator_category = std::random_access_iterator_tag;
field_ptr() noexcept = default;
explicit field_ptr(const field_view* v) noexcept : type_(type::field_view), ptr_(v) {}
explicit field_ptr(const field* v) noexcept : type_(type::field), ptr_(v) {}
const field* as_field() const noexcept { assert(type_ == type::field); return static_cast<const field*>(ptr_); }
const field_view* as_field_view() const noexcept { assert(type_ == type::field_view); return static_cast<const field_view*>(ptr_); }
field_ptr& operator++() noexcept { ptr_ = incremented(1); return *this; }
field_ptr operator++(int) noexcept { return field_ptr(type_, incremented(1)); }
field_ptr& operator--() noexcept { ptr_ = incremented(-1); return *this; }
field_ptr operator--(int) noexcept { return field_ptr(type_, incremented(-1)); }
field_ptr& operator+=(std::ptrdiff_t n) noexcept { ptr_ = incremented(n); return *this; }
field_ptr& operator-=(std::ptrdiff_t n) noexcept { ptr_ = incremented(-n); return *this; }
field_ptr operator+(std::ptrdiff_t n) const noexcept { return field_ptr(type_, incremented(n)); }
field_ptr operator-(std::ptrdiff_t n) const noexcept { return field_ptr(type_, incremented(-n)); }
std::ptrdiff_t operator-(const field_ptr& rhs) const noexcept
{
if (type_ == type::field)
{
return static_cast<const field*>(ptr_) - static_cast<const field*>(rhs.ptr_);
}
else
{
return static_cast<const field_view*>(ptr_) - static_cast<const field_view*>(rhs.ptr_);
}
}
field_view operator*() const noexcept { return dereference(); }
field_view operator[](std::ptrdiff_t i) const noexcept { return (*this + i).dereference(); }
bool operator==(const field_ptr& rhs) const noexcept { return type_ == rhs.type_ && ptr_ == rhs.ptr_; }
bool operator!=(const field_ptr& rhs) const noexcept { return !(*this == rhs); }
bool operator<(const field_ptr& rhs) const noexcept { return ptr_ < rhs.ptr_; }
bool operator<=(const field_ptr& rhs) const noexcept { return ptr_ <= rhs.ptr_; }
bool operator>(const field_ptr& rhs) const noexcept { return ptr_ > rhs.ptr_; }
bool operator>=(const field_ptr& rhs) const noexcept { return ptr_ >= rhs.ptr_; }
};
inline field_ptr operator+(std::ptrdiff_t n, const field_ptr& ptr) noexcept { return ptr + n; }
}
}
}
#endif

View File

@@ -11,134 +11,64 @@
#pragma once
#include <boost/mysql/row.hpp>
#include <cstddef>
#include <iterator>
inline void boost::mysql::row::rebase_strings(
const char* old_buffer_base
std::vector<boost::mysql::field>::iterator boost::mysql::row::from_ptr(
detail::field_ptr ptr
) noexcept
{
auto diff = string_buffer_.data() - old_buffer_base;
for (auto& f: fields_)
{
const boost::string_view* str = f.if_string();
if (str)
{
f = field_view(boost::string_view(
str->data() + diff,
str->size()
));
}
}
assert(ptr >= begin() && ptr <= end());
return fields_.begin() + (begin() - ptr);
}
inline void boost::mysql::row::copy_strings()
{
// Calculate size
std::size_t size = 0;
for (const auto& f: fields_)
{
const boost::string_view* str = f.if_string();
if (str)
{
size += str->size();
}
}
// Make space
string_buffer_.resize(size);
// Copy the strings
std::size_t offset = 0;
for (auto& f: fields_)
{
const boost::string_view* str = f.if_string();
if (str)
{
std::memcpy(string_buffer_.data() + offset, str->data(), str->size());
f = field_view(boost::string_view(string_buffer_.data() + offset, str->size()));
offset += str->size();
}
}
}
inline boost::mysql::row::iterator boost::mysql::row::to_row_it(
std::vector<field_view>::iterator it
boost::mysql::detail::field_ptr boost::mysql::row::to_ptr(
std::vector<field>::iterator it
) noexcept
{
return it == fields_.end() ? nullptr : fields_.data() + (it - fields_.begin());
}
inline std::vector<boost::mysql::field_view>::iterator boost::mysql::row::to_vector_it(
iterator it
) noexcept
{
return it == nullptr ? fields_.end() : fields_.begin() + (it - fields_.data());
}
boost::mysql::row::row(
const row& other
) :
fields_(other.fields_),
string_buffer_(other.string_buffer_)
{
rebase_strings(other.string_buffer_.data());
return begin() + (fields_.begin() - it);
}
const boost::mysql::row& boost::mysql::row::operator=(
const row& rhs
)
{
fields_ = rhs.fields_;
string_buffer_ = rhs.string_buffer_;
rebase_strings(rhs.string_buffer_.data());
return *this;
}
inline boost::string_view boost::mysql::row::copy_string(
boost::string_view v
)
{
const char* old_buffer_base = string_buffer_.data();
std::size_t old_buffer_size = string_buffer_.size();
string_buffer_.insert(string_buffer_.end(), v.data(), v.data() + v.size());
if (string_buffer_.data() != old_buffer_base)
rebase_strings(old_buffer_base);
return boost::string_view(string_buffer_.data() + old_buffer_size, v.size());
}
inline boost::mysql::row::iterator boost::mysql::row::insert(
iterator before,
boost::mysql::row::iterator boost::mysql::row::replace(
iterator pos,
field_view v
)
{
const auto* str = v.if_string();
if (str)
{
v = field_view(copy_string(*str));
}
auto res = fields_.insert(to_vector_it(before), v);
return to_row_it(res);
assert(pos >= begin() && pos < end());
*const_cast<field*>(pos.as_field()) = v;
return pos;
}
// inline boost::mysql::row::iterator boost::mysql::row::insert(
// iterator before,
// std::initializer_list<field_view> v
// )
// {
// // Calculate the extra size required for the strings
// std::size_t new_string_size = 0;
// for (const auto& f: v)
// {
// const auto* str = f.if_string();
// if (str)
// {
// new_string_size += str->size();
// }
// }
boost::mysql::row::iterator boost::mysql::row::replace(
iterator first,
iterator last,
std::initializer_list<field_view> v
)
{
return replace(first, last, v.begin(), v.end());
}
// }
template <class FwdIt>
boost::mysql::row::iterator boost::mysql::row::replace(
iterator first,
iterator last,
FwdIt other_first,
FwdIt other_last
)
{
assert(last >= first);
assert((last - first) == std::distance(other_first, other_last));
auto itfrom = other_first;
auto itto = first;
for (; itto != last; ++itto, ++itfrom)
{
*const_cast<field*>(itto.as_field()) = *itfrom;
}
return first; // TODO: first or last?
}
#endif

View File

@@ -13,6 +13,17 @@
#include <boost/mysql/row_view.hpp>
#include <algorithm>
#include <ostream>
#include <stdexcept>
boost::mysql::field_view boost::mysql::row_view::at(
std::size_t i
) const
{
if (i >= size_)
throw std::out_of_range("row_view::at");
return fields_[i];
}
inline bool boost::mysql::operator==(
const row_view& lhs,

View File

@@ -10,7 +10,8 @@
#include <boost/mysql/field_view.hpp>
#include <boost/mysql/row_view.hpp>
#include <boost/utility/string_view_fwd.hpp>
#include <boost/mysql/detail/auxiliar/field_ptr.hpp.hpp>
#include <cstddef>
#include <vector>
@@ -44,18 +45,23 @@ class row
{
public:
row() = default;
inline row(const row&);
row(row_view r) : fields_(r.begin(), r.end()) {}
row(const row&) = default;
row(row&&) = default;
inline const row& operator=(const row&);
row& operator=(const row&) = default;
row& operator=(row&&) = default;
~row() = default;
using iterator = const field_view*;
using iterator = detail::field_ptr;
using const_iterator = iterator;
// TODO: add other standard container members when we add field and field_view
using value_type = field;
using reference = field_view;
using const_reference = reference;
using size_type = std::size_t;
using difference_type = std::ptrdiff_t;
iterator begin() const noexcept { return fields_.data(); }
iterator end() const noexcept { return fields_.data() + fields_.size(); }
iterator begin() const noexcept { return iterator(fields_.data()); }
iterator end() const noexcept { return iterator(fields_.data() + fields_.size()); }
field_view at(std::size_t i) const { return fields_.at(i); }
field_view operator[](std::size_t i) const noexcept { return fields_[i]; }
field_view front() const noexcept { return fields_.front(); }
@@ -63,21 +69,21 @@ public:
bool empty() const noexcept { return fields_.empty(); }
std::size_t size() const noexcept { return fields_.size(); }
inline iterator insert(iterator before, field_view v);
inline iterator insert(iterator before, std::initializer_list<field_view> v);
inline iterator insert(iterator before, field_view v) { return to_ptr(fields_.insert(from_ptr(before), v)); }
inline iterator insert(iterator before, std::initializer_list<field_view> v) { return to_ptr(fields_.insert(from_ptr(before), v.begin(), v.end())); }
template <class FwdIt>
iterator insert(iterator before, FwdIt first, FwdIt last);
iterator insert(iterator before, FwdIt first, FwdIt last) { return to_ptr(fields_.insert(from_ptr(before), first, last));}
inline iterator replace(iterator pos, field_view v);
inline iterator replace(iterator first, iterator last, std::initializer_list<field_view> v);
template <class FwdIt>
inline iterator replace(iterator first, iterator last, FwdIt other_first, FwdIt other_last);
inline iterator erase(iterator pos);
inline iterator erase(iterator first, iterator last);
inline iterator erase(iterator pos) { return to_ptr(fields_.erase(from_ptr(pos))); }
inline iterator erase(iterator first, iterator last) { return to_ptr(fields_.erase(from_ptr(first), from_ptr(last))); }
inline void push_back(field_view v);
inline void pop_back();
inline void push_back(field_view v) { fields_.emplace_back(v); }
inline void pop_back() { fields_.pop_back(); }
operator row_view() const noexcept
{
@@ -93,24 +99,12 @@ public:
* pointers, references and iterators to elements in [refmem row values] will be invalidated.
* Any string values using the memory held by this row will also become invalid.
*/
void clear() noexcept
{
fields_.clear();
string_buffer_.clear();
}
// TODO: hide these
const std::vector<field_view>& fields() const noexcept { return fields_; }
std::vector<field_view>& values() noexcept { return fields_; }
inline void copy_strings();
void clear() noexcept { fields_.clear(); }
private:
std::vector<field_view> fields_;
std::vector<char> string_buffer_;
inline std::vector<field>::iterator from_ptr(detail::field_ptr) noexcept;
inline detail::field_ptr to_ptr(std::vector<field>::iterator) noexcept;
inline iterator to_row_it(std::vector<field_view>::iterator it) noexcept;
inline std::vector<field_view>::iterator to_vector_it(iterator it) noexcept;
inline boost::string_view copy_string(boost::string_view v);
inline void rebase_strings(const char* old_buffer_base) noexcept;
std::vector<field> fields_;
};

View File

@@ -8,32 +8,41 @@
#ifndef BOOST_MYSQL_ROW_VIEW_HPP
#define BOOST_MYSQL_ROW_VIEW_HPP
#include <boost/mysql/field_view.hpp>
#include <boost/mysql/detail/auxiliar/field_ptr.hpp.hpp>
#include <cstddef>
#include <iosfwd>
#include <iterator>
namespace boost {
namespace mysql {
class row_view
{
const field_view* fields_ {};
std::size_t size_ {};
public:
row_view() = default;
row_view(const field_view* f, std::size_t size) noexcept : fields_ {f}, size_{size} {}
row_view(const field_view* f, std::size_t size) noexcept : fields_ (f), size_(size) {}
row_view(const field* f, std::size_t size) noexcept : fields_(f), size_(size) {}
using iterator = const field_view*;
using iterator = detail::field_ptr;
using const_iterator = iterator;
using value_type = field;
using reference = field_view;
using const_reference = field_view;
using size_type = std::size_t;
using difference_type = std::ptrdiff_t;
iterator begin() const noexcept { return fields_; }
iterator end() const noexcept { return fields_ + size_; }
field_view at(std::size_t i) const;
field_view operator[](std::size_t i) const noexcept { return fields_[i]; }
field_view front() const noexcept { return fields_[0]; }
field_view front() const noexcept { return *fields_; }
field_view back() const noexcept { return fields_[size_ - 1]; }
bool empty() const noexcept { return size_ == 0; }
std::size_t size() const noexcept { return size_; }
private:
detail::field_ptr fields_ {};
std::size_t size_ {};
};