2
0
mirror of https://github.com/boostorg/mysql.git synced 2026-02-17 13:52:18 +00:00
This commit is contained in:
Ruben Perez
2022-08-18 16:30:04 +02:00
parent cbffee7d55
commit ed12d12f38
7 changed files with 222 additions and 185 deletions

View File

@@ -0,0 +1,68 @@
//
// 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_ROWS_ITERATOR_HPP
#define BOOST_MYSQL_DETAIL_AUXILIAR_ROWS_ITERATOR_HPP
#include <cstdint>
#include <boost/mysql/row.hpp>
#include <boost/mysql/row_view.hpp>
#include <iterator>
namespace boost {
namespace mysql {
namespace detail {
template <class RowsType> // This can be either rows or rows_view
class rows_iterator
{
const RowsType* obj_;
std::size_t row_num_;
public:
using value_type = row;
using reference = row_view;
using pointer = const void*;
using difference_type = std::ptrdiff_t;
using iterator_category = std::random_access_iterator_tag;
rows_iterator(const RowsType* obj, std::size_t rownum) noexcept : obj_(obj), row_num_(rownum) {}
rows_iterator& operator++() noexcept { ++row_num_; return *this; }
rows_iterator operator++(int) noexcept { return rows_iterator(obj_, row_num_ + 1); }
rows_iterator& operator--() noexcept { --row_num_; return *this; }
rows_iterator operator--(int) noexcept { return rows_iterator(obj_, row_num_ - 1); }
rows_iterator& operator+=(std::ptrdiff_t n) noexcept { row_num_ += n; return *this; }
rows_iterator& operator-=(std::ptrdiff_t n) noexcept { row_num_ -= n; return *this; }
rows_iterator operator+(std::ptrdiff_t n) const noexcept { return rows_iterator(obj_, row_num_ + n); }
rows_iterator operator-(std::ptrdiff_t n) const noexcept { return rows_iterator(obj_, row_num_ - n); }
std::ptrdiff_t operator-(rows_iterator rhs) const noexcept { return row_num_ - rhs.row_num_; }
reference operator*() const noexcept { return (*obj_)[row_num_]; }
reference operator[](std::ptrdiff_t i) const noexcept { return (*obj_)[row_num_ + i]; }
bool operator==(rows_iterator rhs) const noexcept { return obj_ == rhs.obj_&& row_num_ == rhs.row_num_; }
bool operator!=(rows_iterator rhs) const noexcept { return !(*this == rhs); }
bool operator<(rows_iterator rhs) const noexcept { return row_num_ < rhs.row_num_; }
bool operator<=(rows_iterator rhs) const noexcept { return row_num_ <= rhs.row_num_; }
bool operator>(rows_iterator rhs) const noexcept { return row_num_ > rhs.row_num_; }
bool operator>=(rows_iterator rhs) const noexcept { return row_num_ >= rhs.row_num_; }
};
template <class RowsType>
rows_iterator<RowsType> operator+(std::ptrdiff_t n, rows_iterator<RowsType> it) noexcept
{
return it + n;
}
}
}
}
#endif

View File

@@ -8,33 +8,59 @@
#ifndef BOOST_MYSQL_IMPL_ROWS_IPP
#define BOOST_MYSQL_IMPL_ROWS_IPP
#include "boost/mysql/rows_view.hpp"
#include <cstddef>
#pragma once
#include <boost/mysql/rows.hpp>
#include <stdexcept>
inline void boost::mysql::rows::rebase_strings(const char* old_buffer_base)
boost::mysql::rows::rows(
const rows_view& view
) :
fields_(view.begin(), view.end())
{
const char* new_buffer_base = string_buffer_.data();
auto diff = new_buffer_base - old_buffer_base;
if (diff)
{
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()
));
}
}
}
copy_strings();
}
inline boost::mysql::row_view boost::mysql::rows::at(
boost::mysql::rows::rows(
const rows& rhs
) :
fields_(rhs.fields_),
string_buffer_(rhs.string_buffer_)
{
rebase_strings(rhs.string_buffer_.data());
}
boost::mysql::rows& boost::mysql::rows::operator=(
const rows& rhs
)
{
fields_ = rhs.fields_;
string_buffer_ = rhs.string_buffer_;
rebase_strings(rhs.string_buffer_.data());
return *this;
}
boost::mysql::rows& boost::mysql::rows::operator=(
const rows_view& rhs
)
{
fields_.assign(rhs.begin(), rhs.end());
copy_strings();
return *this;
}
boost::mysql::row_view boost::mysql::rows::operator[](
std::size_t i
) const noexcept
{
return row_view(fields_.data() + num_columns_ * i, num_columns_);
}
boost::mysql::row_view boost::mysql::rows::at(
std::size_t i
) const
{
@@ -45,31 +71,48 @@ inline boost::mysql::row_view boost::mysql::rows::at(
return (*this)[i];
}
inline void boost::mysql::rows::copy_strings(std::size_t field_offset)
inline void boost::mysql::rows::rebase_strings(const char* old_buffer_base)
{
// Calculate the extra size required for the new strings
std::size_t size = 0;
for (const auto* f = fields_.data() + field_offset; f != fields_.data() + fields_.size(); ++f)
const char* new_buffer_base = string_buffer_.data();
auto diff = new_buffer_base - old_buffer_base;
if (diff)
{
const boost::string_view* str = f->if_string();
for (auto& f: fields_)
{
const boost::string_view* str = f.if_string();
if (str && !str->empty())
{
f = field_view(boost::string_view(
str->data() + diff,
str->size()
));
}
}
}
}
inline void boost::mysql::rows::copy_strings()
{
// Calculate the required size for the new strings
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 and rebase the old strings
const char* old_buffer_base = string_buffer_.data();
std::size_t old_buffer_size = string_buffer_.size();
// Make space
string_buffer_.resize(size);
rebase_strings(old_buffer_base);
// Copy the strings
std::size_t offset = old_buffer_size;
std::size_t offset = 0;
for (auto& f: fields_)
{
const boost::string_view* str = f.if_string();
if (str)
if (str && !str->empty())
{
std::memcpy(string_buffer_.data() + offset, str->data(), str->size());
f = field_view(boost::string_view(string_buffer_.data() + offset, str->size()));

View File

@@ -1,93 +0,0 @@
//
// 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_IMPL_ROWS_VIEW_HPP
#define BOOST_MYSQL_IMPL_ROWS_VIEW_HPP
#pragma once
#include <boost/mysql/rows_view.hpp>
#include <cstddef>
#include <iterator>
#include <stdexcept>
#include <cassert>
class boost::mysql::rows_view::iterator
{
const rows_view* obj_;
std::size_t row_num_;
public:
using value_type = row;
using reference = row_view;
using pointer = const void*;
using difference_type = std::ptrdiff_t;
using iterator_category = std::bidirectional_iterator_tag;
iterator(const rows_view* obj, std::size_t rownum) noexcept : obj_(obj), row_num_(rownum) {}
iterator& operator++() noexcept { ++row_num_; return *this; }
iterator operator++(int) noexcept { return iterator(obj_, row_num_ + 1); }
iterator& operator--() noexcept { --row_num_; return *this; }
iterator operator--(int) noexcept { return iterator(obj_, row_num_ - 1); }
iterator& operator+=(std::ptrdiff_t n) noexcept { row_num_ += n; return *this; }
iterator& operator-=(std::ptrdiff_t n) noexcept { row_num_ -= n; return *this; }
iterator operator+(std::ptrdiff_t n) const noexcept { return iterator(obj_, row_num_ + n); }
iterator operator-(std::ptrdiff_t n) const noexcept { return iterator(obj_, row_num_ - n); }
std::ptrdiff_t operator-(const iterator& rhs) const noexcept { return row_num_ - rhs.row_num_; }
reference operator*() const noexcept { return (*obj_)[row_num_]; }
reference operator[](std::ptrdiff_t i) const noexcept { return (*obj_)[row_num_ + i]; }
bool operator==(const iterator& rhs) const noexcept { return obj_ == rhs.obj_&& row_num_ == rhs.row_num_; }
bool operator!=(const iterator& rhs) const noexcept { return !(*this == rhs); }
bool operator<(const iterator& rhs) const noexcept { return row_num_ < rhs.row_num_; }
bool operator<=(const iterator& rhs) const noexcept { return row_num_ <= rhs.row_num_; }
bool operator>(const iterator& rhs) const noexcept { return row_num_ > rhs.row_num_; }
bool operator>=(const iterator& rhs) const noexcept { return row_num_ >= rhs.row_num_; }
};
inline boost::mysql::rows_view::iterator operator+(
std::ptrdiff_t n,
const boost::mysql::rows_view::iterator& it
) noexcept
{
return it + n;
}
boost::mysql::row_view boost::mysql::rows_view::operator[](
std::size_t i
) const noexcept
{
assert(i >= size());
return row_view(fields_ + num_columns_ * i, num_columns_);
}
boost::mysql::row_view boost::mysql::rows_view::at(
std::size_t i
) const
{
if (i >= size())
{
throw std::out_of_range("rows_view::at");
}
return (*this)[i];
}
boost::mysql::rows_view::iterator boost::mysql::rows_view::begin() const noexcept
{
return iterator(this, 0);
}
boost::mysql::rows_view::iterator boost::mysql::rows_view::end() const noexcept
{
return iterator(this, size());
}
#endif

View File

@@ -0,0 +1,37 @@
//
// 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_IMPL_ROWS_VIEW_HPP
#define BOOST_MYSQL_IMPL_ROWS_VIEW_HPP
#pragma once
#include <boost/mysql/rows_view.hpp>
#include <stdexcept>
#include <cassert>
boost::mysql::row_view boost::mysql::rows_view::operator[](
std::size_t i
) const noexcept
{
assert(i >= size());
return row_view(fields_ + num_columns_ * i, num_columns_);
}
boost::mysql::row_view boost::mysql::rows_view::at(
std::size_t i
) const
{
if (i >= size())
{
throw std::out_of_range("rows_view::at");
}
return (*this)[i];
}
#endif

View File

@@ -50,6 +50,7 @@ public:
row(row&&) = default;
row& operator=(const row&) = default;
row& operator=(row&&) = default;
row& operator=(row_view r) { fields_.assign(r.begin(), r.end()); return *this; }
~row() = default;
using iterator = detail::field_ptr;

View File

@@ -8,74 +8,51 @@
#ifndef BOOST_MYSQL_ROWS_HPP
#define BOOST_MYSQL_ROWS_HPP
#include <boost/mysql/detail/auxiliar/rows_iterator.hpp>
#include <boost/mysql/rows_view.hpp>
#include <boost/mysql/field_view.hpp>
#include <boost/mysql/row_view.hpp>
#include <boost/mysql/row.hpp>
namespace boost {
namespace mysql {
class rows
{
public:
rows() = default;
inline rows(const rows_view& view);
inline rows(const rows&);
rows(rows&&) = default;
inline rows& operator=(const rows&);
rows& operator=(rows&&) = default;
inline rows& operator=(const rows_view&);
~rows() = default;
using iterator = detail::rows_iterator<rows>;
using const_iterator = iterator;
using value_type = row;
using reference = row_view;
using const_reference = row_view;
using size_type = std::size_t;
using difference_type = std::ptrdiff_t;
iterator begin() const noexcept { return iterator(this, 0); }
iterator end() const noexcept { return iterator(this, size()); }
inline row_view at(std::size_t i) const;
inline row_view operator[](std::size_t i) const noexcept;
row_view front() const noexcept { return (*this)[0]; }
row_view back() const noexcept { return (*this)[size() - 1]; }
bool empty() const noexcept { return fields_.empty(); }
std::size_t size() const noexcept { return fields_.size() / num_columns_; }
operator rows_view() const noexcept { return rows_view(fields_.data(), fields_.size(), num_columns_); }
private:
std::vector<field_view> fields_;
std::vector<char> string_buffer_;
std::size_t num_columns_ {};
inline void rebase_strings(const char* old_buffer_base);
public:
rows() = default;
rows(std::size_t num_columns) noexcept : num_columns_(num_columns) {}
rows(const rows&) = delete; // TODO
rows(rows&&) = default;
const rows& operator=(const rows&) = delete; // TODO
rows& operator=(rows&&) = default;
class iterator;
using const_iterator = iterator;
// TODO: add other standard container members
iterator begin() const noexcept { return iterator(this, 0); }
iterator end() const noexcept { return iterator(this, size()); }
inline row_view at(std::size_t i) const;
row_view operator[](std::size_t i) const noexcept
{
return row_view(fields_.data() + num_columns_ * i, num_columns_);
}
row_view front() const noexcept { return (*this)[0]; }
row_view back() const noexcept { return (*this)[size() - 1]; }
bool empty() const noexcept { return fields_.empty(); }
std::size_t size() const noexcept { return fields_.size() / num_columns_; }
// TODO: hide these
std::vector<field_view>& fields() noexcept { return fields_; }
inline void copy_strings(std::size_t field_offset);
void clear() noexcept
{
fields_.clear();
string_buffer_.clear();
}
class iterator
{
const rows* obj_;
std::size_t row_num_;
public:
using value_type = row_view; // TODO: should this be row?
using reference = row_view;
using pointer = void const*;
using difference_type = std::ptrdiff_t;
using iterator_category = std::bidirectional_iterator_tag;
// TODO: this can be made random access
iterator(const rows* obj, std::size_t rownum) noexcept : obj_(obj), row_num_(rownum) {}
iterator& operator++() noexcept { ++row_num_; return *this; }
iterator operator++(int) noexcept { return iterator(obj_, row_num_ + 1); }
iterator& operator--() noexcept { --row_num_; return *this; }
iterator operator--(int) noexcept { return iterator(obj_, row_num_ - 1); }
reference operator*() const noexcept { return (*obj_)[row_num_]; }
bool operator==(const iterator& rhs) const noexcept { return obj_ == rhs.obj_&& row_num_ == rhs.row_num_; }
bool operator!=(const iterator& rhs) const noexcept { return !(*this == rhs); }
};
inline void copy_strings();
};

View File

@@ -8,6 +8,7 @@
#ifndef BOOST_MYSQL_ROWS_VIEW_HPP
#define BOOST_MYSQL_ROWS_VIEW_HPP
#include <boost/mysql/detail/auxiliar/rows_iterator.hpp>
#include <boost/mysql/field_view.hpp>
#include <boost/mysql/row.hpp>
#include <boost/mysql/row_view.hpp>
@@ -18,13 +19,10 @@ namespace mysql {
class rows_view
{
const field_view* fields_ {};
std::size_t num_values_ {};
std::size_t num_columns_ {};
public:
rows_view() = default;
class iterator;
using iterator = detail::rows_iterator<rows_view>;
using const_iterator = iterator;
using value_type = row;
using reference = row_view;
@@ -32,8 +30,8 @@ public:
using size_type = std::size_t;
using difference_type = std::ptrdiff_t;
inline iterator begin() const noexcept;
inline iterator end() const noexcept;
iterator begin() const noexcept { return iterator(this, 0); }
iterator end() const noexcept { return iterator(this, size()); }
inline row_view at(std::size_t i) const;
inline row_view operator[](std::size_t i) const noexcept;
row_view front() const noexcept { return (*this)[0]; }
@@ -49,6 +47,12 @@ public:
{
assert(num_values % num_columns == 0);
}
private:
const field_view* fields_ {};
std::size_t num_values_ {};
std::size_t num_columns_ {};
friend class rows;
};
@@ -56,7 +60,7 @@ public:
} // boost
#include <boost/mysql/impl/rows_view.hpp>
#include <boost/mysql/impl/rows_view.ipp>
#endif