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:
105
include/boost/mysql/detail/auxiliar/field_ptr.hpp.hpp
Normal file
105
include/boost/mysql/detail/auxiliar/field_ptr.hpp.hpp
Normal 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
|
||||
@@ -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
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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_;
|
||||
};
|
||||
|
||||
|
||||
|
||||
@@ -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_ {};
|
||||
};
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user