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

field_view now handles field references

This commit is contained in:
Ruben Perez
2022-09-29 18:32:58 +02:00
parent afeed27a8c
commit 5d6d7e3bfd
6 changed files with 616 additions and 290 deletions

View File

@@ -0,0 +1,86 @@
//
// 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_IMPL_HPP
#define BOOST_MYSQL_DETAIL_AUXILIAR_FIELD_IMPL_HPP
#include <boost/mysql/field_kind.hpp>
#include <boost/mysql/datetime_types.hpp>
#include <boost/mysql/bad_field_access.hpp>
#include <boost/variant2/variant.hpp>
#include <boost/mp11.hpp>
#include <string>
#include <type_traits>
namespace boost {
namespace mysql {
namespace detail {
// Breaks a circular dependency between field_view and field
struct field_impl
{
using null_t = boost::variant2::monostate;
using variant_type = boost::variant2::variant<
null_t, // Any of the below when the value is NULL
std::int64_t, // signed TINYINT, SMALLINT, MEDIUMINT, INT, BIGINT
std::uint64_t, // unsigned TINYINT, SMALLINT, MEDIUMINT, INT, BIGINT, YEAR, BIT
std::string, // CHAR, VARCHAR, BINARY, VARBINARY, TEXT (all sizes), BLOB (all sizes), ENUM, SET, DECIMAL, GEOMTRY
float, // FLOAT
double, // DOUBLE
date, // DATE
datetime, // DATETIME, TIMESTAMP
time // TIME
>;
variant_type data;
field_impl() = default;
template <typename Arg>
field_impl(Arg&& arg) noexcept(std::is_nothrow_constructible<variant_type, Arg>::value) : data (std::forward<Arg>(arg)) {}
field_kind kind() const noexcept { return static_cast<field_kind>(data.index()); }
template <typename T>
const T& as() const
{
const T* res = boost::variant2::get_if<T>(&data);
if (!res)
throw bad_field_access();
return *res;
}
template <typename T>
T& as()
{
T* res = boost::variant2::get_if<T>(&data);
if (!res)
throw bad_field_access();
return *res;
}
template <typename T>
const T& get() const noexcept
{
constexpr auto I = mp11::mp_find<variant_type, T>::value;
return boost::variant2::unsafe_get<I>(data);
}
template <typename T>
T& get() noexcept
{
constexpr auto I = mp11::mp_find<variant_type, T>::value;
return boost::variant2::unsafe_get<I>(data);
}
};
} // detail
} // mysql
} // boost
#endif

View File

@@ -29,10 +29,6 @@ public:
offset_(offset), size_(size) {}
constexpr std::size_t offset() const noexcept { return offset_; }
constexpr std::size_t size() const noexcept { return size_; }
constexpr boost::string_view to_string_view(const char* base) const noexcept
{
return boost::string_view(base + offset_, size_);
}
constexpr bool operator==(string_view_offset rhs) const noexcept
{
return offset_ == rhs.offset_ && size_ == rhs.size_;

View File

@@ -8,11 +8,12 @@
#ifndef BOOST_MYSQL_FIELD_HPP
#define BOOST_MYSQL_FIELD_HPP
#include <boost/utility/string_view.hpp>
#include <boost/variant2/variant.hpp>
#include <boost/mysql/field_view.hpp>
#include <boost/mysql/datetime_types.hpp>
#include <boost/mysql/field_kind.hpp>
#include <boost/mysql/detail/auxiliar/field_impl.hpp>
#include <boost/utility/string_view.hpp>
#include <boost/variant2/variant.hpp>
#include <cstddef>
#include <ostream>
#include <string>
@@ -32,7 +33,7 @@ public:
field& operator=(field&&) = default;
~field() = default;
explicit field(std::nullptr_t) noexcept : repr_(null_t()) {}
explicit field(std::nullptr_t) noexcept {}
field(signed char v) noexcept : repr_(std::int64_t(v)) {}
field(short v) noexcept : repr_(std::int64_t(v)) {}
field(int v) noexcept : repr_(std::int64_t(v)) {}
@@ -51,26 +52,26 @@ public:
field(const time& v) noexcept : repr_(v) {}
field(const field_view& v) { from_view(v); }
field& operator=(std::nullptr_t) noexcept { repr_.emplace<null_t>(null_t()); return *this; }
field& operator=(signed char v) noexcept { repr_.emplace<std::int64_t>(v); return *this; }
field& operator=(short v) noexcept { repr_.emplace<std::int64_t>(v); return *this; }
field& operator=(int v) noexcept { repr_.emplace<std::int64_t>(v); return *this; }
field& operator=(long v) noexcept { repr_.emplace<std::int64_t>(v); return *this; }
field& operator=(long long v) noexcept { repr_.emplace<std::int64_t>(v); return *this; }
field& operator=(unsigned char v) noexcept { repr_.emplace<std::uint64_t>(v); return *this; }
field& operator=(unsigned short v) noexcept { repr_.emplace<std::uint64_t>(v); return *this; }
field& operator=(unsigned int v) noexcept { repr_.emplace<std::uint64_t>(v); return *this; }
field& operator=(unsigned long v) noexcept { repr_.emplace<std::uint64_t>(v); return *this; }
field& operator=(unsigned long long v) noexcept { repr_.emplace<std::uint64_t>(v); return *this; }
field& operator=(std::string v) { repr_.emplace<std::string>(std::move(v)); return *this; }
field& operator=(float v) noexcept { repr_.emplace<float>(v); return *this; }
field& operator=(double v) noexcept { repr_.emplace<double>(v); return *this; }
field& operator=(const date& v) noexcept { repr_.emplace<date>(v); return *this; }
field& operator=(const datetime& v) noexcept { repr_.emplace<datetime>(v); return *this; }
field& operator=(const time& v) noexcept { repr_.emplace<time>(v); return *this; }
field& operator=(std::nullptr_t) noexcept { repr_.data.emplace<detail::field_impl::null_t>(); return *this; }
field& operator=(signed char v) noexcept { repr_.data.emplace<std::int64_t>(v); return *this; }
field& operator=(short v) noexcept { repr_.data.emplace<std::int64_t>(v); return *this; }
field& operator=(int v) noexcept { repr_.data.emplace<std::int64_t>(v); return *this; }
field& operator=(long v) noexcept { repr_.data.emplace<std::int64_t>(v); return *this; }
field& operator=(long long v) noexcept { repr_.data.emplace<std::int64_t>(v); return *this; }
field& operator=(unsigned char v) noexcept { repr_.data.emplace<std::uint64_t>(v); return *this; }
field& operator=(unsigned short v) noexcept { repr_.data.emplace<std::uint64_t>(v); return *this; }
field& operator=(unsigned int v) noexcept { repr_.data.emplace<std::uint64_t>(v); return *this; }
field& operator=(unsigned long v) noexcept { repr_.data.emplace<std::uint64_t>(v); return *this; }
field& operator=(unsigned long long v) noexcept { repr_.data.emplace<std::uint64_t>(v); return *this; }
field& operator=(std::string v) { repr_.data.emplace<std::string>(std::move(v)); return *this; }
field& operator=(float v) noexcept { repr_.data.emplace<float>(v); return *this; }
field& operator=(double v) noexcept { repr_.data.emplace<double>(v); return *this; }
field& operator=(const date& v) noexcept { repr_.data.emplace<date>(v); return *this; }
field& operator=(const datetime& v) noexcept { repr_.data.emplace<datetime>(v); return *this; }
field& operator=(const time& v) noexcept { repr_.data.emplace<time>(v); return *this; }
field& operator=(const field_view& v) { from_view(v); return *this; }
field_kind kind() const noexcept { return static_cast<field_kind>(repr_.index()); }
field_kind kind() const noexcept { return repr_.kind(); }
bool is_null() const noexcept { return kind() == field_kind::null; }
bool is_int64() const noexcept { return kind() == field_kind::int64; }
@@ -82,41 +83,41 @@ public:
bool is_datetime() const noexcept { return kind() == field_kind::datetime; }
bool is_time() const noexcept { return kind() == field_kind::time; }
const std::int64_t& as_int64() const { return internal_as<std::int64_t>(); }
const std::uint64_t& as_uint64() const { return internal_as<std::uint64_t>(); }
const std::string& as_string() const { return internal_as<std::string>(); }
const float& as_float() const { return internal_as<float>(); }
const double& as_double() const { return internal_as<double>(); }
const date& as_date() const { return internal_as<date>(); }
const datetime& as_datetime() const { return internal_as<datetime>(); }
const time& as_time() const { return internal_as<time>(); }
const std::int64_t& as_int64() const { return repr_.as<std::int64_t>(); }
const std::uint64_t& as_uint64() const { return repr_.as<std::uint64_t>(); }
const std::string& as_string() const { return repr_.as<std::string>(); }
const float& as_float() const { return repr_.as<float>(); }
const double& as_double() const { return repr_.as<double>(); }
const date& as_date() const { return repr_.as<date>(); }
const datetime& as_datetime() const { return repr_.as<datetime>(); }
const time& as_time() const { return repr_.as<time>(); }
std::int64_t& as_int64() { return internal_as<std::int64_t>(); }
std::uint64_t& as_uint64() { return internal_as<std::uint64_t>(); }
std::string& as_string() { return internal_as<std::string>(); }
float& as_float() { return internal_as<float>(); }
double& as_double() { return internal_as<double>(); }
date& as_date() { return internal_as<date>(); }
datetime& as_datetime() { return internal_as<datetime>(); }
time& as_time() { return internal_as<time>(); }
std::int64_t& as_int64() { return repr_.as<std::int64_t>(); }
std::uint64_t& as_uint64() { return repr_.as<std::uint64_t>(); }
std::string& as_string() { return repr_.as<std::string>(); }
float& as_float() { return repr_.as<float>(); }
double& as_double() { return repr_.as<double>(); }
date& as_date() { return repr_.as<date>(); }
datetime& as_datetime() { return repr_.as<datetime>(); }
time& as_time() { return repr_.as<time>(); }
const std::int64_t& get_int64() const noexcept { return internal_get<std::int64_t>(); }
const std::uint64_t& get_uint64() const noexcept { return internal_get<std::uint64_t>(); }
const std::string& get_string() const noexcept { return internal_get<std::string>(); }
const float& get_float() const noexcept { return internal_get<float>(); }
const double& get_double() const noexcept { return internal_get<double>(); }
const date& get_date() const noexcept { return internal_get<date>(); }
const datetime& get_datetime() const noexcept { return internal_get<datetime>(); }
const time& get_time() const noexcept { return internal_get<time>(); }
const std::int64_t& get_int64() const noexcept { return repr_.get<std::int64_t>(); }
const std::uint64_t& get_uint64() const noexcept { return repr_.get<std::uint64_t>(); }
const std::string& get_string() const noexcept { return repr_.get<std::string>(); }
const float& get_float() const noexcept { return repr_.get<float>(); }
const double& get_double() const noexcept { return repr_.get<double>(); }
const date& get_date() const noexcept { return repr_.get<date>(); }
const datetime& get_datetime() const noexcept { return repr_.get<datetime>(); }
const time& get_time() const noexcept { return repr_.get<time>(); }
std::int64_t& get_int64() noexcept { return internal_get<std::int64_t>(); }
std::uint64_t& get_uint64() noexcept { return internal_get<std::uint64_t>(); }
std::string& get_string() noexcept { return internal_get<std::string>(); }
float& get_float() noexcept { return internal_get<float>(); }
double& get_double() noexcept { return internal_get<double>(); }
date& get_date() noexcept { return internal_get<date>(); }
datetime& get_datetime() noexcept { return internal_get<datetime>(); }
time& get_time() noexcept { return internal_get<time>(); }
std::int64_t& get_int64() noexcept { return repr_.get<std::int64_t>(); }
std::uint64_t& get_uint64() noexcept { return repr_.get<std::uint64_t>(); }
std::string& get_string() noexcept { return repr_.get<std::string>(); }
float& get_float() noexcept { return repr_.get<float>(); }
double& get_double() noexcept { return repr_.get<double>(); }
date& get_date() noexcept { return repr_.get<date>(); }
datetime& get_datetime() noexcept { return repr_.get<datetime>(); }
time& get_time() noexcept { return repr_.get<time>(); }
void emplace_null() noexcept { *this = nullptr; }
void emplace_int64(std::int64_t v) noexcept { *this = v; }
@@ -128,38 +129,12 @@ public:
void emplace_datetime(const datetime& v) noexcept { *this = v; }
void emplace_time(const time& v) noexcept { *this = v; }
inline operator field_view() const noexcept;
inline operator field_view() const noexcept { return field_view(&repr_); }
bool operator==(const field& rhs) const noexcept { return field_view(*this) == field_view(rhs); }
bool operator!=(const field& rhs) const noexcept { return !(*this == rhs); }
private:
using null_t = boost::variant2::monostate;
using variant_type = boost::variant2::variant<
null_t, // Any of the below when the value is NULL
std::int64_t, // signed TINYINT, SMALLINT, MEDIUMINT, INT, BIGINT
std::uint64_t, // unsigned TINYINT, SMALLINT, MEDIUMINT, INT, BIGINT, YEAR, BIT
std::string, // CHAR, VARCHAR, BINARY, VARBINARY, TEXT (all sizes), BLOB (all sizes), ENUM, SET, DECIMAL, GEOMTRY
float, // FLOAT
double, // DOUBLE
date, // DATE
datetime, // DATETIME, TIMESTAMP
time // TIME
>;
variant_type repr_;
template <typename T>
const T& internal_as() const;
template <typename T>
T& internal_as();
template <typename T>
const T& internal_get() const noexcept;
template <typename T>
T& internal_get() noexcept;
detail::field_impl repr_;
inline void from_view(const field_view& v);
};

View File

@@ -8,11 +8,12 @@
#ifndef BOOST_MYSQL_FIELD_VIEW_HPP
#define BOOST_MYSQL_FIELD_VIEW_HPP
#include <boost/utility/string_view.hpp>
#include <boost/variant2/variant.hpp>
#include <boost/mysql/detail/auxiliar/string_view_offset.hpp>
#include <boost/mysql/detail/auxiliar/field_impl.hpp>
#include <boost/mysql/datetime_types.hpp>
#include <boost/mysql/field_kind.hpp>
#include <boost/utility/string_view.hpp>
#include <cstddef>
#include <cstdint>
#include <iosfwd>
#include <array>
@@ -48,29 +49,37 @@ public:
* Caution: `value(NULL)` will __NOT__ match this overload. It will try to construct
* a `boost::string_view` from a NULL C string, causing undefined behavior.
*/
BOOST_CXX14_CONSTEXPR explicit field_view(std::nullptr_t) noexcept : repr_(null_t()) {}
BOOST_CXX14_CONSTEXPR explicit field_view(std::nullptr_t) noexcept {}
BOOST_CXX14_CONSTEXPR field_view(signed char v) noexcept : repr_(std::int64_t(v)) {}
BOOST_CXX14_CONSTEXPR field_view(short v) noexcept : repr_(std::int64_t(v)) {}
BOOST_CXX14_CONSTEXPR field_view(int v) noexcept : repr_(std::int64_t(v)) {}
BOOST_CXX14_CONSTEXPR field_view(long v) noexcept : repr_(std::int64_t(v)) {}
BOOST_CXX14_CONSTEXPR field_view(long long v) noexcept : repr_(std::int64_t(v)) {}
BOOST_CXX14_CONSTEXPR inline field_view(signed char v) noexcept;
BOOST_CXX14_CONSTEXPR inline field_view(short v) noexcept;
BOOST_CXX14_CONSTEXPR inline field_view(int v) noexcept;
BOOST_CXX14_CONSTEXPR inline field_view(long v) noexcept;
BOOST_CXX14_CONSTEXPR inline field_view(long long v) noexcept;
BOOST_CXX14_CONSTEXPR field_view(unsigned char v) noexcept : repr_(std::uint64_t(v)) {}
BOOST_CXX14_CONSTEXPR field_view(unsigned short v) noexcept : repr_(std::uint64_t(v)) {}
BOOST_CXX14_CONSTEXPR field_view(unsigned int v) noexcept : repr_(std::uint64_t(v)) {}
BOOST_CXX14_CONSTEXPR field_view(unsigned long v) noexcept : repr_(std::uint64_t(v)) {}
BOOST_CXX14_CONSTEXPR field_view(unsigned long long v) noexcept : repr_(std::uint64_t(v)) {}
BOOST_CXX14_CONSTEXPR inline field_view(unsigned char v) noexcept;
BOOST_CXX14_CONSTEXPR inline field_view(unsigned short v) noexcept;
BOOST_CXX14_CONSTEXPR inline field_view(unsigned int v) noexcept;
BOOST_CXX14_CONSTEXPR inline field_view(unsigned long v) noexcept;
BOOST_CXX14_CONSTEXPR inline field_view(unsigned long long v) noexcept;
BOOST_CXX14_CONSTEXPR field_view(boost::string_view v) noexcept : repr_(v) {}
BOOST_CXX14_CONSTEXPR field_view(float v) noexcept : repr_(v) {}
BOOST_CXX14_CONSTEXPR field_view(double v) noexcept : repr_(v) {}
BOOST_CXX14_CONSTEXPR field_view(const date& v) noexcept : repr_(v) {}
BOOST_CXX14_CONSTEXPR field_view(const datetime& v) noexcept : repr_(v) {}
BOOST_CXX14_CONSTEXPR field_view(const time& v) noexcept : repr_(v) {}
BOOST_CXX14_CONSTEXPR inline field_view(boost::string_view v) noexcept;
BOOST_CXX14_CONSTEXPR inline field_view(float v) noexcept;
BOOST_CXX14_CONSTEXPR inline field_view(double v) noexcept;
BOOST_CXX14_CONSTEXPR inline field_view(const date& v) noexcept;
BOOST_CXX14_CONSTEXPR inline field_view(const datetime& v) noexcept;
BOOST_CXX14_CONSTEXPR inline field_view(const time& v) noexcept;
// TODO: hide this
BOOST_CXX14_CONSTEXPR explicit field_view(detail::string_view_offset v) noexcept : repr_(v) {}
BOOST_CXX14_CONSTEXPR explicit field_view(detail::string_view_offset v) noexcept : ikind_(internal_kind::sv_offset)
{
repr_.sv_offset = { v.offset(), v.size() };
}
BOOST_CXX14_CONSTEXPR explicit field_view(const detail::field_impl* v) noexcept : ikind_(internal_kind::field_ptr)
{
repr_.field_ptr = v;
}
BOOST_CXX14_CONSTEXPR inline field_kind kind() const noexcept;
@@ -84,23 +93,23 @@ public:
BOOST_CXX14_CONSTEXPR bool is_datetime() const noexcept { return kind() == field_kind::datetime; }
BOOST_CXX14_CONSTEXPR bool is_time() const noexcept { return kind() == field_kind::time; }
BOOST_CXX14_CONSTEXPR std::int64_t as_int64() const { return internal_as<std::int64_t>(); }
BOOST_CXX14_CONSTEXPR std::uint64_t as_uint64() const { return internal_as<std::uint64_t>(); }
BOOST_CXX14_CONSTEXPR boost::string_view as_string() const { return internal_as<boost::string_view>(); }
BOOST_CXX14_CONSTEXPR float as_float() const { return internal_as<float>(); }
BOOST_CXX14_CONSTEXPR double as_double() const { return internal_as<double>(); }
BOOST_CXX14_CONSTEXPR date as_date() const { return internal_as<date>(); }
BOOST_CXX14_CONSTEXPR datetime as_datetime() const { return internal_as<datetime>(); }
BOOST_CXX14_CONSTEXPR time as_time() const { return internal_as<time>(); }
BOOST_CXX14_CONSTEXPR inline std::int64_t as_int64() const;
BOOST_CXX14_CONSTEXPR inline std::uint64_t as_uint64() const;
BOOST_CXX14_CONSTEXPR inline boost::string_view as_string() const;
BOOST_CXX14_CONSTEXPR inline float as_float() const;
BOOST_CXX14_CONSTEXPR inline double as_double() const;
BOOST_CXX14_CONSTEXPR inline date as_date() const;
BOOST_CXX14_CONSTEXPR inline datetime as_datetime() const;
BOOST_CXX14_CONSTEXPR inline time as_time() const;
BOOST_CXX14_CONSTEXPR std::int64_t get_int64() const noexcept { return internal_get<std::int64_t>(); }
BOOST_CXX14_CONSTEXPR std::uint64_t get_uint64() const noexcept { return internal_get<std::uint64_t>(); }
BOOST_CXX14_CONSTEXPR boost::string_view get_string() const noexcept { return internal_get<boost::string_view>(); }
BOOST_CXX14_CONSTEXPR float get_float() const noexcept { return internal_get<float>(); }
BOOST_CXX14_CONSTEXPR double get_double() const noexcept { return internal_get<double>(); }
BOOST_CXX14_CONSTEXPR date get_date() const noexcept { return internal_get<date>(); }
BOOST_CXX14_CONSTEXPR datetime get_datetime() const noexcept { return internal_get<datetime>(); }
BOOST_CXX14_CONSTEXPR time get_time() const noexcept { return internal_get<time>(); }
BOOST_CXX14_CONSTEXPR inline std::int64_t get_int64() const noexcept;
BOOST_CXX14_CONSTEXPR inline std::uint64_t get_uint64() const noexcept;
BOOST_CXX14_CONSTEXPR inline boost::string_view get_string() const noexcept;
BOOST_CXX14_CONSTEXPR inline float get_float() const noexcept;
BOOST_CXX14_CONSTEXPR inline double get_double() const noexcept;
BOOST_CXX14_CONSTEXPR inline date get_date() const noexcept;
BOOST_CXX14_CONSTEXPR inline datetime get_datetime() const noexcept;
BOOST_CXX14_CONSTEXPR inline time get_time() const noexcept;
/// Tests for equality (type and value); see [link mysql.values.relational this section] for more info.
BOOST_CXX14_CONSTEXPR bool operator==(const field_view& rhs) const noexcept;
@@ -111,39 +120,65 @@ public:
// TODO: hide this
void offset_to_string_view(const std::uint8_t* buffer_first) noexcept
{
auto* sv_index = boost::variant2::get_if<detail::string_view_offset>(&repr_);
if (sv_index)
if (ikind_ == internal_kind::sv_offset)
{
repr_ = sv_index->to_string_view(reinterpret_cast<const char*>(buffer_first));
ikind_ = internal_kind::string;
repr_.string = {
reinterpret_cast<const char*>(buffer_first) + repr_.sv_offset.offset,
repr_.sv_offset.size
};
}
}
private:
struct print_visitor;
enum class internal_kind
{
null = 0,
int64,
uint64,
string,
float_,
double_,
date,
datetime,
time,
sv_offset,
field_ptr
};
union repr_t
{
std::int64_t int64;
std::uint64_t uint64;
struct
{
const char* ptr;
std::size_t size;
} string;
float float_;
double double_;
date::rep date_;
datetime::rep datetime_;
time::rep time_;
struct
{
std::size_t offset;
std::size_t size;
} sv_offset;
const detail::field_impl* field_ptr;
boost::string_view get_string() const noexcept { return boost::string_view(string.ptr, string.size); }
date get_date() const noexcept { return date(date::duration(date_));}
datetime get_datetime() const noexcept { return datetime(datetime::duration(datetime_)); }
time get_time() const noexcept { return time(time_); }
};
internal_kind ikind_ { internal_kind::null };
repr_t repr_;
using null_t = boost::variant2::monostate;
using variant_type = boost::variant2::variant<
null_t, // Any of the below when the value is NULL
std::int64_t, // signed TINYINT, SMALLINT, MEDIUMINT, INT, BIGINT
std::uint64_t, // unsigned TINYINT, SMALLINT, MEDIUMINT, INT, BIGINT, YEAR, BIT
boost::string_view,// CHAR, VARCHAR, BINARY, VARBINARY, TEXT (all sizes), BLOB (all sizes), ENUM, SET, DECIMAL, GEOMTRY
float, // FLOAT
double, // DOUBLE
date, // DATE
datetime, // DATETIME, TIMESTAMP
time, // TIME
detail::string_view_offset // Used during parsing, not exposed to the user
>;
variant_type repr_;
template <typename T>
const T& internal_as() const;
template <typename T>
const T& internal_get() const noexcept;
friend std::ostream& operator<<(std::ostream& os, const field_view& v);
bool is_field_ptr() const noexcept { return ikind_ == internal_kind::field_ptr; }
inline void check_kind(internal_kind expected) const;
};
/**

View File

@@ -8,7 +8,6 @@
#ifndef BOOST_MYSQL_IMPL_FIELD_HPP
#define BOOST_MYSQL_IMPL_FIELD_HPP
#include "boost/mysql/field_view.hpp"
#pragma once
#include <boost/mysql/field.hpp>
@@ -23,70 +22,18 @@ void boost::mysql::field::from_view(
{
switch (fv.kind())
{
case field_kind::null: repr_.emplace<null_t>(null_t()); break;
case field_kind::int64: repr_.emplace<std::int64_t>(fv.get_int64()); break;
case field_kind::uint64: repr_.emplace<std::uint64_t>(fv.get_uint64()); break;
case field_kind::string: repr_.emplace<std::string>(fv.get_string()); break;
case field_kind::float_: repr_.emplace<float>(fv.get_float()); break;
case field_kind::double_: repr_.emplace<double>(fv.get_double()); break;
case field_kind::date: repr_.emplace<date>(fv.get_date()); break;
case field_kind::datetime: repr_.emplace<datetime>(fv.get_datetime()); break;
case field_kind::time: repr_.emplace<time>(fv.get_time()); break;
case field_kind::null: repr_.data.emplace<detail::field_impl::null_t>(); break;
case field_kind::int64: repr_.data.emplace<std::int64_t>(fv.get_int64()); break;
case field_kind::uint64: repr_.data.emplace<std::uint64_t>(fv.get_uint64()); break;
case field_kind::string: repr_.data.emplace<std::string>(fv.get_string()); break;
case field_kind::float_: repr_.data.emplace<float>(fv.get_float()); break;
case field_kind::double_: repr_.data.emplace<double>(fv.get_double()); break;
case field_kind::date: repr_.data.emplace<date>(fv.get_date()); break;
case field_kind::datetime: repr_.data.emplace<datetime>(fv.get_datetime()); break;
case field_kind::time: repr_.data.emplace<time>(fv.get_time()); break;
}
}
inline boost::mysql::field::operator field_view() const noexcept
{
switch (kind())
{
case field_kind::null: return field_view();
case field_kind::int64: return field_view(get_int64());
case field_kind::uint64: return field_view(get_uint64());
case field_kind::string: return field_view(get_string());
case field_kind::float_: return field_view(get_float());
case field_kind::double_: return field_view(get_double());
case field_kind::date: return field_view(get_date());
case field_kind::datetime: return field_view(get_datetime());
case field_kind::time: return field_view(get_time());
}
}
template <typename T>
const T& boost::mysql::field::internal_as() const
{
const T* res = boost::variant2::get_if<T>(&repr_);
if (!res)
throw bad_field_access();
return *res;
}
template <typename T>
T& boost::mysql::field::internal_as()
{
T* res = boost::variant2::get_if<T>(&repr_);
if (!res)
throw bad_field_access();
return *res;
}
template <typename T>
const T& boost::mysql::field::internal_get() const noexcept
{
// TODO: this can be done better
const T* res = boost::variant2::get_if<T>(&repr_);
assert(res);
return *res;
}
template <typename T>
T& boost::mysql::field::internal_get() noexcept
{
// TODO: this can be done better
T* res = boost::variant2::get_if<T>(&repr_);
assert(res);
return *res;
}
inline std::ostream& boost::mysql::operator<<(
std::ostream& os,
const field& value

View File

@@ -12,110 +12,386 @@
#include <boost/mysql/field_view.hpp>
#include <boost/mysql/detail/protocol/date.hpp>
#include <boost/mysql/detail/auxiliar/string_view_offset.hpp>
#include <boost/mysql/bad_field_access.hpp>
#include <ostream>
#include <limits>
struct boost::mysql::field_view::print_visitor
namespace boost {
namespace mysql {
namespace detail {
inline std::ostream& print_date(std::ostream& os, const date& value)
{
std::ostream& os;
assert(value >= min_date && value <= max_date);
auto ymd = detail::days_to_ymd(value.time_since_epoch().count());
char buffer [32] {};
snprintf(buffer, sizeof(buffer), "%04d-%02u-%02u", ymd.years, ymd.month, ymd.day);
os << buffer;
return os;
}
print_visitor(std::ostream& os): os(os) {};
inline std::ostream& print_time(std::ostream& os, const time& value)
{
using namespace std::chrono;
assert(value >= min_time && value <= max_time);
char buffer [64] {};
const char* sign = value < microseconds(0) ? "-" : "";
auto num_micros = value % seconds(1);
auto num_secs = duration_cast<seconds>(value % minutes(1) - num_micros);
auto num_mins = duration_cast<minutes>(value % hours(1) - num_secs);
auto num_hours = duration_cast<hours>(value - num_mins);
template <class T>
void operator()(const T& value) const { os << value; }
snprintf(buffer, sizeof(buffer), "%s%02d:%02u:%02u.%06u",
sign,
static_cast<int>(std::abs(num_hours.count())),
static_cast<unsigned>(std::abs(num_mins.count())),
static_cast<unsigned>(std::abs(num_secs.count())),
static_cast<unsigned>(std::abs(num_micros.count()))
);
void operator()(const date& value) const
{
assert(value >= min_date && value <= max_date);
auto ymd = detail::days_to_ymd(value.time_since_epoch().count());
char buffer [32] {};
snprintf(buffer, sizeof(buffer), "%04d-%02u-%02u", ymd.years, ymd.month, ymd.day);
os << buffer;
}
void operator()(const datetime& value) const
{
using namespace std::chrono;
date date_part = time_point_cast<days>(value);
if (date_part > value)
date_part -= days(1);
auto tod = value - date_part;
(*this)(date_part); // date part
os << ' '; // separator
(*this)(duration_cast<time>(tod)); // time of day part
}
void operator()(const time& value) const
{
using namespace std::chrono;
assert(value >= min_time && value <= max_time);
char buffer [64] {};
const char* sign = value < microseconds(0) ? "-" : "";
auto num_micros = value % seconds(1);
auto num_secs = duration_cast<seconds>(value % minutes(1) - num_micros);
auto num_mins = duration_cast<minutes>(value % hours(1) - num_secs);
auto num_hours = duration_cast<hours>(value - num_mins);
os << buffer;
return os;
}
snprintf(buffer, sizeof(buffer), "%s%02d:%02u:%02u.%06u",
sign,
static_cast<int>(std::abs(num_hours.count())),
static_cast<unsigned>(std::abs(num_mins.count())),
static_cast<unsigned>(std::abs(num_secs.count())),
static_cast<unsigned>(std::abs(num_micros.count()))
);
inline std::ostream& print_datetime(std::ostream& os, const datetime& value)
{
using namespace std::chrono;
date date_part = time_point_cast<days>(value);
if (date_part > value)
date_part -= days(1);
auto tod = value - date_part;
print_date(os, date_part); // date part
os << ' '; // separator
print_time(os, duration_cast<time>(tod)); // time of day part
return os;
}
os << buffer;
}
void operator()(null_t) const { os << "<NULL>"; }
void operator()(detail::string_view_offset) const { os << "<invalid>"; }
};
} // detail
} // mysql
} // boost
BOOST_CXX14_CONSTEXPR boost::mysql::field_view::field_view(
signed char v
) noexcept :
ikind_(internal_kind::int64)
{
repr_.int64 = v;
}
BOOST_CXX14_CONSTEXPR boost::mysql::field_view::field_view(
short v
) noexcept :
ikind_(internal_kind::int64)
{
repr_.int64 = v;
}
BOOST_CXX14_CONSTEXPR boost::mysql::field_view::field_view(
int v
) noexcept :
ikind_(internal_kind::int64)
{
repr_.int64 = v;
}
BOOST_CXX14_CONSTEXPR boost::mysql::field_view::field_view(
long v
) noexcept :
ikind_(internal_kind::int64)
{
repr_.int64 = v;
}
BOOST_CXX14_CONSTEXPR boost::mysql::field_view::field_view(
long long v
) noexcept :
ikind_(internal_kind::int64)
{
repr_.int64 = v;
}
BOOST_CXX14_CONSTEXPR boost::mysql::field_view::field_view(
unsigned char v
) noexcept :
ikind_(internal_kind::uint64)
{
repr_.uint64 = v;
}
BOOST_CXX14_CONSTEXPR boost::mysql::field_view::field_view(
unsigned short v
) noexcept :
ikind_(internal_kind::uint64)
{
repr_.uint64 = v;
}
BOOST_CXX14_CONSTEXPR boost::mysql::field_view::field_view(
unsigned int v
) noexcept :
ikind_(internal_kind::uint64)
{
repr_.uint64 = v;
}
BOOST_CXX14_CONSTEXPR boost::mysql::field_view::field_view(
unsigned long v
) noexcept :
ikind_(internal_kind::uint64)
{
repr_.uint64 = v;
}
BOOST_CXX14_CONSTEXPR boost::mysql::field_view::field_view(
unsigned long long v
) noexcept :
ikind_(internal_kind::uint64)
{
repr_.uint64 = v;
}
BOOST_CXX14_CONSTEXPR boost::mysql::field_view::field_view(
boost::string_view v
) noexcept :
ikind_(internal_kind::string)
{
repr_.string = { v.data(), v.size()};
}
BOOST_CXX14_CONSTEXPR boost::mysql::field_view::field_view(
float v
) noexcept :
ikind_(internal_kind::float_)
{
repr_.float_ = v;
}
BOOST_CXX14_CONSTEXPR boost::mysql::field_view::field_view(
double v
) noexcept :
ikind_(internal_kind::double_)
{
repr_.double_ = v;
}
BOOST_CXX14_CONSTEXPR boost::mysql::field_view::field_view(
const date& v
) noexcept :
ikind_(internal_kind::date)
{
repr_.date_ = v.time_since_epoch().count();
}
BOOST_CXX14_CONSTEXPR boost::mysql::field_view::field_view(
const datetime& v
) noexcept :
ikind_(internal_kind::datetime)
{
repr_.datetime_ = v.time_since_epoch().count();
}
BOOST_CXX14_CONSTEXPR boost::mysql::field_view::field_view(
const time& v
) noexcept :
ikind_(internal_kind::time)
{
repr_.time_ = v.count();
}
BOOST_CXX14_CONSTEXPR inline boost::mysql::field_kind boost::mysql::field_view::kind() const noexcept
{
// Indices below time are user-facing; indices above that are used
// by the library during parsing, but never reach the user
assert(repr_.index() <= static_cast<int>(field_kind::time));
return static_cast<field_kind>(repr_.index());
switch (ikind_)
{
case internal_kind::null: return field_kind::null;
case internal_kind::int64: return field_kind::int64;
case internal_kind::uint64: return field_kind::uint64;
case internal_kind::string: return field_kind::string;
case internal_kind::float_: return field_kind::float_;
case internal_kind::double_: return field_kind::double_;
case internal_kind::date: return field_kind::date;
case internal_kind::datetime: return field_kind::datetime;
case internal_kind::time: return field_kind::time;
case internal_kind::field_ptr: return repr_.field_ptr->kind();
// sv_offset values must be converted via offset_to_string_view before calling any other fn
default: assert(false); return field_kind::null;
}
}
template <typename T>
const T& boost::mysql::field_view::internal_as() const
BOOST_CXX14_CONSTEXPR std::int64_t
boost::mysql::field_view::as_int64() const
{
const T* res = boost::variant2::get_if<T>(&repr_);
if (!res)
if (is_field_ptr())
return repr_.field_ptr->as<std::int64_t>();
check_kind(internal_kind::int64);
return repr_.int64;
}
BOOST_CXX14_CONSTEXPR std::uint64_t
boost::mysql::field_view::as_uint64() const
{
if (is_field_ptr())
return repr_.field_ptr->as<std::uint64_t>();
check_kind(internal_kind::uint64);
return repr_.uint64;
}
BOOST_CXX14_CONSTEXPR boost::string_view
boost::mysql::field_view::as_string() const
{
if (is_field_ptr())
return repr_.field_ptr->as<std::string>();
check_kind(internal_kind::string);
return repr_.get_string();
}
BOOST_CXX14_CONSTEXPR float
boost::mysql::field_view::as_float() const
{
if (is_field_ptr())
return repr_.field_ptr->as<float>();
check_kind(internal_kind::float_);
return repr_.float_;
}
BOOST_CXX14_CONSTEXPR double
boost::mysql::field_view::as_double() const
{
if (is_field_ptr())
return repr_.field_ptr->as<double>();
check_kind(internal_kind::double_);
return repr_.double_;
}
BOOST_CXX14_CONSTEXPR boost::mysql::date
boost::mysql::field_view::as_date() const
{
if (is_field_ptr())
return repr_.field_ptr->as<date>();
check_kind(internal_kind::date);
return repr_.get_date();
}
BOOST_CXX14_CONSTEXPR boost::mysql::datetime
boost::mysql::field_view::as_datetime() const
{
if (is_field_ptr())
return repr_.field_ptr->as<datetime>();
check_kind(internal_kind::datetime);
return repr_.get_datetime();
}
BOOST_CXX14_CONSTEXPR boost::mysql::time
boost::mysql::field_view::as_time() const
{
if (is_field_ptr())
return repr_.field_ptr->as<time>();
check_kind(internal_kind::time);
return repr_.get_time();
}
BOOST_CXX14_CONSTEXPR std::int64_t
boost::mysql::field_view::get_int64() const noexcept
{
return is_field_ptr() ? repr_.field_ptr->get<std::int64_t>() : repr_.int64;
}
BOOST_CXX14_CONSTEXPR std::uint64_t
boost::mysql::field_view::get_uint64() const noexcept
{
return is_field_ptr() ? repr_.field_ptr->get<std::uint64_t>() : repr_.uint64;
}
BOOST_CXX14_CONSTEXPR boost::string_view
boost::mysql::field_view::get_string() const noexcept
{
return is_field_ptr() ? boost::string_view(repr_.field_ptr->get<std::string>()) : repr_.get_string();
}
BOOST_CXX14_CONSTEXPR float
boost::mysql::field_view::get_float() const noexcept
{
return is_field_ptr() ? repr_.field_ptr->get<float>() : repr_.float_;
}
BOOST_CXX14_CONSTEXPR double
boost::mysql::field_view::get_double() const noexcept
{
return is_field_ptr() ? repr_.field_ptr->get<double>() : repr_.double_;
}
BOOST_CXX14_CONSTEXPR boost::mysql::date
boost::mysql::field_view::get_date() const noexcept
{
return is_field_ptr() ? repr_.field_ptr->get<date>() : repr_.get_date();
}
BOOST_CXX14_CONSTEXPR boost::mysql::datetime
boost::mysql::field_view::get_datetime() const noexcept
{
return is_field_ptr() ? repr_.field_ptr->get<datetime>() : repr_.get_datetime();
}
BOOST_CXX14_CONSTEXPR boost::mysql::time
boost::mysql::field_view::get_time() const noexcept
{
return is_field_ptr() ? repr_.field_ptr->get<time>() : repr_.get_time();
}
void boost::mysql::field_view::check_kind(
internal_kind expected
) const
{
if (ikind_ != expected)
throw bad_field_access();
return *res;
}
template <typename T>
const T& boost::mysql::field_view::internal_get() const noexcept
{
const T* res = boost::variant2::get_if<T>(&repr_);
assert(res);
return *res;
}
BOOST_CXX14_CONSTEXPR bool boost::mysql::field_view::operator==(
const field_view& rhs
) const noexcept
{
if (is_int64() && rhs.is_uint64())
auto k = kind(), rhs_k = rhs.kind();
switch (k)
{
std::int64_t this_val = get_int64();
if (this_val < 0)
case field_kind::null: return rhs_k == field_kind::null;
case field_kind::int64:
if (rhs_k == field_kind::int64)
return get_int64() == rhs.get_int64();
else if (rhs_k == field_kind::uint64)
{
std::int64_t this_val = get_int64();
if (this_val < 0)
return false;
else
return static_cast<std::uint64_t>(this_val) == rhs.get_uint64();
}
else
return false;
return static_cast<std::uint64_t>(this_val) == rhs.get_uint64();
}
else if (is_uint64() && rhs.is_int64())
{
std::int64_t rhs_val = rhs.get_int64();
if (rhs_val < 0)
case field_kind::uint64:
if (rhs_k == field_kind::uint64)
return get_uint64() == rhs.get_uint64();
else if (rhs_k == field_kind::int64)
{
std::int64_t rhs_val = rhs.get_int64();
if (rhs_val < 0)
return false;
else
return static_cast<std::uint64_t>(rhs_val) == get_uint64();
}
else
return false;
return static_cast<std::uint64_t>(rhs_val) == get_uint64();
}
else
{
return repr_ == rhs.repr_;
case field_kind::string:
return rhs_k == field_kind::string && get_string() == rhs.get_string();
case field_kind::float_:
return rhs_k == field_kind::float_ && get_float() == rhs.get_float();
case field_kind::double_:
return rhs_k == field_kind::double_ && get_double() == rhs.get_double();
case field_kind::date:
return rhs_k == field_kind::date && get_date() == rhs.get_date();
case field_kind::datetime:
return rhs_k == field_kind::datetime && get_datetime() == rhs.get_datetime();
case field_kind::time:
return rhs_k == field_kind::time && get_time() == rhs.get_time();
}
}
@@ -125,8 +401,18 @@ inline std::ostream& boost::mysql::operator<<(
const field_view& value
)
{
boost::variant2::visit(field_view::print_visitor(os), value.repr_);
return os;
switch (value.kind())
{
case field_kind::null: return os << "<NULL>";
case field_kind::int64: return os << value.get_int64();
case field_kind::uint64: return os << value.get_uint64();
case field_kind::string: return os << value.get_string();
case field_kind::float_: return os << value.get_float();
case field_kind::double_: return os << value.get_double();
case field_kind::date: return detail::print_date(os, value.get_date());
case field_kind::datetime: return detail::print_datetime(os, value.get_datetime());
case field_kind::time: return detail::print_time(os, value.get_time());
}
}
template <class... Types>
@@ -139,4 +425,5 @@ boost::mysql::make_field_views(
}
#endif