value impl

This commit is contained in:
BlackMATov
2021-08-11 18:05:19 +07:00
parent c0ad3347fe
commit c0708cd877
6 changed files with 489 additions and 25 deletions

View File

@@ -13,6 +13,7 @@
#include <cassert>
#include <cstddef>
#include <cstdint>
#include <cstring>
#include <functional>
#include <initializer_list>
#include <map>

View File

@@ -71,9 +71,10 @@ namespace meta_hpp
}
template < typename T >
any_type type_db::get() {
const any_type& type_db::get() {
static const auto raw_type = detail::make_any_type<T>();
return any_type{raw_type};
static const auto type = any_type{raw_type};
return type;
}
template < typename Tuple >

View File

@@ -190,7 +190,7 @@ namespace meta_hpp
type_db() = delete;
template < typename T >
static any_type get();
static const any_type& get();
template < typename Tuple >
static std::vector<any_type> multi_get();

View File

@@ -30,16 +30,12 @@ namespace meta_hpp
template < typename T, std::enable_if_t<
std::is_pointer_v<T> ||
std::is_lvalue_reference_v<T>, int> = 0 >
explicit arg_base(typename_arg_t<T>)
: raw_type_{type_db::get<stdex::remove_cvref_t<T>>()}
, ref_type_{std::is_const_v<std::remove_reference_t<T>> ? ref_types::cref : ref_types::ref} {}
explicit arg_base(typename_arg_t<T>);
template < typename T, std::enable_if_t<
std::is_rvalue_reference_v<T> ||
(!std::is_pointer_v<T> && !std::is_reference_v<T>), int> = 0 >
explicit arg_base(typename_arg_t<T>)
: raw_type_{type_db::get<stdex::remove_cvref_t<T>>()}
, ref_type_{std::is_const_v<std::remove_reference_t<T>> ? ref_types::crref : ref_types::rref} {}
explicit arg_base(typename_arg_t<T>);
bool is_const() const noexcept;
bool is_lvalue() const noexcept;
@@ -58,6 +54,20 @@ namespace meta_hpp
namespace meta_hpp
{
template < typename T, std::enable_if_t<
std::is_pointer_v<T> ||
std::is_lvalue_reference_v<T>, int> >
arg_base::arg_base(typename_arg_t<T>)
: raw_type_{type_db::get<stdex::remove_cvref_t<T>>()}
, ref_type_{std::is_const_v<std::remove_reference_t<T>> ? ref_types::cref : ref_types::ref} {}
template < typename T, std::enable_if_t<
std::is_rvalue_reference_v<T> ||
(!std::is_pointer_v<T> && !std::is_reference_v<T>), int> >
arg_base::arg_base(typename_arg_t<T>)
: raw_type_{type_db::get<stdex::remove_cvref_t<T>>()}
, ref_type_{std::is_const_v<std::remove_reference_t<T>> ? ref_types::crref : ref_types::rref} {}
inline bool arg_base::is_const() const noexcept {
return ref_type_ == ref_types::cref
|| ref_type_ == ref_types::crref;

View File

@@ -14,33 +14,242 @@ namespace meta_hpp
public:
value() = delete;
value(value&&) = default;
value& operator=(value&&) = default;
value(value&& other);
value(const value& other);
value(const value&) = default;
value& operator=(const value&) = default;
value& operator=(value&& other);
value& operator=(const value& other);
template < typename T, typename Tp = std::decay_t<T>
template < typename T
, typename Tp = std::decay_t<T>
, std::enable_if_t<!std::is_same_v<Tp, value>, int> = 0 >
value(T&& val)
: raw_{std::forward<T>(val)} {}
value(T&& val);
template < typename T, typename Tp = std::decay_t<T>
template < typename T
, typename Tp = std::decay_t<T>
, std::enable_if_t<!std::is_same_v<Tp, value>, int> = 0 >
value& operator=(T&& val) {
value{std::forward<T>(val)}.swap(*this);
return *this;
}
value& operator=(T&& val);
void swap(value& other) noexcept {
using std::swap;
swap(raw_, other.raw_);
}
void swap(value& other) noexcept;
const any_type& type() const noexcept;
void* data() noexcept;
const void* data() const noexcept;
const void* cdata() const noexcept;
template < typename T >
bool equals(const T& other) const;
bool equals(const value& other) const;
template < typename T, typename Tp = std::decay_t<T> >
Tp& cast() &;
template < typename T, typename Tp = std::decay_t<T> >
Tp&& cast() &&;
template < typename T, typename Tp = std::decay_t<T> >
const Tp& cast() const &;
template < typename T, typename Tp = std::decay_t<T> >
const Tp&& cast() const &&;
template < typename T, typename Tp = std::decay_t<T> >
Tp* try_cast() noexcept;
template < typename T, typename Tp = std::decay_t<T> >
const Tp* try_cast() const noexcept;
private:
struct traits;
std::any raw_{};
const traits* traits_{};
};
inline void swap(value& l, value& r) noexcept {
l.swap(r);
}
}
namespace meta_hpp
{
struct value::traits final {
const any_type type;
void* (*const data)(value&) noexcept;
const void* (*const cdata)(const value&) noexcept;
bool (*const equals)(const value&, const value&);
void (*const move_ctor)(std::any&, value&&);
void (*const copy_ctor)(std::any&, const value&);
template < typename T >
static const traits* get() noexcept;
};
template < typename T >
const value::traits* value::traits::get() noexcept {
static const traits traits{
// type
type_db::get<T>(),
// data
+[](value& v) noexcept -> void* {
return v.try_cast<T>();
},
// cdata
+[](const value& v) noexcept -> const void* {
return v.try_cast<T>();
},
// equals
+[](const value& l, const value& r) -> bool {
if ( l.type() != r.type() ) {
return false;
}
if constexpr ( std::is_invocable_v<std::equal_to<>, const T&, const T&> ) {
return std::equal_to<>{}(l.cast<T>(), r.cast<T>());
} else {
throw std::logic_error("value type doesn't have equality operator");
}
},
// move_ctor
+[](std::any& dst, value&& src) {
if constexpr ( std::is_move_constructible_v<T> ) {
dst.emplace<T>(std::move(src).cast<T>());
} else {
throw std::logic_error("value type is not move constructible");
}
},
// copy_ctor
+[](std::any& dst, const value& src) {
if constexpr ( std::is_copy_constructible_v<T> ) {
dst.emplace<T>(src.cast<T>());
} else {
throw std::logic_error("value type is not copy constructible");
}
},
};
return &traits;
}
}
namespace meta_hpp
{
inline value::value(value&& other) {
traits_ = other.traits_;
traits_->move_ctor(raw_, std::move(other));
}
inline value::value(const value& other) {
traits_ = other.traits_;
traits_->copy_ctor(raw_, other);
}
inline value& value::operator=(value&& other) {
if ( this != &other ) {
traits_ = other.traits_;
traits_->move_ctor(raw_, std::move(other));
}
return *this;
}
inline value& value::operator=(const value& other) {
if ( this != &other ) {
traits_ = other.traits_;
traits_->copy_ctor(raw_, other);
}
return *this;
}
template < typename T, typename Tp
, std::enable_if_t<!std::is_same_v<Tp, value>, int> >
value::value(T&& val)
: raw_{std::forward<T>(val)}
, traits_{traits::get<Tp>()} {}
template < typename T, typename Tp
, std::enable_if_t<!std::is_same_v<Tp, value>, int> >
value& value::operator=(T&& val) {
raw_ = std::forward<T>(val);
traits_ = type_db::get<Tp>();
return *this;
}
inline void value::swap(value& other) noexcept {
using std::swap;
swap(raw_, other.raw_);
swap(traits_, other.traits_);
}
inline const any_type& value::type() const noexcept {
return traits_->type;
}
inline void* value::data() noexcept {
return traits_->data(*this);
}
inline const void* value::data() const noexcept {
return traits_->cdata(*this);
}
inline const void* value::cdata() const noexcept {
return traits_->cdata(*this);
}
template < typename T >
bool value::equals(const T& other) const {
return type() == type_db::get<T>()
&& std::equal_to<>{}(cast<T>(), other);
}
inline bool value::equals(const value& other) const {
return traits_->equals(*this, other);
}
template < typename T, typename Tp >
Tp& value::cast() & {
if ( type() != type_db::get<Tp>() ) {
throw std::logic_error("bad value cast");
}
return std::any_cast<Tp&>(raw_);
}
template < typename T, typename Tp >
Tp&& value::cast() && {
if ( type() != type_db::get<Tp>() ) {
throw std::logic_error("bad value cast");
}
return std::move(std::any_cast<Tp&>(raw_));
}
template < typename T, typename Tp >
const Tp& value::cast() const & {
if ( type() != type_db::get<Tp>() ) {
throw std::logic_error("bad value cast");
}
return std::any_cast<const Tp&>(raw_);
}
template < typename T, typename Tp >
const Tp&& value::cast() const && {
if ( type() != type_db::get<Tp>() ) {
throw std::logic_error("bad value cast");
}
return std::move(std::any_cast<const Tp&>(raw_));
}
template < typename T, typename Tp >
Tp* value::try_cast() noexcept {
return std::any_cast<Tp>(&raw_);
}
template < typename T, typename Tp >
const Tp* value::try_cast() const noexcept {
return std::any_cast<Tp>(&raw_);
}
}