mirror of
https://github.com/boostorg/mysql.git
synced 2026-02-17 13:52:18 +00:00
rows
This commit is contained in:
68
include/boost/mysql/detail/auxiliar/rows_iterator.hpp
Normal file
68
include/boost/mysql/detail/auxiliar/rows_iterator.hpp
Normal 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
|
||||
@@ -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()));
|
||||
|
||||
@@ -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
|
||||
37
include/boost/mysql/impl/rows_view.ipp
Normal file
37
include/boost/mysql/impl/rows_view.ipp
Normal 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
|
||||
@@ -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;
|
||||
|
||||
@@ -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();
|
||||
};
|
||||
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user