mirror of
https://github.com/BlackMATov/meta.hpp.git
synced 2025-12-16 22:17:02 +07:00
value impl
This commit is contained in:
@@ -13,6 +13,7 @@
|
||||
#include <cassert>
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
#include <cstring>
|
||||
#include <functional>
|
||||
#include <initializer_list>
|
||||
#include <map>
|
||||
|
||||
@@ -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 >
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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_);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user