From ed12d12f38ff06d10b385db88c7ea21eda698ac1 Mon Sep 17 00:00:00 2001 From: Ruben Perez Date: Thu, 18 Aug 2022 16:30:04 +0200 Subject: [PATCH] rows --- .../mysql/detail/auxiliar/rows_iterator.hpp | 68 ++++++++++++ include/boost/mysql/impl/rows.ipp | 103 +++++++++++++----- include/boost/mysql/impl/rows_view.hpp | 93 ---------------- include/boost/mysql/impl/rows_view.ipp | 37 +++++++ include/boost/mysql/row.hpp | 1 + include/boost/mysql/rows.hpp | 87 ++++++--------- include/boost/mysql/rows_view.hpp | 18 +-- 7 files changed, 222 insertions(+), 185 deletions(-) create mode 100644 include/boost/mysql/detail/auxiliar/rows_iterator.hpp delete mode 100644 include/boost/mysql/impl/rows_view.hpp create mode 100644 include/boost/mysql/impl/rows_view.ipp diff --git a/include/boost/mysql/detail/auxiliar/rows_iterator.hpp b/include/boost/mysql/detail/auxiliar/rows_iterator.hpp new file mode 100644 index 00000000..c6cca97a --- /dev/null +++ b/include/boost/mysql/detail/auxiliar/rows_iterator.hpp @@ -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 +#include +#include +#include + + +namespace boost { +namespace mysql { +namespace detail { + +template // 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 +rows_iterator operator+(std::ptrdiff_t n, rows_iterator it) noexcept +{ + return it + n; +} + +} +} +} + + + +#endif diff --git a/include/boost/mysql/impl/rows.ipp b/include/boost/mysql/impl/rows.ipp index e81a09cd..4b1d718d 100644 --- a/include/boost/mysql/impl/rows.ipp +++ b/include/boost/mysql/impl/rows.ipp @@ -8,33 +8,59 @@ #ifndef BOOST_MYSQL_IMPL_ROWS_IPP #define BOOST_MYSQL_IMPL_ROWS_IPP +#include "boost/mysql/rows_view.hpp" +#include #pragma once #include #include - -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())); diff --git a/include/boost/mysql/impl/rows_view.hpp b/include/boost/mysql/impl/rows_view.hpp deleted file mode 100644 index a67293d4..00000000 --- a/include/boost/mysql/impl/rows_view.hpp +++ /dev/null @@ -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 -#include -#include -#include -#include - - -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 diff --git a/include/boost/mysql/impl/rows_view.ipp b/include/boost/mysql/impl/rows_view.ipp new file mode 100644 index 00000000..26c5d2ca --- /dev/null +++ b/include/boost/mysql/impl/rows_view.ipp @@ -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 +#include +#include + + +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 diff --git a/include/boost/mysql/row.hpp b/include/boost/mysql/row.hpp index a1b64426..66af0160 100644 --- a/include/boost/mysql/row.hpp +++ b/include/boost/mysql/row.hpp @@ -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; diff --git a/include/boost/mysql/rows.hpp b/include/boost/mysql/rows.hpp index 9e5f4362..24df5e07 100644 --- a/include/boost/mysql/rows.hpp +++ b/include/boost/mysql/rows.hpp @@ -8,74 +8,51 @@ #ifndef BOOST_MYSQL_ROWS_HPP #define BOOST_MYSQL_ROWS_HPP +#include +#include #include #include +#include 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; + 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 fields_; std::vector 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& 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(); }; diff --git a/include/boost/mysql/rows_view.hpp b/include/boost/mysql/rows_view.hpp index d4fca983..09500c4c 100644 --- a/include/boost/mysql/rows_view.hpp +++ b/include/boost/mysql/rows_view.hpp @@ -8,6 +8,7 @@ #ifndef BOOST_MYSQL_ROWS_VIEW_HPP #define BOOST_MYSQL_ROWS_VIEW_HPP +#include #include #include #include @@ -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; 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 +#include #endif