new basic version

This commit is contained in:
BlackMATov
2021-11-25 05:34:00 +07:00
parent e729c67b8d
commit e17c8a4206
56 changed files with 8359 additions and 0 deletions

View File

@@ -10,6 +10,20 @@
#include "meta_kinds.hpp"
#include "meta_registry.hpp"
#include "meta_registry/class_bind.hpp"
#include "meta_registry/enum_bind.hpp"
#include "meta_registry/scope_bind.hpp"
#include "meta_states.hpp"
#include "meta_states/ctor.hpp"
#include "meta_states/evalue.hpp"
#include "meta_states/function.hpp"
#include "meta_states/member.hpp"
#include "meta_states/method.hpp"
#include "meta_states/scope.hpp"
#include "meta_states/variable.hpp"
#include "meta_traits.hpp"
#include "meta_traits/array_traits.hpp"
#include "meta_traits/class_traits.hpp"
@@ -22,3 +36,22 @@
#include "meta_traits/pointer_traits.hpp"
#include "meta_traits/reference_traits.hpp"
#include "meta_traits/void_traits.hpp"
#include "meta_types.hpp"
#include "meta_types/any_type.hpp"
#include "meta_types/array_type.hpp"
#include "meta_types/class_type.hpp"
#include "meta_types/ctor_type.hpp"
#include "meta_types/enum_type.hpp"
#include "meta_types/function_type.hpp"
#include "meta_types/member_type.hpp"
#include "meta_types/method_type.hpp"
#include "meta_types/number_type.hpp"
#include "meta_types/pointer_type.hpp"
#include "meta_types/reference_type.hpp"
#include "meta_types/void_type.hpp"
#include "meta_utilities.hpp"
#include "meta_utilities/arg.hpp"
#include "meta_utilities/inst.hpp"
#include "meta_utilities/value.hpp"

View File

@@ -165,6 +165,7 @@ namespace meta_hpp
struct function_index;
struct member_index;
struct method_index;
struct scope_index;
struct variable_index;
using class_set = std::set<class_type, std::less<>>;
@@ -178,5 +179,6 @@ namespace meta_hpp
using function_map = std::map<function_index, function, std::less<>>;
using member_map = std::map<member_index, member, std::less<>>;
using method_map = std::map<method_index, method, std::less<>>;
using scope_map = std::map<scope_index, scope, std::less<>>;
using variable_map = std::map<variable_index, variable, std::less<>>;
}

View File

@@ -0,0 +1,94 @@
/*******************************************************************************
* This file is part of the "https://github.com/blackmatov/meta.hpp"
* For conditions of distribution and use, see copyright notice in LICENSE.md
* Copyright (C) 2021, by Matvey Cherevko (blackmatov@gmail.com)
******************************************************************************/
#pragma once
#include "meta_base.hpp"
#include "meta_states.hpp"
namespace meta_hpp
{
template < class_kind Class >
class class_bind final {
public:
explicit class_bind();
operator class_type() const noexcept;
template < typename... Args >
class_bind& ctor_();
template < class_kind Base >
class_bind& base_();
template < function_kind Function >
class_bind& function_(std::string name, Function function);
template < member_kind Member >
class_bind& member_(std::string name, Member member);
template < method_kind Method >
class_bind& method_(std::string name, Method method);
template < pointer_kind Pointer >
class_bind& variable_(std::string name, Pointer pointer);
private:
detail::class_type_data_ptr data_;
};
}
namespace meta_hpp
{
template < enum_kind Enum >
class enum_bind final {
public:
explicit enum_bind();
operator enum_type() const noexcept;
enum_bind& evalue_(std::string name, Enum value);
private:
detail::enum_type_data_ptr data_;
};
}
namespace meta_hpp
{
class scope_bind final {
public:
explicit scope_bind(std::string_view name);
operator scope() const noexcept;
template < class_kind Class >
scope_bind& class_(std::string name);
template < enum_kind Enum >
scope_bind& enum_(std::string name);
template < function_kind Function >
scope_bind& function_(std::string name, Function function);
template < pointer_kind Pointer >
scope_bind& variable_(std::string name, Pointer pointer);
private:
detail::scope_state_ptr state_;
};
}
namespace meta_hpp
{
template < class_kind Class >
class_bind<Class> class_() {
return class_bind<Class>{};
}
template < enum_kind Enum >
enum_bind<Enum> enum_() {
return enum_bind<Enum>{};
}
inline scope_bind scope_(std::string name) {
return scope_bind{std::move(name)};
}
}

View File

@@ -0,0 +1,70 @@
/*******************************************************************************
* This file is part of the "https://github.com/blackmatov/meta.hpp"
* For conditions of distribution and use, see copyright notice in LICENSE.md
* Copyright (C) 2021, by Matvey Cherevko (blackmatov@gmail.com)
******************************************************************************/
#pragma once
#include "../meta_base.hpp"
#include "../meta_registry.hpp"
namespace meta_hpp
{
template < class_kind Class >
class_bind<Class>::class_bind()
: data_{detail::get_type_data<Class>()} {}
template < class_kind Class >
class_bind<Class>::operator class_type() const noexcept {
return class_type{data_};
}
template < class_kind Class >
template < typename... Args >
class_bind<Class>& class_bind<Class>::ctor_() {
auto ctor_state = detail::ctor_state::make<Class, Args...>();
data_->ctors.emplace(ctor_state->index, std::move(ctor_state));
return *this;
}
template < class_kind Class >
template < class_kind Base >
class_bind<Class>& class_bind<Class>::base_() {
auto base_data = detail::class_type_data::get<Base>();
data_->bases.emplace(base_data);
return *this;
}
template < class_kind Class >
template < function_kind Function >
class_bind<Class>& class_bind<Class>::function_(std::string name, Function function) {
auto function_state = detail::function_state::make<Function>(std::move(name), std::move(function));
data_->functions.emplace(function_state->index, std::move(function_state));
return *this;
}
template < class_kind Class >
template < member_kind Member >
class_bind<Class>& class_bind<Class>::member_(std::string name, Member member) {
auto member_state = detail::member_state::make<Member>(std::move(name), std::move(member));
data_->members.emplace(member_state->index, std::move(member_state));
return *this;
}
template < class_kind Class >
template < method_kind Method >
class_bind<Class>& class_bind<Class>::method_(std::string name, Method method) {
auto method_state = detail::method_state::make<Method>(std::move(name), std::move(method));
data_->methods.emplace(method_state->index, std::move(method_state));
return *this;
}
template < class_kind Class >
template < pointer_kind Pointer >
class_bind<Class>& class_bind<Class>::variable_(std::string name, Pointer pointer) {
auto variable_state = detail::variable_state::make<Pointer>(std::move(name), std::move(pointer));
data_->variables.emplace(variable_state->index, std::move(variable_state));
return *this;
}
}

View File

@@ -0,0 +1,29 @@
/*******************************************************************************
* This file is part of the "https://github.com/blackmatov/meta.hpp"
* For conditions of distribution and use, see copyright notice in LICENSE.md
* Copyright (C) 2021, by Matvey Cherevko (blackmatov@gmail.com)
******************************************************************************/
#pragma once
#include "../meta_base.hpp"
#include "../meta_registry.hpp"
namespace meta_hpp
{
template < enum_kind Enum >
enum_bind<Enum>::enum_bind()
: data_{detail::get_type_data<Enum>()} {}
template < enum_kind Enum >
enum_bind<Enum>::operator enum_type() const noexcept {
return enum_type{data_};
}
template < enum_kind Enum >
enum_bind<Enum>& enum_bind<Enum>::evalue_(std::string name, Enum value) {
auto evalue_state = detail::evalue_state::make(std::move(name), std::move(value));
data_->evalues.emplace(evalue_state->index, std::move(evalue_state));
return *this;
}
}

View File

@@ -0,0 +1,48 @@
/*******************************************************************************
* This file is part of the "https://github.com/blackmatov/meta.hpp"
* For conditions of distribution and use, see copyright notice in LICENSE.md
* Copyright (C) 2021, by Matvey Cherevko (blackmatov@gmail.com)
******************************************************************************/
#pragma once
#include "../meta_base.hpp"
#include "../meta_registry.hpp"
namespace meta_hpp
{
inline scope_bind::scope_bind(std::string_view name)
: state_{detail::get_scope_state(name)} {}
inline scope_bind::operator scope() const noexcept {
return scope{state_};
}
template < class_kind Class >
scope_bind& scope_bind::class_(std::string name) {
auto class_data = detail::class_type_data::get<Class>();
state_->classes.emplace(std::move(name), class_data);
return *this;
}
template < enum_kind Enum >
scope_bind& scope_bind::enum_(std::string name) {
auto enum_data = detail::enum_type_data::get<Enum>();
state_->enums.emplace(std::move(name), enum_data);
return *this;
}
template < function_kind Function >
scope_bind& scope_bind::function_(std::string name, Function function) {
auto function_state = detail::function_state::make<Function>(std::move(name), std::move(function));
state_->functions.emplace(function_state->index, std::move(function_state));
return *this;
}
template < pointer_kind Pointer >
scope_bind& scope_bind::variable_(std::string name, Pointer pointer) {
auto variable_state = detail::variable_state::make<Pointer>(std::move(name), std::move(pointer));
state_->variables.emplace(variable_state->index, std::move(variable_state));
return *this;
}
}

View File

@@ -0,0 +1,329 @@
/*******************************************************************************
* This file is part of the "https://github.com/blackmatov/meta.hpp"
* For conditions of distribution and use, see copyright notice in LICENSE.md
* Copyright (C) 2021, by Matvey Cherevko (blackmatov@gmail.com)
******************************************************************************/
#pragma once
#include "meta_base.hpp"
#include "meta_types.hpp"
#include "meta_utilities.hpp"
namespace meta_hpp
{
template < typename T >
concept states_family =
std::same_as<T, ctor> ||
std::same_as<T, evalue> ||
std::same_as<T, function> ||
std::same_as<T, member> ||
std::same_as<T, method> ||
std::same_as<T, scope> ||
std::same_as<T, variable>;
template < states_family T, states_family U >
bool operator<(const T& l, const U& r) noexcept {
if ( !static_cast<bool>(r) ) {
return false;
}
if ( !static_cast<bool>(l) ) {
return true;
}
return l.get_index() < r.get_index();
}
template < states_family T, states_family U >
bool operator==(const T& l, const U& r) noexcept {
if ( static_cast<bool>(l) != static_cast<bool>(r) ) {
return false;
}
if ( !static_cast<bool>(l) ) {
return true;
}
return l.get_index() == r.get_index();
}
template < states_family T, states_family U >
bool operator!=(const T& l, const U& r) noexcept {
return !(l == r);
}
}
namespace meta_hpp
{
class ctor final {
public:
explicit ctor() = default;
explicit ctor(detail::ctor_state_ptr state);
bool is_valid() const noexcept;
explicit operator bool() const noexcept;
const ctor_index& get_index() const noexcept;
const ctor_type& get_type() const noexcept;
template < typename... Args >
value invoke(Args&&... args) const;
template < typename... Args >
bool is_invocable_with() const noexcept;
private:
detail::ctor_state_ptr state_;
};
class evalue final {
public:
explicit evalue() = default;
explicit evalue(detail::evalue_state_ptr state);
bool is_valid() const noexcept;
explicit operator bool() const noexcept;
const evalue_index& get_index() const noexcept;
const enum_type& get_type() const noexcept;
const std::string& get_name() const noexcept;
const value& get_value() const noexcept;
private:
detail::evalue_state_ptr state_;
};
class function final {
public:
explicit function() = default;
explicit function(detail::function_state_ptr state);
bool is_valid() const noexcept;
explicit operator bool() const noexcept;
const function_index& get_index() const noexcept;
const function_type& get_type() const noexcept;
const std::string& get_name() const noexcept;
template < typename... Args >
std::optional<value> invoke(Args&&... args) const;
template < typename... Args >
bool is_invocable_with() const noexcept;
private:
detail::function_state_ptr state_;
};
class member final {
public:
explicit member() = default;
explicit member(detail::member_state_ptr state);
bool is_valid() const noexcept;
explicit operator bool() const noexcept;
const member_index& get_index() const noexcept;
const member_type& get_type() const noexcept;
const std::string& get_name() const noexcept;
template < typename Instance >
value get(Instance&& instance) const;
template < typename Instance, typename Value >
void set(Instance&& instance, Value&& value) const;
private:
detail::member_state_ptr state_;
};
class method final {
public:
explicit method() = default;
explicit method(detail::method_state_ptr state);
bool is_valid() const noexcept;
explicit operator bool() const noexcept;
const method_index& get_index() const noexcept;
const method_type& get_type() const noexcept;
const std::string& get_name() const noexcept;
template < typename Instance, typename... Args >
std::optional<value> invoke(Instance&& instance, Args&&... args) const;
template < typename Inst, typename... Args >
bool is_invocable_with() const noexcept;
private:
detail::method_state_ptr state_;
};
class scope final {
public:
explicit scope() = default;
explicit scope(detail::scope_state_ptr state);
bool is_valid() const noexcept;
explicit operator bool() const noexcept;
const scope_index& get_index() const noexcept;
const std::string& get_name() const noexcept;
const class_map& get_classes() const noexcept;
const enum_map& get_enums() const noexcept;
const function_map& get_functions() const noexcept;
const variable_map& get_variables() const noexcept;
class_type get_class(std::string_view name) const noexcept;
enum_type get_enum(std::string_view name) const noexcept;
function get_function(std::string_view name) const noexcept;
variable get_variable(std::string_view name) const noexcept;
template < typename... Args >
function get_function_with(std::string_view name) const noexcept;
function get_function_with(std::string_view name, std::vector<any_type> args) const noexcept;
function get_function_with(std::string_view name, std::initializer_list<any_type> args) const noexcept;
private:
detail::scope_state_ptr state_;
};
class variable final {
public:
explicit variable() = default;
explicit variable(detail::variable_state_ptr state);
bool is_valid() const noexcept;
explicit operator bool() const noexcept;
const variable_index& get_index() const noexcept;
const pointer_type& get_type() const noexcept;
const std::string& get_name() const noexcept;
value get() const;
template < typename Value >
void set(Value&& value) const;
private:
detail::variable_state_ptr state_;
};
}
namespace meta_hpp::detail
{
struct ctor_state final {
using invoke_impl = std::function<value(const arg*, std::size_t)>;
using is_invocable_with_impl = std::function<bool(const arg_base*, std::size_t)>;
ctor_index index;
invoke_impl invoke;
is_invocable_with_impl is_invocable_with;
template < class_kind Class, typename... Args >
static ctor_state_ptr make();
template < class_kind Class, typename... Args >
explicit ctor_state(ctor_index index, type_list<Class>, type_list<Args...>);
};
struct evalue_state final {
evalue_index index;
class value value;
template < enum_kind Enum >
static evalue_state_ptr make(std::string name, Enum value);
template < enum_kind Enum >
explicit evalue_state(evalue_index index, Enum value);
};
struct function_state final {
using invoke_impl = std::function<std::optional<value>(const arg*, std::size_t)>;
using is_invocable_with_impl = std::function<bool(const arg_base*, std::size_t)>;
function_index index;
invoke_impl invoke;
is_invocable_with_impl is_invocable_with;
template < function_kind Function >
static function_state_ptr make(std::string name, Function function);
template < function_kind Function >
explicit function_state(function_index index, Function function);
};
struct member_state final {
using getter_impl = std::function<value(const inst&)>;
using setter_impl = std::function<void(const inst&, const arg&)>;
member_index index;
getter_impl getter;
setter_impl setter;
template < member_kind Member >
static member_state_ptr make(std::string name, Member member);
template < member_kind Member >
explicit member_state(member_index index, Member member);
};
struct method_state final {
using invoke_impl = std::function<std::optional<value>(const inst&, const arg*, std::size_t)>;
using is_invocable_with_impl = std::function<bool(const inst_base&, const arg_base*, std::size_t)>;
method_index index;
invoke_impl invoke;
is_invocable_with_impl is_invocable_with;
template < method_kind Method >
static method_state_ptr make(std::string name, Method method);
template < method_kind Method >
explicit method_state(method_index index, Method method);
};
struct scope_state final {
scope_index index;
class_map classes;
enum_map enums;
function_map functions;
variable_map variables;
static scope_state_ptr get(std::string_view name);
explicit scope_state(scope_index index);
};
struct variable_state final {
using getter_impl = std::function<value()>;
using setter_impl = std::function<void(const arg&)>;
variable_index index;
getter_impl getter;
setter_impl setter;
template < pointer_kind Pointer >
static variable_state_ptr make(std::string name, Pointer pointer);
template < pointer_kind Pointer >
explicit variable_state(variable_index index, Pointer pointer);
};
}
namespace meta_hpp
{
namespace detail
{
inline scope_state_ptr get_scope_state(std::string_view name) {
return scope_state::get(name);
}
}
inline scope resolve_scope(std::string_view name) {
return scope{detail::get_scope_state(name)};
}
}

View File

@@ -0,0 +1,146 @@
/*******************************************************************************
* This file is part of the "https://github.com/blackmatov/meta.hpp"
* For conditions of distribution and use, see copyright notice in LICENSE.md
* Copyright (C) 2021, by Matvey Cherevko (blackmatov@gmail.com)
******************************************************************************/
#pragma once
#include "../meta_base.hpp"
#include "../meta_states.hpp"
#include "../meta_types/ctor_type.hpp"
namespace meta_hpp::detail
{
template < class_kind Class, typename... Args, std::size_t... Is >
value raw_ctor_invoke_impl(
const arg* args,
std::index_sequence<Is...>)
{
using ct = ctor_traits<Class, Args...>;
using class_type = typename ct::class_type;
using argument_types = typename ct::argument_types;
if ( !(... && (args + Is)->can_cast_to<type_list_at_t<Is, argument_types>>()) ) {
throw std::logic_error("an attempt to call a constructor with an incorrect argument types");
}
class_type return_value{(args + Is)->cast<type_list_at_t<Is, argument_types>>()...};
return value{std::forward<class_type>(return_value)};
}
template < class_kind Class, typename... Args >
value raw_ctor_invoke(
const arg* args,
std::size_t arg_count)
{
using ct = ctor_traits<Class, Args...>;
if ( arg_count != ct::arity ) {
throw std::logic_error("an attempt to call a constructor with an incorrect arity");
}
return raw_ctor_invoke_impl<Class, Args...>(
args,
std::make_index_sequence<ct::arity>());
}
template < class_kind Class, typename... Args >
ctor_state::invoke_impl make_ctor_invoke() {
using namespace std::placeholders;
return std::bind(&raw_ctor_invoke<Class, Args...>, _1, _2);
}
}
namespace meta_hpp::detail
{
template < class_kind Class, typename... Args, std::size_t... Is >
bool raw_ctor_is_invocable_with_impl(
const arg_base* arg_bases,
std::index_sequence<Is...>)
{
using ct = ctor_traits<Class, Args...>;
using argument_types = typename ct::argument_types;
return (... && (arg_bases + Is)->can_cast_to<type_list_at_t<Is, argument_types>>() );
}
template < class_kind Class, typename... Args >
bool raw_ctor_is_invocable_with(
const arg_base* arg_bases,
std::size_t arg_count)
{
using ct = ctor_traits<Class, Args...>;
if ( arg_count != ct::arity ) {
return false;
}
return raw_ctor_is_invocable_with_impl<Class, Args...>(
arg_bases,
std::make_index_sequence<ct::arity>());
}
template < class_kind Class, typename... Args >
ctor_state::is_invocable_with_impl make_ctor_is_invocable_with() {
using namespace std::placeholders;
return std::bind(&raw_ctor_is_invocable_with<Class, Args...>, _1, _2);
}
}
namespace meta_hpp::detail
{
template < class_kind Class, typename... Args >
ctor_state_ptr ctor_state::make() {
ctor_index index{ctor_type_data::get<Class, Args...>()};
return std::make_shared<ctor_state>(std::move(index), type_list<Class>{}, type_list<Args...>{});
}
template < class_kind Class, typename... Args >
ctor_state::ctor_state(ctor_index index, type_list<Class>, type_list<Args...>)
: index{std::move(index)}
, invoke{make_ctor_invoke<Class, Args...>()}
, is_invocable_with{make_ctor_is_invocable_with<Class, Args...>()} {}
}
namespace meta_hpp
{
inline ctor::ctor(detail::ctor_state_ptr state)
: state_{std::move(state)} {}
inline bool ctor::is_valid() const noexcept {
return !!state_;
}
inline ctor::operator bool() const noexcept {
return is_valid();
}
inline const ctor_index& ctor::get_index() const noexcept {
return state_->index;
}
inline const ctor_type& ctor::get_type() const noexcept {
return state_->index.type;
}
template < typename... Args >
inline value ctor::invoke(Args&&... args) const {
if constexpr ( sizeof...(Args) > 0 ) {
std::array<detail::arg, sizeof...(Args)> vargs{detail::arg{std::forward<Args>(args)}...};
return state_->invoke(vargs.data(), vargs.size());
} else {
return state_->invoke(nullptr, 0);
}
}
template < typename... Args >
inline bool ctor::is_invocable_with() const noexcept {
if constexpr ( sizeof...(Args) > 0 ) {
std::array<detail::arg_base, sizeof...(Args)> arg_bases{detail::arg_base{type_list<Args>{}}...};
return state_->is_invocable_with(arg_bases.data(), arg_bases.size());
} else {
return state_->is_invocable_with(nullptr, 0);
}
}
}

View File

@@ -0,0 +1,56 @@
/*******************************************************************************
* This file is part of the "https://github.com/blackmatov/meta.hpp"
* For conditions of distribution and use, see copyright notice in LICENSE.md
* Copyright (C) 2021, by Matvey Cherevko (blackmatov@gmail.com)
******************************************************************************/
#pragma once
#include "../meta_base.hpp"
#include "../meta_states.hpp"
#include "../meta_types/enum_type.hpp"
namespace meta_hpp::detail
{
template < enum_kind Enum >
evalue_state_ptr evalue_state::make(std::string name, Enum value) {
evalue_index index{enum_type_data::get<Enum>(), std::move(name)};
return std::make_shared<evalue_state>(std::move(index), std::move(value));
}
template < enum_kind Enum >
evalue_state::evalue_state(evalue_index index, Enum value)
: index{std::move(index)}
, value{std::move(value)} {}
}
namespace meta_hpp
{
inline evalue::evalue(detail::evalue_state_ptr state)
: state_{std::move(state)} {}
inline bool evalue::is_valid() const noexcept {
return !!state_;
}
inline evalue::operator bool() const noexcept {
return is_valid();
}
inline const evalue_index& evalue::get_index() const noexcept {
return state_->index;
}
inline const enum_type& evalue::get_type() const noexcept {
return state_->index.type;
}
inline const std::string& evalue::get_name() const noexcept {
return state_->index.name;
}
inline const value& evalue::get_value() const noexcept {
return state_->value;
}
}

View File

@@ -0,0 +1,160 @@
/*******************************************************************************
* This file is part of the "https://github.com/blackmatov/meta.hpp"
* For conditions of distribution and use, see copyright notice in LICENSE.md
* Copyright (C) 2021, by Matvey Cherevko (blackmatov@gmail.com)
******************************************************************************/
#pragma once
#include "../meta_base.hpp"
#include "../meta_states.hpp"
#include "../meta_types/function_type.hpp"
namespace meta_hpp::detail
{
template < function_kind Function, std::size_t... Is >
std::optional<value> raw_function_invoke_impl(
Function function,
const arg* args,
std::index_sequence<Is...>)
{
using ft = function_traits<Function>;
using return_type = typename ft::return_type;
using argument_types = typename ft::argument_types;
if ( !(... && (args + Is)->can_cast_to<type_list_at_t<Is, argument_types>>()) ) {
throw std::logic_error("an attempt to call a function with an incorrect argument types");
}
if constexpr ( std::is_void_v<return_type> ) {
std::invoke(function,
(args + Is)->cast<type_list_at_t<Is, argument_types>>()...);
return std::nullopt;
} else {
return_type return_value{std::invoke(function,
(args + Is)->cast<type_list_at_t<Is, argument_types>>()...)};
return value{std::forward<return_type>(return_value)};
}
}
template < function_kind Function >
std::optional<value> raw_function_invoke(
Function function,
const arg* args,
std::size_t arg_count)
{
using ft = function_traits<Function>;
if ( arg_count != ft::arity ) {
throw std::logic_error("an attempt to call a function with an incorrect arity");
}
return raw_function_invoke_impl<Function>(
function,
args,
std::make_index_sequence<ft::arity>());
}
template < function_kind Function >
function_state::invoke_impl make_function_invoke(Function function) {
using namespace std::placeholders;
return std::bind(&raw_function_invoke<Function>, function, _1, _2);
}
}
namespace meta_hpp::detail
{
template < function_kind Function, std::size_t... Is >
bool raw_function_is_invocable_with_impl(
const arg_base* arg_bases,
std::index_sequence<Is...>)
{
using ft = function_traits<Function>;
using argument_types = typename ft::argument_types;
return (... && (arg_bases + Is)->can_cast_to<type_list_at_t<Is, argument_types>>() );
}
template < function_kind Function >
bool raw_function_is_invocable_with(
const arg_base* arg_bases,
std::size_t arg_count)
{
using ft = function_traits<Function>;
if ( arg_count != ft::arity ) {
return false;
}
return raw_function_is_invocable_with_impl<Function>(
arg_bases,
std::make_index_sequence<ft::arity>());
}
template < function_kind Function >
function_state::is_invocable_with_impl make_function_is_invocable_with() {
using namespace std::placeholders;
return std::bind(&raw_function_is_invocable_with<Function>, _1, _2);
}
}
namespace meta_hpp::detail
{
template < function_kind Function >
function_state_ptr function_state::make(std::string name, Function function) {
function_index index{function_type_data::get<Function>(), std::move(name)};
return std::make_shared<function_state>(std::move(index), std::move(function));
}
template < function_kind Function >
function_state::function_state(function_index index, Function function)
: index{std::move(index)}
, invoke{make_function_invoke(function)}
, is_invocable_with{make_function_is_invocable_with<Function>()} {}
}
namespace meta_hpp
{
inline function::function(detail::function_state_ptr state)
: state_{std::move(state)} {}
inline bool function::is_valid() const noexcept {
return !!state_;
}
inline function::operator bool() const noexcept {
return is_valid();
}
inline const function_index& function::get_index() const noexcept {
return state_->index;
}
inline const function_type& function::get_type() const noexcept {
return state_->index.type;
}
inline const std::string& function::get_name() const noexcept {
return state_->index.name;
}
template < typename... Args >
std::optional<value> function::invoke(Args&&... args) const {
if constexpr ( sizeof...(Args) > 0 ) {
std::array<detail::arg, sizeof...(Args)> vargs{detail::arg{std::forward<Args>(args)}...};
return state_->invoke(vargs.data(), vargs.size());
} else {
return state_->invoke(nullptr, 0);
}
}
template < typename... Args >
bool function::is_invocable_with() const noexcept {
if constexpr ( sizeof...(Args) > 0 ) {
std::array<detail::arg_base, sizeof...(Args)> arg_bases{detail::arg_base{type_list<Args>{}}...};
return state_->is_invocable_with(arg_bases.data(), arg_bases.size());
} else {
return state_->is_invocable_with(nullptr, 0);
}
}
}

View File

@@ -0,0 +1,124 @@
/*******************************************************************************
* This file is part of the "https://github.com/blackmatov/meta.hpp"
* For conditions of distribution and use, see copyright notice in LICENSE.md
* Copyright (C) 2021, by Matvey Cherevko (blackmatov@gmail.com)
******************************************************************************/
#pragma once
#include "../meta_base.hpp"
#include "../meta_states.hpp"
#include "../meta_types/member_type.hpp"
namespace meta_hpp::detail
{
template < member_kind Member >
value raw_member_getter(Member member, const inst& inst) {
using mt = member_traits<Member>;
using class_type = typename mt::class_type;
using value_type = typename mt::value_type;
using qualified_type = const class_type;
if ( !inst.can_cast_to<qualified_type>() ) {
throw std::logic_error("an attempt to get a member with an incorrect instance type");
}
value_type return_value{std::invoke(member, inst.cast<qualified_type>())};
return value{std::forward<value_type>(return_value)};
}
template < member_kind Member >
void raw_member_setter([[maybe_unused]] Member member, const inst& inst, const arg& arg) {
using mt = member_traits<Member>;
using class_type = typename mt::class_type;
using value_type = typename mt::value_type;
using qualified_type = class_type;
if constexpr ( !std::is_const_v<value_type> ) {
if ( inst.is_const() ) {
throw std::logic_error("an attempt to set a member with an const instance type");
}
if ( !inst.can_cast_to<qualified_type>() ) {
throw std::logic_error("an attempt to set a member with an incorrect instance type");
}
if ( !arg.can_cast_to<value_type>() ) {
throw std::logic_error("an attempt to set a member with an incorrect argument type");
}
std::invoke(member, inst.cast<qualified_type>()) = arg.cast<value_type>();
} else {
throw std::logic_error("an attempt to set a constant member");
}
}
}
namespace meta_hpp::detail
{
template < member_kind Member >
member_state::getter_impl make_member_getter(Member member) {
using namespace std::placeholders;
return std::bind(&raw_member_getter<Member>, member, _1);
}
template < member_kind Member >
member_state::setter_impl make_member_setter(Member member) {
using namespace std::placeholders;
return std::bind(&raw_member_setter<Member>, member, _1, _2);
}
}
namespace meta_hpp::detail
{
template < member_kind Member >
member_state_ptr member_state::make(std::string name, Member member) {
member_index index{member_type_data::get<Member>(), std::move(name)};
return std::make_shared<member_state>(std::move(index), std::move(member));
}
template < member_kind Member >
member_state::member_state(member_index index, Member member)
: index{std::move(index)}
, getter{make_member_getter(member)}
, setter{make_member_setter(member)} {}
}
namespace meta_hpp
{
inline member::member(detail::member_state_ptr state)
: state_{std::move(state)} {}
inline bool member::is_valid() const noexcept {
return !!state_;
}
inline member::operator bool() const noexcept {
return is_valid();
}
inline const member_index& member::get_index() const noexcept {
return state_->index;
}
inline const member_type& member::get_type() const noexcept {
return state_->index.type;
}
inline const std::string& member::get_name() const noexcept {
return state_->index.name;
}
template < typename Instance >
value member::get(Instance&& instance) const {
return state_->getter(detail::inst{std::forward<Instance>(instance)});
}
template < typename Instance, typename Value >
void member::set(Instance&& instance, Value&& value) const {
state_->setter(detail::inst{std::forward<Instance>(instance)}, detail::arg{std::forward<Value>(value)});
}
}

View File

@@ -0,0 +1,176 @@
/*******************************************************************************
* This file is part of the "https://github.com/blackmatov/meta.hpp"
* For conditions of distribution and use, see copyright notice in LICENSE.md
* Copyright (C) 2021, by Matvey Cherevko (blackmatov@gmail.com)
******************************************************************************/
#pragma once
#include "../meta_base.hpp"
#include "../meta_states.hpp"
#include "../meta_types/method_type.hpp"
namespace meta_hpp::detail
{
template < method_kind Method, std::size_t... Is >
std::optional<value> raw_method_invoke_impl(
Method method,
const inst& inst,
const arg* args,
std::index_sequence<Is...>)
{
using mt = method_traits<Method>;
using return_type = typename mt::return_type;
using qualified_type = typename mt::qualified_type;
using argument_types = typename mt::argument_types;
if ( !inst.can_cast_to<qualified_type>() ) {
throw std::logic_error("an attempt to call a method with an incorrect instance type");
}
if ( !(... && (args + Is)->can_cast_to<type_list_at_t<Is, argument_types>>()) ) {
throw std::logic_error("an attempt to call a method with an incorrect argument types");
}
if constexpr ( std::is_void_v<return_type> ) {
std::invoke(method,
inst.cast<qualified_type>(),
(args + Is)->cast<type_list_at_t<Is, argument_types>>()...);
return std::nullopt;
} else {
return_type return_value{std::invoke(method,
inst.cast<qualified_type>(),
(args + Is)->cast<type_list_at_t<Is, argument_types>>()...)};
return value{std::forward<return_type>(return_value)};
}
}
template < method_kind Method >
std::optional<value> raw_method_invoke(
Method method,
const inst& inst,
const arg* args,
std::size_t arg_count)
{
using mt = method_traits<Method>;
if ( arg_count != mt::arity ) {
throw std::logic_error("an attempt to call a method with an incorrect arity");
}
return raw_method_invoke_impl<Method>(
method,
inst,
args,
std::make_index_sequence<mt::arity>());
}
template < method_kind Method >
method_state::invoke_impl make_method_invoke(Method method) {
using namespace std::placeholders;
return std::bind(&raw_method_invoke<Method>, method, _1, _2, _3);
}
}
namespace meta_hpp::detail
{
template < method_kind Method, std::size_t... Is >
bool raw_method_is_invocable_with_impl(
const inst_base& inst_base,
const arg_base* arg_bases,
std::index_sequence<Is...>)
{
using mt = method_traits<Method>;
using qualified_type = typename mt::qualified_type;
using argument_types = typename mt::argument_types;
return inst_base.can_cast_to<qualified_type>()
&& (... && (arg_bases + Is)->can_cast_to<type_list_at_t<Is, argument_types>>() );
}
template < method_kind Method >
bool raw_method_is_invocable_with(
const inst_base& inst_base,
const arg_base* arg_bases,
std::size_t arg_count)
{
using mt = method_traits<Method>;
if ( arg_count != mt::arity ) {
return false;
}
return raw_method_is_invocable_with_impl<Method>(
inst_base,
arg_bases,
std::make_index_sequence<mt::arity>());
}
template < method_kind Method >
method_state::is_invocable_with_impl make_method_is_invocable_with() {
using namespace std::placeholders;
return std::bind(&raw_method_is_invocable_with<Method>, _1, _2, _3);
}
}
namespace meta_hpp::detail
{
template < method_kind Method >
method_state_ptr method_state::make(std::string name, Method method) {
method_index index{method_type_data::get<Method>(), std::move(name)};
return std::make_shared<method_state>(std::move(index), std::move(method));
}
template < method_kind Method >
method_state::method_state(method_index index, Method method)
: index{std::move(index)}
, invoke{make_method_invoke(method)}
, is_invocable_with{make_method_is_invocable_with<Method>()} {}
}
namespace meta_hpp
{
inline method::method(detail::method_state_ptr state)
: state_{std::move(state)} {}
inline bool method::is_valid() const noexcept {
return !!state_;
}
inline method::operator bool() const noexcept {
return is_valid();
}
inline const method_index& method::get_index() const noexcept {
return state_->index;
}
inline const method_type& method::get_type() const noexcept {
return state_->index.type;
}
inline const std::string& method::get_name() const noexcept {
return state_->index.name;
}
template < typename Instance, typename... Args >
std::optional<value> method::invoke(Instance&& instance, Args&&... args) const {
if constexpr ( sizeof...(Args) > 0 ) {
std::array<detail::arg, sizeof...(Args)> vargs{detail::arg{std::forward<Args>(args)}...};
return state_->invoke(detail::inst{std::forward<Instance>(instance)}, vargs.data(), vargs.size());
} else {
return state_->invoke(detail::inst{std::forward<Instance>(instance)}, nullptr, 0);
}
}
template < typename Inst, typename... Args >
bool method::is_invocable_with() const noexcept {
if constexpr ( sizeof...(Args) > 0 ) {
std::array<detail::arg_base, sizeof...(Args)> arg_bases{detail::arg_base{type_list<Args>{}}...};
return state_->is_invocable_with(detail::inst_base{type_list<Inst>{}}, arg_bases.data(), arg_bases.size());
} else {
return state_->is_invocable_with(detail::inst_base{type_list<Inst>{}}, nullptr, 0);
}
}
}

View File

@@ -0,0 +1,138 @@
/*******************************************************************************
* This file is part of the "https://github.com/blackmatov/meta.hpp"
* For conditions of distribution and use, see copyright notice in LICENSE.md
* Copyright (C) 2021, by Matvey Cherevko (blackmatov@gmail.com)
******************************************************************************/
#pragma once
#include "../meta_base.hpp"
#include "../meta_states.hpp"
namespace meta_hpp::detail
{
inline scope_state_ptr scope_state::get(std::string_view name) {
static std::map<std::string, scope_state_ptr, std::less<>> states;
if ( auto iter = states.find(name); iter != states.end() ) {
return iter->second;
}
auto state = std::make_shared<scope_state>(scope_index{std::string{name}});
return states.emplace(std::string{name}, state).first->second;
}
inline scope_state::scope_state(scope_index index)
: index{std::move(index)} {}
}
namespace meta_hpp
{
inline scope::scope(detail::scope_state_ptr state)
: state_{std::move(state)} {}
inline bool scope::is_valid() const noexcept {
return !!state_;
}
inline scope::operator bool() const noexcept {
return is_valid();
}
inline const scope_index& scope::get_index() const noexcept {
return state_->index;
}
inline const std::string& scope::get_name() const noexcept {
return state_->index.name;
}
inline const class_map& scope::get_classes() const noexcept {
return state_->classes;
}
inline const enum_map& scope::get_enums() const noexcept {
return state_->enums;
}
inline const function_map& scope::get_functions() const noexcept {
return state_->functions;
}
inline const variable_map& scope::get_variables() const noexcept {
return state_->variables;
}
inline class_type scope::get_class(std::string_view name) const noexcept {
if ( auto iter = state_->classes.find(name); iter != state_->classes.end() ) {
return iter->second;
}
return class_type{};
}
inline enum_type scope::get_enum(std::string_view name) const noexcept {
if ( auto iter = state_->enums.find(name); iter != state_->enums.end() ) {
return iter->second;
}
return enum_type{};
}
inline function scope::get_function(std::string_view name) const noexcept {
for ( auto&& [index, function] : state_->functions ) {
if ( index.name == name ) {
return function;
}
}
return function{};
}
inline variable scope::get_variable(std::string_view name) const noexcept {
for ( auto&& [index, variable] : state_->variables ) {
if ( index.name == name ) {
return variable;
}
}
return variable{};
}
template < typename... Args >
function scope::get_function_with(std::string_view name) const noexcept {
return get_function_with(name, {resolve_type<Args>()...});
}
inline function scope::get_function_with(std::string_view name, std::vector<any_type> args) const noexcept {
for ( auto&& [index, function] : state_->functions ) {
if ( index.name != name ) {
continue;
}
if ( function.get_type().get_arity() != args.size() ) {
continue;
}
const std::vector<any_type>& function_args = function.get_type().get_argument_types();
if ( std::equal(args.begin(), args.end(), function_args.begin(), function_args.end()) ) {
return function;
}
}
return function{};
}
inline function scope::get_function_with(std::string_view name, std::initializer_list<any_type> args) const noexcept {
for ( auto&& [index, function] : state_->functions ) {
if ( index.name != name ) {
continue;
}
if ( function.get_type().get_arity() != args.size() ) {
continue;
}
const std::vector<any_type>& function_args = function.get_type().get_argument_types();
if ( std::equal(args.begin(), args.end(), function_args.begin(), function_args.end()) ) {
return function;
}
}
return function{};
}
}

View File

@@ -0,0 +1,105 @@
/*******************************************************************************
* This file is part of the "https://github.com/blackmatov/meta.hpp"
* For conditions of distribution and use, see copyright notice in LICENSE.md
* Copyright (C) 2021, by Matvey Cherevko (blackmatov@gmail.com)
******************************************************************************/
#pragma once
#include "../meta_base.hpp"
#include "../meta_states.hpp"
#include "../meta_types/pointer_type.hpp"
namespace meta_hpp::detail
{
template < pointer_kind Pointer >
value raw_variable_getter(Pointer pointer) {
using pt = pointer_traits<Pointer>;
using data_type = typename pt::data_type;
data_type return_value{*pointer};
return value{std::forward<data_type>(return_value)};
}
template < pointer_kind Pointer >
void raw_variable_setter([[maybe_unused]] Pointer pointer, const arg& arg) {
using pt = pointer_traits<Pointer>;
using data_type = typename pt::data_type;
if constexpr ( !std::is_const_v<data_type> ) {
if ( !arg.can_cast_to<data_type>() ) {
throw std::logic_error("an attempt to set a variable with an incorrect argument type");
}
*pointer = arg.cast<data_type>();
} else {
throw std::logic_error("an attempt to set a constant variable");
}
}
}
namespace meta_hpp::detail
{
template < pointer_kind Pointer >
variable_state::getter_impl make_variable_getter(Pointer pointer) {
using namespace std::placeholders;
return std::bind(&raw_variable_getter<Pointer>, pointer);
}
template < pointer_kind Pointer >
variable_state::setter_impl make_variable_setter(Pointer pointer) {
using namespace std::placeholders;
return std::bind(&raw_variable_setter<Pointer>, pointer, _1);
}
}
namespace meta_hpp::detail
{
template < pointer_kind Pointer >
variable_state_ptr variable_state::make(std::string name, Pointer pointer) {
variable_index index{pointer_type_data::get<Pointer>(), std::move(name)};
return std::make_shared<variable_state>(index, pointer);
}
template < pointer_kind Pointer >
variable_state::variable_state(variable_index index, Pointer pointer)
: index{std::move(index)}
, getter{make_variable_getter(pointer)}
, setter{make_variable_setter(pointer)} {}
}
namespace meta_hpp
{
inline variable::variable(detail::variable_state_ptr state)
: state_{std::move(state)} {}
inline bool variable::is_valid() const noexcept {
return !!state_;
}
inline variable::operator bool() const noexcept {
return is_valid();
}
inline const variable_index& variable::get_index() const noexcept {
return state_->index;
}
inline const pointer_type& variable::get_type() const noexcept {
return state_->index.type;
}
inline const std::string& variable::get_name() const noexcept {
return state_->index.name;
}
inline value variable::get() const {
return state_->getter();
}
template < typename Value >
void variable::set(Value&& value) const {
state_->setter(detail::arg{std::forward<Value>(value)});
}
}

View File

@@ -0,0 +1,722 @@
/*******************************************************************************
* This file is part of the "https://github.com/blackmatov/meta.hpp"
* For conditions of distribution and use, see copyright notice in LICENSE.md
* Copyright (C) 2021, by Matvey Cherevko (blackmatov@gmail.com)
******************************************************************************/
#pragma once
#include "meta_base.hpp"
#include "meta_traits.hpp"
namespace meta_hpp
{
class type_id final {
public:
template < typename T >
explicit type_id(type_list<T>) noexcept
: id_{type_to_id<T>()} {}
type_id(type_id&&) = default;
type_id& operator=(type_id&&) = default;
type_id(const type_id&) = default;
type_id& operator=(const type_id&) = default;
std::size_t get_hash() const noexcept {
return std::hash<underlying_type>{}(id_);
}
friend bool operator<(type_id l, type_id r) noexcept {
return l.id_ < r.id_;
}
friend bool operator==(type_id l, type_id r) noexcept {
return l.id_ == r.id_;
}
friend bool operator!=(type_id l, type_id r) noexcept {
return l.id_ != r.id_;
}
private:
using underlying_type = std::uint32_t;
underlying_type id_{};
private:
static underlying_type next() noexcept {
static std::atomic<underlying_type> id{};
return ++id;
}
template < typename T >
static underlying_type type_to_id() noexcept {
static const underlying_type id{next()};
return id;
}
};
}
namespace meta_hpp
{
template < typename T >
concept types_family =
std::same_as<T, any_type> ||
std::same_as<T, array_type> ||
std::same_as<T, class_type> ||
std::same_as<T, ctor_type> ||
std::same_as<T, enum_type> ||
std::same_as<T, function_type> ||
std::same_as<T, member_type> ||
std::same_as<T, method_type> ||
std::same_as<T, number_type> ||
std::same_as<T, pointer_type> ||
std::same_as<T, reference_type> ||
std::same_as<T, void_type>;
template < types_family T >
bool operator<(type_id l, const T& r) noexcept {
return static_cast<bool>(r) && l < r.get_id();
}
template < types_family T >
bool operator<(const T& l, type_id r) noexcept {
return !static_cast<bool>(l) || l.get_id() < r;
}
template < types_family T, types_family U >
bool operator<(const T& l, const U& r) noexcept {
if ( !static_cast<bool>(r) ) {
return false;
}
if ( !static_cast<bool>(l) ) {
return true;
}
return l.get_id() < r.get_id();
}
template < types_family T >
bool operator==(type_id l, const T& r) noexcept {
return static_cast<bool>(r) && l == r.get_id();
}
template < types_family T >
bool operator==(const T& l, type_id r) noexcept {
return static_cast<bool>(l) && l.get_id() == r;
}
template < types_family T, types_family U >
bool operator==(const T& l, const U& r) noexcept {
if ( static_cast<bool>(l) != static_cast<bool>(r) ) {
return false;
}
if ( !static_cast<bool>(l) ) {
return true;
}
return l.get_id() == r.get_id();
}
template < types_family T >
bool operator!=(type_id l, const T& r) noexcept {
return !(l == r);
}
template < types_family T >
bool operator!=(const T& l, type_id r) noexcept {
return !(l == r);
}
template < types_family T, types_family U >
bool operator!=(const T& l, const U& r) noexcept {
return !(l == r);
}
}
namespace meta_hpp
{
class any_type final {
public:
explicit any_type() = default;
explicit any_type(detail::type_data_base_ptr data);
bool is_valid() const noexcept;
explicit operator bool() const noexcept;
type_id get_id() const noexcept;
type_kind get_kind() const noexcept;
any_type(const array_type& other) noexcept;
any_type(const class_type& other) noexcept;
any_type(const ctor_type& other) noexcept;
any_type(const enum_type& other) noexcept;
any_type(const function_type& other) noexcept;
any_type(const member_type& other) noexcept;
any_type(const method_type& other) noexcept;
any_type(const number_type& other) noexcept;
any_type(const pointer_type& other) noexcept;
any_type(const reference_type& other) noexcept;
any_type(const void_type& other) noexcept;
bool is_array() const noexcept;
bool is_class() const noexcept;
bool is_ctor() const noexcept;
bool is_enum() const noexcept;
bool is_function() const noexcept;
bool is_member() const noexcept;
bool is_method() const noexcept;
bool is_number() const noexcept;
bool is_pointer() const noexcept;
bool is_reference() const noexcept;
bool is_void() const noexcept;
array_type as_array() const noexcept;
class_type as_class() const noexcept;
ctor_type as_ctor() const noexcept;
enum_type as_enum() const noexcept;
function_type as_function() const noexcept;
member_type as_member() const noexcept;
method_type as_method() const noexcept;
number_type as_number() const noexcept;
pointer_type as_pointer() const noexcept;
reference_type as_reference() const noexcept;
void_type as_void() const noexcept;
private:
detail::type_data_base_ptr data_;
};
class array_type final {
public:
array_type() = default;
array_type(detail::array_type_data_ptr data);
bool is_valid() const noexcept;
explicit operator bool() const noexcept;
type_id get_id() const noexcept;
bitflags<array_flags> get_flags() const noexcept;
std::size_t get_extent() const noexcept;
any_type get_data_type() const noexcept;
private:
friend class any_type;
detail::array_type_data_ptr data_;
};
class class_type final {
public:
class_type() = default;
class_type(detail::class_type_data_ptr data);
bool is_valid() const noexcept;
explicit operator bool() const noexcept;
type_id get_id() const noexcept;
bitflags<class_flags> get_flags() const noexcept;
std::size_t get_size() const noexcept;
std::size_t get_arity() const noexcept;
any_type get_argument_type(std::size_t index) const noexcept;
const std::vector<any_type>& get_argument_types() const noexcept;
const ctor_map& get_ctors() const noexcept;
const class_set& get_bases() const noexcept;
const function_map& get_functions() const noexcept;
const member_map& get_members() const noexcept;
const method_map& get_methods() const noexcept;
const variable_map& get_variables() const noexcept;
template < class_kind Derived >
bool is_base_of() const noexcept;
bool is_base_of(const class_type& derived) const noexcept;
template < class_kind Base >
bool is_derived_from() const noexcept;
bool is_derived_from(const class_type& base) const noexcept;
function get_function(std::string_view name) const noexcept;
member get_member(std::string_view name) const noexcept;
method get_method(std::string_view name) const noexcept;
variable get_variable(std::string_view name) const noexcept;
template < typename... Args >
ctor get_ctor_with() const noexcept;
ctor get_ctor_with(std::vector<any_type> args) const noexcept;
ctor get_ctor_with(std::initializer_list<any_type> args) const noexcept;
template < typename... Args >
function get_function_with(std::string_view name) const noexcept;
function get_function_with(std::string_view name, std::vector<any_type> args) const noexcept;
function get_function_with(std::string_view name, std::initializer_list<any_type> args) const noexcept;
template < typename... Args >
method get_method_with(std::string_view name) const noexcept;
method get_method_with(std::string_view name, std::vector<any_type> args) const noexcept;
method get_method_with(std::string_view name, std::initializer_list<any_type> args) const noexcept;
private:
friend class any_type;
detail::class_type_data_ptr data_;
};
class ctor_type final {
public:
ctor_type() = default;
ctor_type(detail::ctor_type_data_ptr data);
bool is_valid() const noexcept;
explicit operator bool() const noexcept;
type_id get_id() const noexcept;
bitflags<ctor_flags> get_flags() const noexcept;
std::size_t get_arity() const noexcept;
any_type get_class_type() const noexcept;
any_type get_argument_type(std::size_t index) const noexcept;
const std::vector<any_type>& get_argument_types() const noexcept;
private:
friend class any_type;
detail::ctor_type_data_ptr data_;
};
class enum_type final {
public:
enum_type() = default;
enum_type(detail::enum_type_data_ptr data);
bool is_valid() const noexcept;
explicit operator bool() const noexcept;
type_id get_id() const noexcept;
bitflags<enum_flags> get_flags() const noexcept;
number_type get_underlying_type() const noexcept;
const evalue_map& get_evalues() const noexcept;
evalue get_evalue(std::string_view name) const noexcept;
template < typename Value >
std::optional<std::string> value_to_name(Value&& value) const noexcept;
std::optional<value> name_to_value(std::string_view name) const noexcept;
private:
friend class any_type;
detail::enum_type_data_ptr data_;
};
class function_type final {
public:
function_type() = default;
function_type(detail::function_type_data_ptr data);
bool is_valid() const noexcept;
explicit operator bool() const noexcept;
type_id get_id() const noexcept;
bitflags<function_flags> get_flags() const noexcept;
std::size_t get_arity() const noexcept;
any_type get_return_type() const noexcept;
any_type get_argument_type(std::size_t index) const noexcept;
const std::vector<any_type>& get_argument_types() const noexcept;
private:
friend class any_type;
detail::function_type_data_ptr data_;
};
class member_type final {
public:
member_type() = default;
member_type(detail::member_type_data_ptr data);
bool is_valid() const noexcept;
explicit operator bool() const noexcept;
type_id get_id() const noexcept;
bitflags<member_flags> get_flags() const noexcept;
class_type get_owner_type() const noexcept;
any_type get_value_type() const noexcept;
private:
friend class any_type;
detail::member_type_data_ptr data_;
};
class method_type final {
public:
method_type() = default;
method_type(detail::method_type_data_ptr data);
bool is_valid() const noexcept;
explicit operator bool() const noexcept;
type_id get_id() const noexcept;
bitflags<method_flags> get_flags() const noexcept;
std::size_t get_arity() const noexcept;
class_type get_owner_type() const noexcept;
any_type get_return_type() const noexcept;
any_type get_argument_type(std::size_t index) const noexcept;
const std::vector<any_type>& get_argument_types() const noexcept;
private:
friend class any_type;
detail::method_type_data_ptr data_;
};
class number_type final {
public:
number_type() = default;
number_type(detail::number_type_data_ptr data);
bool is_valid() const noexcept;
explicit operator bool() const noexcept;
type_id get_id() const noexcept;
bitflags<number_flags> get_flags() const noexcept;
std::size_t get_size() const noexcept;
private:
friend class any_type;
detail::number_type_data_ptr data_;
};
class pointer_type final {
public:
pointer_type() = default;
pointer_type(detail::pointer_type_data_ptr data);
bool is_valid() const noexcept;
explicit operator bool() const noexcept;
type_id get_id() const noexcept;
bitflags<pointer_flags> get_flags() const noexcept;
any_type get_data_type() const noexcept;
private:
friend class any_type;
detail::pointer_type_data_ptr data_;
};
class reference_type final {
public:
reference_type() = default;
reference_type(detail::reference_type_data_ptr data);
bool is_valid() const noexcept;
explicit operator bool() const noexcept;
type_id get_id() const noexcept;
bitflags<reference_flags> get_flags() const noexcept;
any_type get_data_type() const noexcept;
private:
friend class any_type;
detail::reference_type_data_ptr data_;
};
class void_type final {
public:
void_type() = default;
void_type(detail::void_type_data_ptr data);
bool is_valid() const noexcept;
explicit operator bool() const noexcept;
type_id get_id() const noexcept;
bitflags<void_flags> get_flags() const noexcept;
private:
friend class any_type;
detail::void_type_data_ptr data_;
};
}
namespace meta_hpp::detail
{
struct type_data_base {
const type_id id;
const type_kind kind;
explicit type_data_base(type_id id, type_kind kind)
: id{id}
, kind{kind} {}
};
struct array_type_data final : type_data_base {
const bitflags<array_flags> flags;
const std::size_t extent;
const any_type data_type;
template < array_kind Array >
static array_type_data_ptr get();
template < array_kind Array >
explicit array_type_data(type_list<Array>);
};
struct class_type_data final : type_data_base {
const bitflags<class_flags> flags;
const std::size_t size;
const std::vector<any_type> argument_types;
ctor_map ctors;
class_set bases;
function_map functions;
member_map members;
method_map methods;
variable_map variables;
template < class_kind Class >
static class_type_data_ptr get();
template < class_kind Class >
explicit class_type_data(type_list<Class>);
};
struct ctor_type_data final : type_data_base {
const bitflags<ctor_flags> flags;
const any_type class_type;
const std::vector<any_type> argument_types;
template < class_kind Class, typename... Args >
static ctor_type_data_ptr get();
template < class_kind Class, typename... Args >
explicit ctor_type_data(type_list<Class>, type_list<Args...>);
};
struct enum_type_data final : type_data_base {
const bitflags<enum_flags> flags;
const number_type underlying_type;
evalue_map evalues;
template < enum_kind Enum >
static enum_type_data_ptr get();
template < enum_kind Enum >
explicit enum_type_data(type_list<Enum>);
};
struct function_type_data final : type_data_base {
const bitflags<function_flags> flags;
const any_type return_type;
const std::vector<any_type> argument_types;
template < function_kind Function >
static function_type_data_ptr get();
template < function_kind Function >
explicit function_type_data(type_list<Function>);
};
struct member_type_data final : type_data_base {
const bitflags<member_flags> flags;
const class_type owner_type;
const any_type value_type;
template < member_kind Member >
static member_type_data_ptr get();
template < member_kind Member >
explicit member_type_data(type_list<Member>);
};
struct method_type_data final : type_data_base {
const bitflags<method_flags> flags;
const class_type owner_type;
const any_type return_type;
const std::vector<any_type> argument_types;
template < method_kind Method >
static method_type_data_ptr get();
template < method_kind Method >
explicit method_type_data(type_list<Method>);
};
struct number_type_data final : type_data_base {
const bitflags<number_flags> flags;
const std::size_t size;
template < number_kind Number >
static number_type_data_ptr get();
template < number_kind Number >
explicit number_type_data(type_list<Number>);
};
struct pointer_type_data final : type_data_base {
const bitflags<pointer_flags> flags;
const any_type data_type;
template < pointer_kind Pointer >
static pointer_type_data_ptr get();
template < pointer_kind Pointer >
explicit pointer_type_data(type_list<Pointer>);
};
struct reference_type_data final : type_data_base {
const bitflags<reference_flags> flags;
const any_type data_type;
template < reference_kind Reference >
static reference_type_data_ptr get();
template < reference_kind Reference >
explicit reference_type_data(type_list<Reference>);
};
struct void_type_data final : type_data_base {
const bitflags<void_flags> flags;
template < void_kind Void >
static void_type_data_ptr get();
template < void_kind Void >
explicit void_type_data(type_list<Void>);
};
}
namespace meta_hpp
{
struct ctor_index final {
const ctor_type type;
explicit ctor_index(ctor_type type)
: type{std::move(type)} {}
friend bool operator<(const ctor_index& l, const ctor_index& r) noexcept {
return l.type < r.type;
}
friend bool operator==(const ctor_index& l, const ctor_index& r) noexcept {
return l.type == r.type;
}
};
struct evalue_index final {
const enum_type type;
const std::string name;
explicit evalue_index(enum_type type, std::string name)
: type{std::move(type)}
, name{std::move(name)} {}
friend bool operator<(const evalue_index& l, const evalue_index& r) noexcept {
return std::tie(l.type, l.name) < std::tie(r.type, r.name);
}
friend bool operator==(const evalue_index& l, const evalue_index& r) noexcept {
return std::tie(l.type, l.name) == std::tie(r.type, r.name);
}
};
struct function_index final {
const function_type type;
const std::string name;
explicit function_index(function_type type, std::string name)
: type{std::move(type)}
, name{std::move(name)} {}
friend bool operator<(const function_index& l, const function_index& r) noexcept {
return std::tie(l.type, l.name) < std::tie(r.type, r.name);
}
friend bool operator==(const function_index& l, const function_index& r) noexcept {
return std::tie(l.type, l.name) == std::tie(r.type, r.name);
}
};
struct member_index final {
const member_type type;
const std::string name;
explicit member_index(member_type type, std::string name)
: type{std::move(type)}
, name{std::move(name)} {}
friend bool operator<(const member_index& l, const member_index& r) noexcept {
return std::tie(l.type, l.name) < std::tie(r.type, r.name);
}
friend bool operator==(const member_index& l, const member_index& r) noexcept {
return std::tie(l.type, l.name) == std::tie(r.type, r.name);
}
};
struct method_index final {
const method_type type;
const std::string name;
explicit method_index(method_type type, std::string name)
: type{std::move(type)}
, name{std::move(name)} {}
friend bool operator<(const method_index& l, const method_index& r) noexcept {
return std::tie(l.type, l.name) < std::tie(r.type, r.name);
}
friend bool operator==(const method_index& l, const method_index& r) noexcept {
return std::tie(l.type, l.name) == std::tie(r.type, r.name);
}
};
struct scope_index final {
const std::string name;
explicit scope_index(std::string name)
: name{std::move(name)} {}
friend bool operator<(const scope_index& l, const scope_index& r) noexcept {
return l.name < r.name;
}
friend bool operator==(const scope_index& l, const scope_index& r) noexcept {
return l.name == r.name;
}
};
struct variable_index final {
const pointer_type type;
const std::string name;
explicit variable_index(pointer_type type, std::string name)
: type{std::move(type)}
, name{std::move(name)} {}
friend bool operator<(const variable_index& l, const variable_index& r) noexcept {
return std::tie(l.type, l.name) < std::tie(r.type, r.name);
}
friend bool operator==(const variable_index& l, const variable_index& r) noexcept {
return std::tie(l.type, l.name) == std::tie(r.type, r.name);
}
};
}
namespace meta_hpp
{
namespace detail
{
template < typename T >
kind_type_data_ptr<T> get_type_data() {
static_assert(!std::is_const_v<T> && !std::is_volatile_v<T>);
return kind_type_data<T>::template get<T>();
}
}
template < typename T >
auto resolve_type() {
using raw_type = std::remove_cv_t<T>;
return detail::kind_type<raw_type>{detail::get_type_data<raw_type>()};
}
template < typename T >
auto resolve_type(T&&) {
using raw_type = std::remove_cvref_t<T>;
return detail::kind_type<raw_type>{detail::get_type_data<raw_type>()};
};
}

View File

@@ -0,0 +1,169 @@
/*******************************************************************************
* This file is part of the "https://github.com/blackmatov/meta.hpp"
* For conditions of distribution and use, see copyright notice in LICENSE.md
* Copyright (C) 2021, by Matvey Cherevko (blackmatov@gmail.com)
******************************************************************************/
#pragma once
#include "../meta_base.hpp"
#include "../meta_types.hpp"
namespace meta_hpp
{
inline any_type::any_type(detail::type_data_base_ptr data)
: data_{std::move(data)} {}
inline bool any_type::is_valid() const noexcept {
return !!data_;
}
inline any_type::operator bool() const noexcept {
return is_valid();
}
inline type_id any_type::get_id() const noexcept {
return data_->id;
}
inline type_kind any_type::get_kind() const noexcept {
return data_->kind;
}
inline any_type::any_type(const array_type& other) noexcept
: data_{other.data_} {}
inline any_type::any_type(const class_type& other) noexcept
: data_{other.data_} {}
inline any_type::any_type(const ctor_type& other) noexcept
: data_{other.data_} {}
inline any_type::any_type(const enum_type& other) noexcept
: data_{other.data_} {}
inline any_type::any_type(const function_type& other) noexcept
: data_{other.data_} {}
inline any_type::any_type(const member_type& other) noexcept
: data_{other.data_} {}
inline any_type::any_type(const method_type& other) noexcept
: data_{other.data_} {}
inline any_type::any_type(const number_type& other) noexcept
: data_{other.data_} {}
inline any_type::any_type(const pointer_type& other) noexcept
: data_{other.data_} {}
inline any_type::any_type(const reference_type& other) noexcept
: data_{other.data_} {}
inline any_type::any_type(const void_type& other) noexcept
: data_{other.data_} {}
inline bool any_type::is_array() const noexcept {
return data_ && data_->kind == type_kind::array_;
}
inline bool any_type::is_class() const noexcept {
return data_ && data_->kind == type_kind::class_;
}
inline bool any_type::is_ctor() const noexcept {
return data_ && data_->kind == type_kind::ctor_;
}
inline bool any_type::is_enum() const noexcept {
return data_ && data_->kind == type_kind::enum_;
}
inline bool any_type::is_function() const noexcept {
return data_ && data_->kind == type_kind::function_;
}
inline bool any_type::is_member() const noexcept {
return data_ && data_->kind == type_kind::member_;
}
inline bool any_type::is_method() const noexcept {
return data_ && data_->kind == type_kind::method_;
}
inline bool any_type::is_number() const noexcept {
return data_ && data_->kind == type_kind::number_;
}
inline bool any_type::is_pointer() const noexcept {
return data_ && data_->kind == type_kind::pointer_;
}
inline bool any_type::is_reference() const noexcept {
return data_ && data_->kind == type_kind::reference_;
}
inline bool any_type::is_void() const noexcept {
return data_ && data_->kind == type_kind::void_;
}
inline array_type any_type::as_array() const noexcept {
return is_array()
? array_type{std::static_pointer_cast<detail::array_type_data>(data_)}
: array_type{};
}
inline class_type any_type::as_class() const noexcept {
return is_class()
? class_type{std::static_pointer_cast<detail::class_type_data>(data_)}
: class_type{};
}
inline enum_type any_type::as_enum() const noexcept {
return is_enum()
? enum_type{std::static_pointer_cast<detail::enum_type_data>(data_)}
: enum_type{};
}
inline function_type any_type::as_function() const noexcept {
return is_function()
? function_type{std::static_pointer_cast<detail::function_type_data>(data_)}
: function_type{};
}
inline member_type any_type::as_member() const noexcept {
return is_member()
? member_type{std::static_pointer_cast<detail::member_type_data>(data_)}
: member_type{};
}
inline method_type any_type::as_method() const noexcept {
return is_method()
? method_type{std::static_pointer_cast<detail::method_type_data>(data_)}
: method_type{};
}
inline number_type any_type::as_number() const noexcept {
return is_number()
? number_type{std::static_pointer_cast<detail::number_type_data>(data_)}
: number_type{};
}
inline pointer_type any_type::as_pointer() const noexcept {
return is_pointer()
? pointer_type{std::static_pointer_cast<detail::pointer_type_data>(data_)}
: pointer_type{};
}
inline reference_type any_type::as_reference() const noexcept {
return is_reference()
? reference_type{std::static_pointer_cast<detail::reference_type_data>(data_)}
: reference_type{};
}
inline void_type any_type::as_void() const noexcept {
return is_void()
? void_type{std::static_pointer_cast<detail::void_type_data>(data_)}
: void_type{};
}
}

View File

@@ -0,0 +1,61 @@
/*******************************************************************************
* This file is part of the "https://github.com/blackmatov/meta.hpp"
* For conditions of distribution and use, see copyright notice in LICENSE.md
* Copyright (C) 2021, by Matvey Cherevko (blackmatov@gmail.com)
******************************************************************************/
#pragma once
#include "../meta_base.hpp"
#include "../meta_types.hpp"
#include "../meta_traits/array_traits.hpp"
namespace meta_hpp::detail
{
template < array_kind Array >
struct array_tag {};
template < array_kind Array >
array_type_data_ptr array_type_data::get() {
static array_type_data_ptr data = std::make_shared<array_type_data>(type_list<Array>{});
return data;
}
template < array_kind Array >
array_type_data::array_type_data(type_list<Array>)
: type_data_base{type_id{type_list<array_tag<Array>>{}}, type_kind::array_}
, flags{array_traits<Array>::make_flags()}
, extent{array_traits<Array>::extent}
, data_type{resolve_type<typename array_traits<Array>::data_type>()} {}
}
namespace meta_hpp
{
inline array_type::array_type(detail::array_type_data_ptr data)
: data_{std::move(data)} {}
inline bool array_type::is_valid() const noexcept {
return !!data_;
}
inline array_type::operator bool() const noexcept {
return is_valid();
}
inline type_id array_type::get_id() const noexcept {
return data_->id;
}
inline bitflags<array_flags> array_type::get_flags() const noexcept {
return data_->flags;
}
inline std::size_t array_type::get_extent() const noexcept {
return data_->extent;
}
inline any_type array_type::get_data_type() const noexcept {
return data_->data_type;
}
}

View File

@@ -0,0 +1,332 @@
/*******************************************************************************
* This file is part of the "https://github.com/blackmatov/meta.hpp"
* For conditions of distribution and use, see copyright notice in LICENSE.md
* Copyright (C) 2021, by Matvey Cherevko (blackmatov@gmail.com)
******************************************************************************/
#pragma once
#include "../meta_base.hpp"
#include "../meta_types.hpp"
#include "../meta_traits/class_traits.hpp"
namespace meta_hpp::detail
{
template < class_kind Class >
struct class_tag {};
template < class_kind Class >
class_type_data_ptr class_type_data::get() {
static class_type_data_ptr data = std::make_shared<class_type_data>(type_list<Class>{});
return data;
}
template < class_kind Class >
class_type_data::class_type_data(type_list<Class>)
: type_data_base{type_id{type_list<class_tag<Class>>{}}, type_kind::class_}
, flags{class_traits<Class>::make_flags()}
, size{class_traits<Class>::size}
, argument_types{class_traits<Class>::make_argument_types()} {}
}
namespace meta_hpp
{
inline class_type::class_type(detail::class_type_data_ptr data)
: data_{std::move(data)} {}
inline bool class_type::is_valid() const noexcept {
return !!data_;
}
inline class_type::operator bool() const noexcept {
return is_valid();
}
inline type_id class_type::get_id() const noexcept {
return data_->id;
}
inline bitflags<class_flags> class_type::get_flags() const noexcept {
return data_->flags;
}
inline std::size_t class_type::get_size() const noexcept {
return data_->size;
}
inline std::size_t class_type::get_arity() const noexcept {
return data_->argument_types.size();
}
inline any_type class_type::get_argument_type(std::size_t index) const noexcept {
return index < data_->argument_types.size() ? data_->argument_types[index] : any_type{};
}
inline const std::vector<any_type>& class_type::get_argument_types() const noexcept {
return data_->argument_types;
}
inline const ctor_map& class_type::get_ctors() const noexcept {
return data_->ctors;
}
inline const class_set& class_type::get_bases() const noexcept {
return data_->bases;
}
inline const function_map& class_type::get_functions() const noexcept {
return data_->functions;
}
inline const member_map& class_type::get_members() const noexcept {
return data_->members;
}
inline const method_map& class_type::get_methods() const noexcept {
return data_->methods;
}
inline const variable_map& class_type::get_variables() const noexcept {
return data_->variables;
}
template < class_kind Derived >
bool class_type::is_base_of() const noexcept {
return is_base_of(resolve_type<Derived>());
}
inline bool class_type::is_base_of(const class_type& derived) const noexcept {
return derived.data_ && derived.data_->bases.contains(*this);
}
template < class_kind Base >
bool class_type::is_derived_from() const noexcept {
return is_derived_from(resolve_type<Base>());
}
inline bool class_type::is_derived_from(const class_type& base) const noexcept {
return data_ && data_->bases.contains(base);
}
inline function class_type::get_function(std::string_view name) const noexcept {
for ( auto&& [index, function] : data_->functions ) {
if ( index.name == name ) {
return function;
}
}
for ( auto&& base : data_->bases ) {
if ( function function = base.get_function(name); function ) {
return function;
}
}
return function{};
}
inline member class_type::get_member(std::string_view name) const noexcept {
for ( auto&& [index, member] : data_->members ) {
if ( index.name == name ) {
return member;
}
}
for ( auto&& base : data_->bases ) {
if ( member member = base.get_member(name); member ) {
return member;
}
}
return member{};
}
inline method class_type::get_method(std::string_view name) const noexcept {
for ( auto&& [index, method] : data_->methods ) {
if ( index.name == name ) {
return method;
}
}
for ( auto&& base : data_->bases ) {
if ( method method = base.get_method(name); method ) {
return method;
}
}
return method{};
}
inline variable class_type::get_variable(std::string_view name) const noexcept {
for ( auto&& [index, variable] : data_->variables ) {
if ( index.name == name ) {
return variable;
}
}
for ( auto&& base : data_->bases ) {
if ( variable variable = base.get_variable(name); variable ) {
return variable;
}
}
return variable{};
}
//
// get_ctor_with
//
template < typename... Args >
ctor class_type::get_ctor_with() const noexcept {
return get_ctor_with({resolve_type<Args>()...});
}
inline ctor class_type::get_ctor_with(std::vector<any_type> args) const noexcept {
for ( auto&& [index, ctor] : data_->ctors ) {
if ( ctor.get_type().get_arity() != args.size() ) {
continue;
}
const std::vector<any_type>& ctor_args = ctor.get_type().get_argument_types();
if ( std::equal(args.begin(), args.end(), ctor_args.begin(), ctor_args.end()) ) {
return ctor;
}
}
return ctor{};
}
inline ctor class_type::get_ctor_with(std::initializer_list<any_type> args) const noexcept {
for ( auto&& [index, ctor] : data_->ctors ) {
if ( ctor.get_type().get_arity() != args.size() ) {
continue;
}
const std::vector<any_type>& ctor_args = ctor.get_type().get_argument_types();
if ( std::equal(args.begin(), args.end(), ctor_args.begin(), ctor_args.end()) ) {
return ctor;
}
}
return ctor{};
}
//
// get_function_with
//
template < typename... Args >
function class_type::get_function_with(std::string_view name) const noexcept {
return get_function_with(name, {resolve_type<Args>()...});
}
inline function class_type::get_function_with(std::string_view name, std::vector<any_type> args) const noexcept {
for ( auto&& [index, function] : data_->functions ) {
if ( index.name != name ) {
continue;
}
if ( function.get_type().get_arity() != args.size() ) {
continue;
}
const std::vector<any_type>& function_args = function.get_type().get_argument_types();
if ( std::equal(args.begin(), args.end(), function_args.begin(), function_args.end()) ) {
return function;
}
}
for ( auto&& base : data_->bases ) {
if ( function function = base.get_function_with(name, args); function ) {
return function;
}
}
return function{};
}
inline function class_type::get_function_with(std::string_view name, std::initializer_list<any_type> args) const noexcept {
for ( auto&& [index, function] : data_->functions ) {
if ( index.name != name ) {
continue;
}
if ( function.get_type().get_arity() != args.size() ) {
continue;
}
const std::vector<any_type>& function_args = function.get_type().get_argument_types();
if ( std::equal(args.begin(), args.end(), function_args.begin(), function_args.end()) ) {
return function;
}
}
for ( auto&& base : data_->bases ) {
if ( function function = base.get_function_with(name, args); function ) {
return function;
}
}
return function{};
}
//
// get_method_with
//
template < typename... Args >
method class_type::get_method_with(std::string_view name) const noexcept {
return get_method_with(name, {resolve_type<Args>()...});
}
inline method class_type::get_method_with(std::string_view name, std::vector<any_type> args) const noexcept {
for ( auto&& [index, method] : data_->methods ) {
if ( index.name != name ) {
continue;
}
if ( method.get_type().get_arity() != args.size() ) {
continue;
}
const std::vector<any_type>& method_args = method.get_type().get_argument_types();
if ( std::equal(args.begin(), args.end(), method_args.begin(), method_args.end()) ) {
return method;
}
}
for ( auto&& base : data_->bases ) {
if ( method method = base.get_method_with(name, args); method ) {
return method;
}
}
return method{};
}
inline method class_type::get_method_with(std::string_view name, std::initializer_list<any_type> args) const noexcept {
for ( auto&& [index, method] : data_->methods ) {
if ( index.name != name ) {
continue;
}
if ( method.get_type().get_arity() != args.size() ) {
continue;
}
const std::vector<any_type>& method_args = method.get_type().get_argument_types();
if ( std::equal(args.begin(), args.end(), method_args.begin(), method_args.end()) ) {
return method;
}
}
for ( auto&& base : data_->bases ) {
if ( method method = base.get_method_with(name, args); method ) {
return method;
}
}
return method{};
}
}

View File

@@ -0,0 +1,69 @@
/*******************************************************************************
* This file is part of the "https://github.com/blackmatov/meta.hpp"
* For conditions of distribution and use, see copyright notice in LICENSE.md
* Copyright (C) 2021, by Matvey Cherevko (blackmatov@gmail.com)
******************************************************************************/
#pragma once
#include "../meta_base.hpp"
#include "../meta_types.hpp"
#include "../meta_traits/ctor_traits.hpp"
namespace meta_hpp::detail
{
template < class_kind Class, typename... Args >
struct ctor_tag {};
template < class_kind Class, typename... Args >
ctor_type_data_ptr ctor_type_data::get() {
static ctor_type_data_ptr data = std::make_shared<ctor_type_data>(type_list<Class>{}, type_list<Args...>{});
return data;
}
template < class_kind Class, typename... Args >
ctor_type_data::ctor_type_data(type_list<Class>, type_list<Args...>)
: type_data_base{type_id{type_list<ctor_tag<Class, Args...>>{}}, type_kind::ctor_}
, flags{ctor_traits<Class, Args...>::make_flags()}
, class_type{resolve_type<typename ctor_traits<Class, Args...>::class_type>()}
, argument_types{ctor_traits<Class, Args...>::make_argument_types()} {}
}
namespace meta_hpp
{
inline ctor_type::ctor_type(detail::ctor_type_data_ptr data)
: data_{std::move(data)} {}
inline bool ctor_type::is_valid() const noexcept {
return !!data_;
}
inline ctor_type::operator bool() const noexcept {
return is_valid();
}
inline type_id ctor_type::get_id() const noexcept {
return data_->id;
}
inline bitflags<ctor_flags> ctor_type::get_flags() const noexcept {
return data_->flags;
}
inline std::size_t ctor_type::get_arity() const noexcept {
return data_->argument_types.size();
}
inline any_type ctor_type::get_class_type() const noexcept {
return data_->class_type;
}
inline any_type ctor_type::get_argument_type(std::size_t index) const noexcept {
return index < data_->argument_types.size() ? data_->argument_types[index] : any_type{};
}
inline const std::vector<any_type>& ctor_type::get_argument_types() const noexcept {
return data_->argument_types;
}
}

View File

@@ -0,0 +1,93 @@
/*******************************************************************************
* This file is part of the "https://github.com/blackmatov/meta.hpp"
* For conditions of distribution and use, see copyright notice in LICENSE.md
* Copyright (C) 2021, by Matvey Cherevko (blackmatov@gmail.com)
******************************************************************************/
#pragma once
#include "../meta_base.hpp"
#include "../meta_types.hpp"
#include "../meta_traits/enum_traits.hpp"
namespace meta_hpp::detail
{
template < enum_kind Enum >
struct enum_tag {};
template < enum_kind Enum >
enum_type_data_ptr enum_type_data::get() {
static enum_type_data_ptr data = std::make_shared<enum_type_data>(type_list<Enum>{});
return data;
}
template < enum_kind Enum >
enum_type_data::enum_type_data(type_list<Enum>)
: type_data_base{type_id{type_list<enum_tag<Enum>>{}}, type_kind::enum_}
, flags{enum_traits<Enum>::make_flags()}
, underlying_type{resolve_type<typename enum_traits<Enum>::underlying_type>()} {}
}
namespace meta_hpp
{
inline enum_type::enum_type(detail::enum_type_data_ptr data)
: data_{std::move(data)} {}
inline bool enum_type::is_valid() const noexcept {
return !!data_;
}
inline enum_type::operator bool() const noexcept {
return is_valid();
}
inline type_id enum_type::get_id() const noexcept {
return data_->id;
}
inline bitflags<enum_flags> enum_type::get_flags() const noexcept {
return data_->flags;
}
inline number_type enum_type::get_underlying_type() const noexcept {
return data_->underlying_type;
}
inline const evalue_map& enum_type::get_evalues() const noexcept {
return data_->evalues;
}
inline evalue enum_type::get_evalue(std::string_view name) const noexcept {
for ( auto&& [index, evalue] : data_->evalues ) {
if ( index.name == name ) {
return evalue;
}
}
return evalue{};
}
template < typename Value >
std::optional<std::string> enum_type::value_to_name(Value&& value) const noexcept {
const detail::arg value_arg{std::forward<Value>(value)};
if ( value_arg.get_raw_type() != *this ) {
return std::nullopt;
}
for ( auto&& evalue : data_->evalues ) {
if ( evalue.second.get_value() == value ) {
return evalue.second.get_index().name;
}
}
return std::nullopt;
}
inline std::optional<value> enum_type::name_to_value(std::string_view name) const noexcept {
if ( const evalue value = get_evalue(name); value ) {
return value.get_value();
}
return std::nullopt;
}
}

View File

@@ -0,0 +1,69 @@
/*******************************************************************************
* This file is part of the "https://github.com/blackmatov/meta.hpp"
* For conditions of distribution and use, see copyright notice in LICENSE.md
* Copyright (C) 2021, by Matvey Cherevko (blackmatov@gmail.com)
******************************************************************************/
#pragma once
#include "../meta_base.hpp"
#include "../meta_types.hpp"
#include "../meta_traits/function_traits.hpp"
namespace meta_hpp::detail
{
template < function_kind Function >
struct function_tag {};
template < function_kind Function >
function_type_data_ptr function_type_data::get() {
static function_type_data_ptr data = std::make_shared<function_type_data>(type_list<Function>{});
return data;
}
template < function_kind Function >
function_type_data::function_type_data(type_list<Function>)
: type_data_base{type_id{type_list<function_tag<Function>>{}}, type_kind::function_}
, flags{function_traits<Function>::make_flags()}
, return_type{resolve_type<typename function_traits<Function>::return_type>()}
, argument_types{function_traits<Function>::make_argument_types()} {}
}
namespace meta_hpp
{
inline function_type::function_type(detail::function_type_data_ptr data)
: data_{std::move(data)} {}
inline bool function_type::is_valid() const noexcept {
return !!data_;
}
inline function_type::operator bool() const noexcept {
return is_valid();
}
inline type_id function_type::get_id() const noexcept {
return data_->id;
}
inline bitflags<function_flags> function_type::get_flags() const noexcept {
return data_->flags;
}
inline std::size_t function_type::get_arity() const noexcept {
return data_->argument_types.size();
}
inline any_type function_type::get_return_type() const noexcept {
return data_->return_type;
}
inline any_type function_type::get_argument_type(std::size_t index) const noexcept {
return index < data_->argument_types.size() ? data_->argument_types[index] : any_type{};
}
inline const std::vector<any_type>& function_type::get_argument_types() const noexcept {
return data_->argument_types;
}
}

View File

@@ -0,0 +1,61 @@
/*******************************************************************************
* This file is part of the "https://github.com/blackmatov/meta.hpp"
* For conditions of distribution and use, see copyright notice in LICENSE.md
* Copyright (C) 2021, by Matvey Cherevko (blackmatov@gmail.com)
******************************************************************************/
#pragma once
#include "../meta_base.hpp"
#include "../meta_types.hpp"
#include "../meta_traits/member_traits.hpp"
namespace meta_hpp::detail
{
template < member_kind Member >
struct member_tag {};
template < member_kind Member >
member_type_data_ptr member_type_data::get() {
static member_type_data_ptr data = std::make_shared<member_type_data>(type_list<Member>{});
return data;
}
template < member_kind Member >
member_type_data::member_type_data(type_list<Member>)
: type_data_base{type_id{type_list<member_tag<Member>>{}}, type_kind::member_}
, flags{member_traits<Member>::make_flags()}
, owner_type{resolve_type<typename member_traits<Member>::class_type>()}
, value_type{resolve_type<typename member_traits<Member>::value_type>()} {}
}
namespace meta_hpp
{
inline member_type::member_type(detail::member_type_data_ptr data)
: data_{std::move(data)} {}
inline bool member_type::is_valid() const noexcept {
return !!data_;
}
inline member_type::operator bool() const noexcept {
return is_valid();
}
inline type_id member_type::get_id() const noexcept {
return data_->id;
}
inline bitflags<member_flags> member_type::get_flags() const noexcept {
return data_->flags;
}
inline class_type member_type::get_owner_type() const noexcept {
return data_->owner_type;
}
inline any_type member_type::get_value_type() const noexcept {
return data_->value_type;
}
}

View File

@@ -0,0 +1,74 @@
/*******************************************************************************
* This file is part of the "https://github.com/blackmatov/meta.hpp"
* For conditions of distribution and use, see copyright notice in LICENSE.md
* Copyright (C) 2021, by Matvey Cherevko (blackmatov@gmail.com)
******************************************************************************/
#pragma once
#include "../meta_base.hpp"
#include "../meta_types.hpp"
#include "../meta_traits/method_traits.hpp"
namespace meta_hpp::detail
{
template < method_kind Method >
struct method_tag {};
template < method_kind Method >
method_type_data_ptr method_type_data::get() {
static method_type_data_ptr data = std::make_shared<method_type_data>(type_list<Method>{});
return data;
}
template < method_kind Method >
method_type_data::method_type_data(type_list<Method>)
: type_data_base{type_id{type_list<method_tag<Method>>{}}, type_kind::method_}
, flags{method_traits<Method>::make_flags()}
, owner_type{resolve_type<typename method_traits<Method>::class_type>()}
, return_type{resolve_type<typename method_traits<Method>::return_type>()}
, argument_types{method_traits<Method>::make_argument_types()} {}
}
namespace meta_hpp
{
inline method_type::method_type(detail::method_type_data_ptr data)
: data_{std::move(data)} {}
inline bool method_type::is_valid() const noexcept {
return !!data_;
}
inline method_type::operator bool() const noexcept {
return is_valid();
}
inline type_id method_type::get_id() const noexcept {
return data_->id;
}
inline bitflags<method_flags> method_type::get_flags() const noexcept {
return data_->flags;
}
inline std::size_t method_type::get_arity() const noexcept {
return data_->argument_types.size();
}
inline class_type method_type::get_owner_type() const noexcept {
return data_->owner_type;
}
inline any_type method_type::get_return_type() const noexcept {
return data_->return_type;
}
inline any_type method_type::get_argument_type(std::size_t index) const noexcept {
return index < data_->argument_types.size() ? data_->argument_types[index] : any_type{};
}
inline const std::vector<any_type>& method_type::get_argument_types() const noexcept {
return data_->argument_types;
}
}

View File

@@ -0,0 +1,56 @@
/*******************************************************************************
* This file is part of the "https://github.com/blackmatov/meta.hpp"
* For conditions of distribution and use, see copyright notice in LICENSE.md
* Copyright (C) 2021, by Matvey Cherevko (blackmatov@gmail.com)
******************************************************************************/
#pragma once
#include "../meta_base.hpp"
#include "../meta_types.hpp"
#include "../meta_traits/number_traits.hpp"
namespace meta_hpp::detail
{
template < number_kind Number >
struct number_tag {};
template < number_kind Number >
number_type_data_ptr number_type_data::get() {
static number_type_data_ptr data = std::make_shared<number_type_data>(type_list<Number>{});
return data;
}
template < number_kind Number >
number_type_data::number_type_data(type_list<Number>)
: type_data_base{type_id{type_list<number_tag<Number>>{}}, type_kind::number_}
, flags{number_traits<Number>::make_flags()}
, size{number_traits<Number>::size} {}
}
namespace meta_hpp
{
inline number_type::number_type(detail::number_type_data_ptr data)
: data_{std::move(data)} {}
inline bool number_type::is_valid() const noexcept {
return !!data_;
}
inline number_type::operator bool() const noexcept {
return is_valid();
}
inline type_id number_type::get_id() const noexcept {
return data_->id;
}
inline bitflags<number_flags> number_type::get_flags() const noexcept {
return data_->flags;
}
inline std::size_t number_type::get_size() const noexcept {
return data_->size;
}
}

View File

@@ -0,0 +1,56 @@
/*******************************************************************************
* This file is part of the "https://github.com/blackmatov/meta.hpp"
* For conditions of distribution and use, see copyright notice in LICENSE.md
* Copyright (C) 2021, by Matvey Cherevko (blackmatov@gmail.com)
******************************************************************************/
#pragma once
#include "../meta_base.hpp"
#include "../meta_types.hpp"
#include "../meta_traits/pointer_traits.hpp"
namespace meta_hpp::detail
{
template < pointer_kind Pointer >
struct pointer_tag {};
template < pointer_kind Pointer >
pointer_type_data_ptr pointer_type_data::get() {
static pointer_type_data_ptr data = std::make_shared<pointer_type_data>(type_list<Pointer>{});
return data;
}
template < pointer_kind Pointer >
pointer_type_data::pointer_type_data(type_list<Pointer>)
: type_data_base{type_id{type_list<pointer_tag<Pointer>>{}}, type_kind::pointer_}
, flags{pointer_traits<Pointer>::make_flags()}
, data_type{resolve_type<typename pointer_traits<Pointer>::data_type>()} {}
}
namespace meta_hpp
{
inline pointer_type::pointer_type(detail::pointer_type_data_ptr data)
: data_{std::move(data)} {}
inline bool pointer_type::is_valid() const noexcept {
return !!data_;
}
inline pointer_type::operator bool() const noexcept {
return is_valid();
}
inline type_id pointer_type::get_id() const noexcept {
return data_->id;
}
inline bitflags<pointer_flags> pointer_type::get_flags() const noexcept {
return data_->flags;
}
inline any_type pointer_type::get_data_type() const noexcept {
return data_->data_type;
}
}

View File

@@ -0,0 +1,56 @@
/*******************************************************************************
* This file is part of the "https://github.com/blackmatov/meta.hpp"
* For conditions of distribution and use, see copyright notice in LICENSE.md
* Copyright (C) 2021, by Matvey Cherevko (blackmatov@gmail.com)
******************************************************************************/
#pragma once
#include "../meta_base.hpp"
#include "../meta_types.hpp"
#include "../meta_traits/reference_traits.hpp"
namespace meta_hpp::detail
{
template < reference_kind Reference >
struct reference_tag {};
template < reference_kind Reference >
reference_type_data_ptr reference_type_data::get() {
static reference_type_data_ptr data = std::make_shared<reference_type_data>(type_list<Reference>{});
return data;
}
template < reference_kind Reference >
reference_type_data::reference_type_data(type_list<Reference>)
: type_data_base{type_id{type_list<reference_tag<Reference>>{}}, type_kind::reference_}
, flags{reference_traits<Reference>::make_flags()}
, data_type{resolve_type<typename reference_traits<Reference>::data_type>()} {}
}
namespace meta_hpp
{
inline reference_type::reference_type(detail::reference_type_data_ptr data)
: data_{std::move(data)} {}
inline bool reference_type::is_valid() const noexcept {
return !!data_;
}
inline reference_type::operator bool() const noexcept {
return is_valid();
}
inline type_id reference_type::get_id() const noexcept {
return data_->id;
}
inline bitflags<reference_flags> reference_type::get_flags() const noexcept {
return data_->flags;
}
inline any_type reference_type::get_data_type() const noexcept {
return data_->data_type;
}
}

View File

@@ -0,0 +1,51 @@
/*******************************************************************************
* This file is part of the "https://github.com/blackmatov/meta.hpp"
* For conditions of distribution and use, see copyright notice in LICENSE.md
* Copyright (C) 2021, by Matvey Cherevko (blackmatov@gmail.com)
******************************************************************************/
#pragma once
#include "../meta_base.hpp"
#include "../meta_types.hpp"
#include "../meta_traits/void_traits.hpp"
namespace meta_hpp::detail
{
template < void_kind Void >
struct void_tag {};
template < void_kind Void >
void_type_data_ptr void_type_data::get() {
static void_type_data_ptr data = std::make_shared<void_type_data>(type_list<Void>{});
return data;
}
template < void_kind Void >
void_type_data::void_type_data(type_list<Void>)
: type_data_base{type_id{type_list<void_tag<Void>>{}}, type_kind::void_}
, flags{void_traits<Void>::make_flags()} {}
}
namespace meta_hpp
{
inline void_type::void_type(detail::void_type_data_ptr data)
: data_{std::move(data)} {}
inline bool void_type::is_valid() const noexcept {
return !!data_;
}
inline void_type::operator bool() const noexcept {
return is_valid();
}
inline type_id void_type::get_id() const noexcept {
return data_->id;
}
inline bitflags<void_flags> void_type::get_flags() const noexcept {
return data_->flags;
}
}

View File

@@ -0,0 +1,238 @@
/*******************************************************************************
* This file is part of the "https://github.com/blackmatov/meta.hpp"
* For conditions of distribution and use, see copyright notice in LICENSE.md
* Copyright (C) 2021, by Matvey Cherevko (blackmatov@gmail.com)
******************************************************************************/
#pragma once
#include "meta_base.hpp"
namespace meta_hpp
{
class value final {
public:
value() = delete;
value(value&& other);
value(const value& other);
value& operator=(value&& other);
value& operator=(const value& other);
template < typename T, typename Tp = std::decay_t<T>
, std::enable_if_t<!std::is_same_v<Tp, value>, int> = 0
, std::enable_if_t<!std::is_same_v<Tp, detail::arg>, int> = 0
, std::enable_if_t<!std::is_same_v<Tp, detail::inst>, int> = 0 >
explicit value(T&& val);
template < typename T, typename Tp = std::decay_t<T>
, std::enable_if_t<!std::is_same_v<Tp, value>, int> = 0
, std::enable_if_t<!std::is_same_v<Tp, detail::arg>, int> = 0
, std::enable_if_t<!std::is_same_v<Tp, detail::inst>, int> = 0 >
value& operator=(T&& val);
void swap(value& other) noexcept;
const any_type& get_type() const noexcept;
void* data() noexcept;
const void* data() const noexcept;
const void* cdata() const noexcept;
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;
template < typename T >
friend bool operator==(const value& l, const T& r);
template < typename T >
friend bool operator==(const T& l, const value& r);
friend bool operator==(const value& l, const value& r);
friend std::istream& operator>>(std::istream& os, value& v);
friend std::ostream& operator<<(std::ostream& os, const value& v);
private:
struct traits;
std::any raw_{};
const traits* traits_{};
};
inline void swap(value& l, value& r) noexcept {
l.swap(r);
}
}
namespace meta_hpp::detail
{
class arg_base {
public:
enum class ref_types {
ref,
rref,
cref,
crref,
};
public:
arg_base() = delete;
arg_base(arg_base&&) = delete;
arg_base& operator=(arg_base&&) = delete;
arg_base(const arg_base&) = delete;
arg_base& operator=(const arg_base&) = delete;
template < typename T, std::enable_if_t<
std::is_pointer_v<T> || std::is_lvalue_reference_v<T>
, int> = 0 >
explicit arg_base(type_list<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(type_list<T>);
explicit arg_base(value& v);
explicit arg_base(value&& v);
explicit arg_base(const value& v);
explicit arg_base(const value&& v);
bool is_const() const noexcept;
bool is_lvalue() const noexcept;
bool is_rvalue() const noexcept;
any_type get_raw_type() const noexcept;
ref_types get_ref_type() const noexcept;
template < typename To >
bool can_cast_to() const noexcept;
private:
any_type raw_type_{};
ref_types ref_type_{};
};
}
namespace meta_hpp::detail
{
class arg final : public arg_base {
public:
arg() = delete;
arg(arg&&) = delete;
arg& operator=(arg&&) = delete;
arg(const arg&) = delete;
arg& operator=(const arg&) = delete;
template < typename T, typename Tp = std::decay_t<T>
, std::enable_if_t<!std::is_same_v<Tp, arg>, int> = 0
, std::enable_if_t<!std::is_same_v<Tp, inst>, int> = 0
, std::enable_if_t<!std::is_same_v<Tp, value>, int> = 0 >
explicit arg(T&& v);
explicit arg(value& v);
explicit arg(value&& v);
explicit arg(const value& v);
explicit arg(const value&& v);
template < typename To >
To cast() const;
private:
void* data_{};
};
}
namespace meta_hpp::detail
{
class inst_base {
public:
enum class ref_types {
ref,
rref,
cref,
crref,
};
public:
inst_base() = delete;
inst_base(inst_base&&) = delete;
inst_base& operator=(inst_base&&) = delete;
inst_base(const inst_base&) = delete;
inst_base& operator=(const inst_base&) = delete;
template < typename T, std::enable_if_t<
std::is_lvalue_reference_v<T> && std::is_class_v<std::remove_reference_t<T>>
, int> = 0>
explicit inst_base(type_list<T>);
template < typename T, std::enable_if_t<
std::is_class_v<T> ||
(std::is_rvalue_reference_v<T> && std::is_class_v<std::remove_reference_t<T>>)
, int> = 0>
explicit inst_base(type_list<T>);
explicit inst_base(value& v);
explicit inst_base(value&& v);
explicit inst_base(const value& v);
explicit inst_base(const value&& v);
bool is_const() const noexcept;
bool is_lvalue() const noexcept;
bool is_rvalue() const noexcept;
any_type get_raw_type() const noexcept;
ref_types get_ref_type() const noexcept;
template < typename To >
bool can_cast_to() const noexcept;
private:
any_type raw_type_{};
ref_types ref_type_{};
};
}
namespace meta_hpp::detail
{
class inst final : public inst_base {
public:
inst() = delete;
inst(inst&&) = delete;
inst& operator=(inst&&) = delete;
inst(const inst&) = delete;
inst& operator=(const inst&) = delete;
template < typename T, typename Tp = std::decay_t<T>
, std::enable_if_t<!std::is_same_v<Tp, arg>, int> = 0
, std::enable_if_t<!std::is_same_v<Tp, inst>, int> = 0
, std::enable_if_t<!std::is_same_v<Tp, value>, int> = 0 >
explicit inst(T&& v);
explicit inst(value& v);
explicit inst(value&& v);
explicit inst(const value& v);
explicit inst(const value&& v);
template < typename To >
decltype(auto) cast() const;
private:
void* data_{};
};
}

View File

@@ -0,0 +1,205 @@
/*******************************************************************************
* This file is part of the "https://github.com/blackmatov/meta.hpp"
* For conditions of distribution and use, see copyright notice in LICENSE.md
* Copyright (C) 2021, by Matvey Cherevko (blackmatov@gmail.com)
******************************************************************************/
#pragma once
#include "../meta_base.hpp"
#include "../meta_utilities.hpp"
namespace meta_hpp::detail
{
template < typename T, std::enable_if_t<
std::is_pointer_v<T> || std::is_lvalue_reference_v<T>
, int> >
arg_base::arg_base(type_list<T>)
: raw_type_{resolve_type<std::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(type_list<T>)
: raw_type_{resolve_type<std::remove_cvref_t<T>>()}
, ref_type_{std::is_const_v<std::remove_reference_t<T>> ? ref_types::crref : ref_types::rref} {}
inline arg_base::arg_base(value& v)
: raw_type_{v.get_type()}
, ref_type_{ref_types::ref} {}
inline arg_base::arg_base(value&& v)
: raw_type_{v.get_type()}
, ref_type_{ref_types::rref} {}
inline arg_base::arg_base(const value& v)
: raw_type_{v.get_type()}
, ref_type_{ref_types::cref} {}
inline arg_base::arg_base(const value&& v)
: raw_type_{v.get_type()}
, ref_type_{ref_types::crref} {}
inline bool arg_base::is_const() const noexcept {
return ref_type_ == ref_types::cref
|| ref_type_ == ref_types::crref;
}
inline bool arg_base::is_lvalue() const noexcept {
return ref_type_ == ref_types::ref
|| ref_type_ == ref_types::cref;
}
inline bool arg_base::is_rvalue() const noexcept {
return ref_type_ == ref_types::rref
|| ref_type_ == ref_types::crref;
}
inline any_type arg_base::get_raw_type() const noexcept {
return raw_type_;
}
inline arg_base::ref_types arg_base::get_ref_type() const noexcept {
return ref_type_;
}
template < typename To >
bool arg_base::can_cast_to() const noexcept {
if constexpr ( std::is_pointer_v<To> ) {
using to_raw_type = std::remove_cv_t<To>;
using to_raw_ptr_type = std::remove_cv_t<std::remove_pointer_t<to_raw_type>>;
return get_raw_type() == resolve_type<to_raw_type>()
|| get_raw_type() == resolve_type<to_raw_ptr_type*>();
}
if constexpr ( std::is_reference_v<To> ) {
constexpr bool to_const = std::is_const_v<std::remove_reference_t<To>>;
if constexpr ( !to_const ) {
if ( is_const() ) {
return false;
}
}
if constexpr ( std::is_lvalue_reference_v<To> ) {
if constexpr ( !to_const ) {
if ( is_rvalue() ) {
return false;
}
}
}
if constexpr ( std::is_rvalue_reference_v<To> ) {
if ( !is_rvalue() ) {
return false;
}
}
using to_raw_type = std::remove_cvref_t<To>;
if ( get_raw_type() == resolve_type<to_raw_type>() ) {
return true;
}
if constexpr ( to_const && std::is_pointer_v<to_raw_type> ) {
using to_raw_ptr_type = std::remove_cv_t<std::remove_pointer_t<to_raw_type>>;
return get_raw_type() == resolve_type<to_raw_ptr_type*>();
}
return false;
}
if constexpr ( !std::is_pointer_v<To> && !std::is_reference_v<To> ) {
using to_raw_type = std::remove_cv_t<To>;
if ( get_raw_type() != resolve_type<to_raw_type>() ) {
return false;
}
return (get_ref_type() == ref_types::ref && std::is_constructible_v<To, to_raw_type&>)
|| (get_ref_type() == ref_types::cref && std::is_constructible_v<To, const to_raw_type&>)
|| (get_ref_type() == ref_types::rref && std::is_constructible_v<To, to_raw_type&&>)
|| (get_ref_type() == ref_types::crref && std::is_constructible_v<To, const to_raw_type&&>);
}
}
}
namespace meta_hpp::detail
{
template < typename T, typename Tp
, std::enable_if_t<!std::is_same_v<Tp, arg>, int>
, std::enable_if_t<!std::is_same_v<Tp, inst>, int>
, std::enable_if_t<!std::is_same_v<Tp, value>, int> >
arg::arg(T&& v)
: arg_base{type_list<T&&>{}}
, data_{const_cast<std::remove_cvref_t<T>*>(std::addressof(v))} {}
inline arg::arg(value& v)
: arg_base{v}
, data_{const_cast<void*>(v.data())} {}
inline arg::arg(value&& v)
: arg_base{v}
, data_{const_cast<void*>(v.data())} {}
inline arg::arg(const value& v)
: arg_base{v}
, data_{const_cast<void*>(v.data())} {}
inline arg::arg(const value&& v)
: arg_base{v}
, data_{const_cast<void*>(v.data())} {}
template < typename To >
To arg::cast() const {
if ( !can_cast_to<To>() ) {
throw std::logic_error("bad argument cast");
}
if constexpr ( std::is_pointer_v<To> ) {
return *static_cast<To*>(data_);
}
if constexpr ( std::is_reference_v<To> ) {
using raw_type = std::remove_cvref_t<To>;
if constexpr ( std::is_lvalue_reference_v<To> ) {
return *static_cast<raw_type*>(data_);
}
if constexpr ( std::is_rvalue_reference_v<To> ) {
return std::move(*static_cast<raw_type*>(data_));
}
}
if constexpr ( !std::is_pointer_v<To> && !std::is_reference_v<To> ) {
using raw_type = std::remove_cv_t<To>;
if ( get_ref_type() == ref_types::ref ) {
if constexpr ( std::is_constructible_v<To, raw_type&> ) {
return To{*static_cast<raw_type*>(data_)};
}
}
if ( get_ref_type() == ref_types::cref ) {
if constexpr ( std::is_constructible_v<To, const raw_type&> ) {
return To{std::as_const(*static_cast<raw_type*>(data_))};
}
}
if ( get_ref_type() == ref_types::rref ) {
if constexpr ( std::is_constructible_v<To, raw_type&&> ) {
return To{std::move(*static_cast<raw_type*>(data_))};
}
}
if ( get_ref_type() == ref_types::crref ) {
if constexpr ( std::is_constructible_v<To, const raw_type&&> ) {
return To{std::move(std::as_const(*static_cast<raw_type*>(data_)))};
}
}
}
throw std::logic_error("bad argument cast");
}
}

View File

@@ -0,0 +1,148 @@
/*******************************************************************************
* This file is part of the "https://github.com/blackmatov/meta.hpp"
* For conditions of distribution and use, see copyright notice in LICENSE.md
* Copyright (C) 2021, by Matvey Cherevko (blackmatov@gmail.com)
******************************************************************************/
#pragma once
#include "../meta_base.hpp"
#include "../meta_utilities.hpp"
namespace meta_hpp::detail
{
template < typename T, std::enable_if_t<
std::is_lvalue_reference_v<T> && std::is_class_v<std::remove_reference_t<T>>
, int> >
inst_base::inst_base(type_list<T>)
: raw_type_{resolve_type<std::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_class_v<T> ||
(std::is_rvalue_reference_v<T> && std::is_class_v<std::remove_reference_t<T>>)
, int> >
inst_base::inst_base(type_list<T>)
: raw_type_{resolve_type<std::remove_cvref_t<T>>()}
, ref_type_{std::is_const_v<std::remove_reference_t<T>> ? ref_types::crref : ref_types::rref} {}
inline inst_base::inst_base(value& v)
: raw_type_{v.get_type()}
, ref_type_{ref_types::ref} {}
inline inst_base::inst_base(value&& v)
: raw_type_{v.get_type()}
, ref_type_{ref_types::rref} {}
inline inst_base::inst_base(const value& v)
: raw_type_{v.get_type()}
, ref_type_{ref_types::cref} {}
inline inst_base::inst_base(const value&& v)
: raw_type_{v.get_type()}
, ref_type_{ref_types::crref} {}
inline bool inst_base::is_const() const noexcept {
return ref_type_ == ref_types::cref
|| ref_type_ == ref_types::crref;
}
inline bool inst_base::is_lvalue() const noexcept {
return ref_type_ == ref_types::ref
|| ref_type_ == ref_types::cref;
}
inline bool inst_base::is_rvalue() const noexcept {
return ref_type_ == ref_types::rref
|| ref_type_ == ref_types::crref;
}
inline any_type inst_base::get_raw_type() const noexcept {
return raw_type_;
}
inline inst_base::ref_types inst_base::get_ref_type() const noexcept {
return ref_type_;
}
template < typename To >
bool inst_base::can_cast_to() const noexcept {
static_assert(
std::is_class_v<To> ||
(std::is_reference_v<To> && std::is_class_v<std::remove_reference_t<To>>));
constexpr bool to_const = std::is_const_v<std::remove_reference_t<To>>;
if constexpr ( !to_const ) {
if ( is_const() ) {
return false;
}
}
if constexpr ( std::is_lvalue_reference_v<To> ) {
if ( !is_lvalue() ) {
return false;
}
}
if constexpr ( std::is_rvalue_reference_v<To> ) {
if ( !is_rvalue() ) {
return false;
}
}
using to_raw_type = std::remove_cvref_t<To>;
return get_raw_type() == resolve_type<to_raw_type>();
}
}
namespace meta_hpp::detail
{
template < typename T, typename Tp
, std::enable_if_t<!std::is_same_v<Tp, arg>, int>
, std::enable_if_t<!std::is_same_v<Tp, inst>, int>
, std::enable_if_t<!std::is_same_v<Tp, value>, int> >
inst::inst(T&& v)
: inst_base{type_list<T&&>{}}
, data_{const_cast<std::remove_cvref_t<T>*>(std::addressof(v))} {}
inline inst::inst(value& v)
: inst_base{v}
, data_{const_cast<void*>(v.data())} {}
inline inst::inst(value&& v)
: inst_base{v}
, data_{const_cast<void*>(v.data())} {}
inline inst::inst(const value& v)
: inst_base{v}
, data_{const_cast<void*>(v.data())} {}
inline inst::inst(const value&& v)
: inst_base{v}
, data_{const_cast<void*>(v.data())} {}
template < typename To >
decltype(auto) inst::cast() const {
if ( !can_cast_to<To>() ) {
throw std::logic_error("bad inst cast");
}
if constexpr ( std::is_reference_v<To> ) {
using raw_type_with_cv = std::remove_reference_t<To>;
if constexpr ( std::is_lvalue_reference_v<To> ) {
return *static_cast<raw_type_with_cv*>(data_);
}
if constexpr ( std::is_rvalue_reference_v<To> ) {
return std::move(*static_cast<raw_type_with_cv*>(data_));
}
}
if constexpr ( !std::is_reference_v<To>) {
using raw_type_with_cv = To;
return *static_cast<raw_type_with_cv*>(data_);
}
}
}

View File

@@ -0,0 +1,306 @@
/*******************************************************************************
* This file is part of the "https://github.com/blackmatov/meta.hpp"
* For conditions of distribution and use, see copyright notice in LICENSE.md
* Copyright (C) 2021, by Matvey Cherevko (blackmatov@gmail.com)
******************************************************************************/
#pragma once
#include "../meta_base.hpp"
#include "../meta_utilities.hpp"
namespace meta_hpp::detail
{
template < typename T, typename = void >
struct has_value_type_equality_operator
: std::false_type {};
template < typename T >
struct has_value_type_equality_operator<T, std::void_t<decltype(
std::declval<const T&>() == std::declval<const T&>()
)>> : std::true_type {};
template < typename T >
inline constexpr bool has_value_type_equality_operator_v = has_value_type_equality_operator<T>::value;
template < typename T, std::enable_if_t<
has_value_type_equality_operator_v<T>
, int> = 0 >
bool value_equals_function(const value& l, const value& r) {
assert(l.get_type() == r.get_type());
return l.cast<T>() == r.cast<T>();
}
template < typename T, std::enable_if_t<
!has_value_type_equality_operator_v<T>
, int> = 0 >
bool value_equals_function([[maybe_unused]] const value& l, [[maybe_unused]] const value& r) {
throw std::logic_error("value type doesn't have equality operator");
}
}
namespace meta_hpp::detail
{
template < typename T, typename = void >
struct has_value_type_istream_operator
: std::false_type {};
template < typename T >
struct has_value_type_istream_operator<T, std::void_t<decltype(
std::declval<std::istream&>() >> std::declval<T&>()
)>> : std::true_type {};
template < typename T >
inline constexpr bool has_value_type_istream_operator_v = has_value_type_istream_operator<T>::value;
template < typename T, std::enable_if_t<
has_value_type_istream_operator_v<T>
, int> = 0 >
void value_istream_function(std::istream& os, value& v) {
os >> v.cast<T>();
}
template < typename T, std::enable_if_t<
!has_value_type_istream_operator_v<T>
, int> = 0 >
void value_istream_function([[maybe_unused]] std::istream& os, [[maybe_unused]] value& v) {
throw std::logic_error("value type doesn't have istream operator");
}
}
namespace meta_hpp::detail
{
template < typename T, typename = void >
struct has_value_type_ostream_operator
: std::false_type {};
template < typename T >
struct has_value_type_ostream_operator<T, std::void_t<decltype(
std::declval<std::ostream&>() << std::declval<const T&>()
)>> : std::true_type {};
template < typename T >
inline constexpr bool has_value_type_ostream_operator_v = has_value_type_ostream_operator<T>::value;
template < typename T, std::enable_if_t<
has_value_type_ostream_operator_v<T>
, int> = 0 >
void value_ostream_function(std::ostream& os, const value& v) {
os << v.cast<T>();
}
template < typename T, std::enable_if_t<
!has_value_type_ostream_operator_v<T>
, int> = 0 >
void value_ostream_function([[maybe_unused]] std::ostream& os, [[maybe_unused]] const value& v) {
throw std::logic_error("value type doesn't have ostream operator");
}
}
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&);
void (*const istream)(std::istream&, value&);
void (*const ostream)(std::ostream&, 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
resolve_type<T>(),
// data
+[](value& v) noexcept -> void* {
return v.try_cast<T>();
},
// cdata
+[](const value& v) noexcept -> const void* {
return v.try_cast<T>();
},
// equals
&detail::value_equals_function<T>,
// 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");
}
},
// istream
&detail::value_istream_function<T>,
// ostream
&detail::value_ostream_function<T>,
};
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>
, std::enable_if_t<!std::is_same_v<Tp, detail::arg>, int>
, std::enable_if_t<!std::is_same_v<Tp, detail::inst>, 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>
, std::enable_if_t<!std::is_same_v<Tp, detail::arg>, int>
, std::enable_if_t<!std::is_same_v<Tp, detail::inst>, int> >
value& value::operator=(T&& val) {
raw_ = std::forward<T>(val);
traits_ = resolve_type<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::get_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, typename Tp >
Tp& value::cast() & {
if ( get_type() != resolve_type<Tp>() ) {
throw std::logic_error("bad value cast");
}
return std::any_cast<Tp&>(raw_);
}
template < typename T, typename Tp >
Tp&& value::cast() && {
if ( get_type() != resolve_type<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 ( get_type() != resolve_type<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 ( get_type() != resolve_type<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_);
}
}
namespace meta_hpp
{
template < typename T >
bool operator==(const value& l, const T& r) {
return l.get_type() == resolve_type<T>()
&& std::equal_to<>{}(l.cast<T>(), r);
}
template < typename T >
bool operator==(const T& l, const value& r) {
return resolve_type<T>() == r.get_type()
&& std::equal_to<>{}(l, r.cast<T>());
}
inline bool operator==(const value& l, const value& r) {
return l.get_type() == r.get_type()
&& l.traits_->equals(l, r);
}
inline std::istream& operator>>(std::istream& is, value& v) {
v.traits_->istream(is, v);
return is;
}
inline std::ostream& operator<<(std::ostream& os, const value& v) {
v.traits_->ostream(os, v);
return os;
}
}

View File

@@ -0,0 +1,38 @@
/*******************************************************************************
* This file is part of the "https://github.com/blackmatov/meta.hpp"
* For conditions of distribution and use, see copyright notice in LICENSE.md
* Copyright (C) 2021, by Matvey Cherevko (blackmatov@gmail.com)
******************************************************************************/
#include "../meta_tests.hpp"
namespace
{
struct base_clazz {
};
struct derived_clazz final : base_clazz {
};
}
TEST_CASE("meta/examples/class") {
namespace meta = meta_hpp;
meta::class_<derived_clazz>()
.base_<base_clazz>();
const meta::class_type base_clazz_type = meta::resolve_type<base_clazz>();
REQUIRE(base_clazz_type);
const meta::class_type derived_clazz_type = meta::resolve_type<derived_clazz>();
REQUIRE(derived_clazz_type);
CHECK(base_clazz_type.is_base_of<derived_clazz>());
CHECK(derived_clazz_type.is_derived_from<base_clazz>());
const meta::class_type int_vector_type = meta::resolve_type<std::vector<int>>();
REQUIRE(int_vector_type);
CHECK(int_vector_type.get_arity() == 2);
CHECK(int_vector_type.get_argument_type(0) == meta::resolve_type<int>());
CHECK(int_vector_type.get_argument_type(1) == meta::resolve_type<std::allocator<int>>());
}

View File

@@ -0,0 +1,99 @@
/*******************************************************************************
* This file is part of the "https://github.com/blackmatov/meta.hpp"
* For conditions of distribution and use, see copyright notice in LICENSE.md
* Copyright (C) 2021, by Matvey Cherevko (blackmatov@gmail.com)
******************************************************************************/
#include "../meta_tests.hpp"
namespace
{
struct ivec2 {
int x{};
int y{};
ivec2() = default;
ivec2(int v) : x{v}, y{v} {}
ivec2(int x, int y) : x{x}, y{y} {}
int dot(const ivec2& other) const noexcept {
return x * other.x + y * other.y;
}
int length2() const noexcept {
return dot(*this);
}
friend bool operator==(const ivec2& l, const ivec2& r) noexcept {
return l.x == r.x && l.y == r.y;
}
};
}
TEST_CASE("meta/examples/complex") {
namespace meta = meta_hpp;
meta::class_<ivec2>()
.ctor_<>()
.ctor_<int>()
.ctor_<int, int>()
.member_("x", &ivec2::x)
.member_("y", &ivec2::y)
.method_("dot", &ivec2::dot)
.method_("length2", &ivec2::length2);
const meta::class_type ivec2_type = meta::resolve_type<ivec2>();
const meta::member ivec2_x = ivec2_type.get_member("x");
const meta::member ivec2_y = ivec2_type.get_member("y");
const meta::method ivec2_dot = ivec2_type.get_method("dot");
const meta::method ivec2_length2 = ivec2_type.get_method("length2");
{
const ivec2 v = ivec2_type.get_ctor_with<>().invoke().cast<ivec2>();
CHECK(v == ivec2{});
CHECK(ivec2_x.get(v) == 0);
CHECK(ivec2_y.get(v) == 0);
}
{
const ivec2 v = ivec2_type.get_ctor_with<int>().invoke(3).cast<ivec2>();
CHECK(v == ivec2{3});
CHECK(ivec2_x.get(v) == 3);
CHECK(ivec2_y.get(v) == 3);
}
{
const meta::value v = ivec2_type.get_ctor_with<int, int>().invoke(1, 2);
CHECK(v == ivec2{1, 2});
CHECK(ivec2_x.get(v) == 1);
CHECK(ivec2_y.get(v) == 2);
}
{
meta::value v = ivec2_type.get_ctor_with<int, int>().invoke(1, 2);
ivec2_x.set(v, 10);
ivec2_y.set(v, 20);
CHECK(ivec2_x.get(v) == 10);
CHECK(ivec2_y.get(v) == 20);
}
{
const meta::value v0 = ivec2_type.get_ctor_with<int, int>().invoke(1, 2);
const meta::value v1 = ivec2_type.get_ctor_with<int, int>().invoke(3, 4);
CHECK(ivec2_dot.invoke(v0, v1) == 1 * 3 + 2 * 4);
}
{
const meta::value v = ivec2_type.get_ctor_with<int, int>().invoke(3, 4);
CHECK(ivec2_length2.invoke(v) == 3 * 3 + 4 * 4);
}
}

View File

@@ -0,0 +1,36 @@
/*******************************************************************************
* This file is part of the "https://github.com/blackmatov/meta.hpp"
* For conditions of distribution and use, see copyright notice in LICENSE.md
* Copyright (C) 2021, by Matvey Cherevko (blackmatov@gmail.com)
******************************************************************************/
#include "../meta_tests.hpp"
namespace
{
enum class color : unsigned {
red = 0xFF0000,
green = 0x00FF00,
blue = 0x0000FF,
white = red | green | blue,
};
}
TEST_CASE("meta/examples/enum") {
namespace meta = meta_hpp;
meta::enum_<color>()
.evalue_("red", color::red)
.evalue_("green", color::green)
.evalue_("blue", color::blue)
.evalue_("white", color::white);
meta::enum_type color_type = meta::resolve_type<color>();
REQUIRE(color_type);
CHECK(color_type.get_underlying_type() == meta::resolve_type<unsigned>());
CHECK(color_type.get_evalue("green").get_index().name == "green");
CHECK(color_type.get_evalue("green").get_value() == color::green);
CHECK_FALSE(color_type.get_evalue("yellow"));
}

View File

@@ -0,0 +1,37 @@
/*******************************************************************************
* This file is part of the "https://github.com/blackmatov/meta.hpp"
* For conditions of distribution and use, see copyright notice in LICENSE.md
* Copyright (C) 2021, by Matvey Cherevko (blackmatov@gmail.com)
******************************************************************************/
#include "../meta_tests.hpp"
namespace
{
struct ivec2 final {
int x{};
int y{};
};
}
TEST_CASE("meta/examples/member") {
namespace meta = meta_hpp;
meta::class_<ivec2>()
.member_("x", &ivec2::x)
.member_("y", &ivec2::y);
const meta::class_type ivec2_type = meta::resolve_type<ivec2>();
REQUIRE(ivec2_type);
CHECK(ivec2_type.get_members().size() == 2);
const meta::member ivec2_x = ivec2_type.get_member("x");
REQUIRE(ivec2_x);
CHECK(ivec2_x.get_index().name == "x");
CHECK(ivec2_x.get_type() == meta::resolve_type<decltype(&ivec2::x)>());
CHECK(ivec2_x.get_type().get_owner_type() == meta::resolve_type<ivec2>());
CHECK(ivec2_x.get_type().get_value_type() == meta::resolve_type<int>());
}

View File

@@ -0,0 +1,48 @@
/*******************************************************************************
* This file is part of the "https://github.com/blackmatov/meta.hpp"
* For conditions of distribution and use, see copyright notice in LICENSE.md
* Copyright (C) 2021, by Matvey Cherevko (blackmatov@gmail.com)
******************************************************************************/
#include "../meta_tests.hpp"
namespace
{
struct ivec2 final {
int x{};
int y{};
int dot(const ivec2& other) const noexcept {
return x * other.x + y * other.y;
}
int length2() const noexcept {
return dot(*this);
}
};
}
TEST_CASE("meta/examples/method") {
namespace meta = meta_hpp;
meta::class_<ivec2>()
.member_("x", &ivec2::x)
.member_("y", &ivec2::y)
.method_("dot", &ivec2::dot)
.method_("length2", &ivec2::length2);
const meta::class_type ivec2_type = meta::resolve_type<ivec2>();
REQUIRE(ivec2_type);
CHECK(ivec2_type.get_methods().size() == 2);
const meta::method ivec2_dot = ivec2_type.get_method("dot");
REQUIRE(ivec2_dot);
CHECK(ivec2_dot.get_index().name == "dot");
CHECK(ivec2_dot.get_type() == meta::resolve_type<decltype(&ivec2::dot)>());
CHECK(ivec2_dot.get_type().get_arity() == 1);
CHECK(ivec2_dot.get_type().get_return_type() == meta::resolve_type<int>());
CHECK(ivec2_dot.get_type().get_argument_type(0) == meta::resolve_type<const ivec2&>());
}

View File

@@ -0,0 +1,31 @@
/*******************************************************************************
* This file is part of the "https://github.com/blackmatov/meta.hpp"
* For conditions of distribution and use, see copyright notice in LICENSE.md
* Copyright (C) 2021, by Matvey Cherevko (blackmatov@gmail.com)
******************************************************************************/
#include "../meta_tests.hpp"
namespace
{
}
TEST_CASE("meta/examples/number") {
namespace meta = meta_hpp;
{
const meta::number_type int_type = meta::resolve_type<int>();
REQUIRE(int_type);
CHECK(int_type.get_flags().has(meta::number_flags::is_signed));
CHECK(int_type.get_size() == sizeof(int));
}
{
const meta::number_type unsigned_type = meta::resolve_type<unsigned>();
REQUIRE(unsigned_type);
CHECK(unsigned_type.get_flags().has(meta::number_flags::is_unsigned));
CHECK(unsigned_type.get_size() == sizeof(unsigned));
}
}

View File

@@ -0,0 +1,58 @@
/*******************************************************************************
* This file is part of the "https://github.com/blackmatov/meta.hpp"
* For conditions of distribution and use, see copyright notice in LICENSE.md
* Copyright (C) 2021, by Matvey Cherevko (blackmatov@gmail.com)
******************************************************************************/
#include "../meta_tests.hpp"
namespace
{
enum class color : unsigned {
red = 0xFF0000,
green = 0x00FF00,
blue = 0x0000FF,
white = red | green | blue,
};
}
TEST_CASE("meta/meta_states/evalue") {
namespace meta = meta_hpp;
meta::enum_<color>()
.evalue_("red", color::red)
.evalue_("green", color::green)
.evalue_("blue", color::blue)
.evalue_("white", color::white);
const meta::enum_type color_type = meta::resolve_type<color>();
REQUIRE(color_type);
SUBCASE("") {
const meta::evalue evalue;
CHECK_FALSE(evalue);
CHECK_FALSE(evalue.is_valid());
CHECK(evalue == color_type.get_evalue("non-existent-evalue"));
}
SUBCASE("operators") {
const meta::evalue blue_e = color_type.get_evalue("blue");
const meta::evalue white_e = color_type.get_evalue("white");
CHECK(blue_e == blue_e);
CHECK(blue_e != white_e);
CHECK((blue_e < white_e || white_e < blue_e));
}
SUBCASE("green") {
const meta::evalue evalue = color_type.get_evalue("green");
REQUIRE(evalue);
CHECK(evalue.get_index().type == evalue.get_type());
CHECK(evalue.get_index().name == "green");
CHECK(evalue.get_type() == meta::resolve_type<color>());
CHECK(evalue.get_name() == "green");
CHECK(evalue.get_value() == color::green);
}
}

View File

@@ -0,0 +1,107 @@
/*******************************************************************************
* This file is part of the "https://github.com/blackmatov/meta.hpp"
* For conditions of distribution and use, see copyright notice in LICENSE.md
* Copyright (C) 2021, by Matvey Cherevko (blackmatov@gmail.com)
******************************************************************************/
#include "../meta_tests.hpp"
namespace
{
struct ivec2 {
int x{};
int y{};
static ivec2 iadd(const ivec2& l, const ivec2& r) noexcept {
return {l.x + r.x, l.y + r.y};
}
static int ilength2(const ivec2& v) noexcept {
return v.x * v.x + v.y * v.y;
}
};
bool operator==(const ivec2& l, const ivec2& r) noexcept {
return l.x == r.x && l.y == r.y;
}
}
TEST_CASE("meta/meta_states/function") {
namespace meta = meta_hpp;
meta::class_<ivec2>()
.function_("iadd", &ivec2::iadd)
.function_("ilength2", &ivec2::ilength2);
const meta::class_type ivec2_type = meta::resolve_type<ivec2>();
REQUIRE(ivec2_type);
SUBCASE("") {
const meta::function func;
CHECK_FALSE(func);
CHECK_FALSE(func.is_valid());
CHECK(func == ivec2_type.get_function("non-existent-function"));
}
SUBCASE("operators") {
const meta::function iadd_f = ivec2_type.get_function("iadd");
const meta::function ilength2_f = ivec2_type.get_function("ilength2");
CHECK(iadd_f == iadd_f);
CHECK(iadd_f != ilength2_f);
CHECK((iadd_f < ilength2_f || ilength2_f < iadd_f));
}
SUBCASE("iadd") {
const meta::function func = ivec2_type.get_function("iadd");
REQUIRE(func);
CHECK(func.get_index().type == func.get_type());
CHECK(func.get_index().name == "iadd");
CHECK(func.get_type() == meta::resolve_type(&ivec2::iadd));
CHECK(func.get_name() == "iadd");
CHECK_FALSE(func.is_invocable_with<>());
CHECK_FALSE(func.is_invocable_with<int>());
CHECK_FALSE(func.is_invocable_with<ivec2, int>());
CHECK_FALSE(func.is_invocable_with<int, ivec2>());
CHECK_FALSE(func.is_invocable_with<ivec2, ivec2, int>());
CHECK(func.is_invocable_with<ivec2, ivec2>());
CHECK(func.is_invocable_with<const ivec2&, ivec2&&>());
CHECK_THROWS(func.invoke());
CHECK_THROWS(func.invoke(42));
CHECK_THROWS(func.invoke(ivec2{}, 42));
CHECK_THROWS(func.invoke(42, ivec2{}));
CHECK_THROWS(func.invoke(ivec2{}, ivec2{}, 42));
CHECK(func.invoke(ivec2{1,2}, ivec2{3,4}));
CHECK(func.invoke(ivec2{1,2}, ivec2{3,4}).value() == ivec2{4,6});
}
SUBCASE("ilength2") {
const meta::function func = ivec2_type.get_function("ilength2");
REQUIRE(func);
CHECK(func.get_index().type == func.get_type());
CHECK(func.get_index().name == "ilength2");
CHECK(func.get_type() == meta::resolve_type(&ivec2::ilength2));
CHECK(func.get_name() == "ilength2");
CHECK_FALSE(func.is_invocable_with<>());
CHECK_FALSE(func.is_invocable_with<int>());
CHECK_FALSE(func.is_invocable_with<ivec2, int>());
CHECK(func.is_invocable_with<ivec2>());
CHECK(func.is_invocable_with<const ivec2&>());
CHECK_THROWS(func.invoke());
CHECK_THROWS(func.invoke(42));
CHECK_THROWS(func.invoke(ivec2{}, 42));
CHECK(func.invoke(ivec2{2,3}));
CHECK(func.invoke(ivec2{2,3}).value() == 13);
}
}

View File

@@ -0,0 +1,81 @@
/*******************************************************************************
* This file is part of the "https://github.com/blackmatov/meta.hpp"
* For conditions of distribution and use, see copyright notice in LICENSE.md
* Copyright (C) 2021, by Matvey Cherevko (blackmatov@gmail.com)
******************************************************************************/
#include "../meta_tests.hpp"
namespace
{
struct clazz_1 {
int int_member = 1;
const int const_int_member = 2;
};
}
TEST_CASE("meta/meta_states/member") {
namespace meta = meta_hpp;
meta::class_<clazz_1>()
.member_("int_member", &clazz_1::int_member)
.member_("const_int_member", &clazz_1::const_int_member);
const meta::class_type clazz_1_type = meta::resolve_type<clazz_1>();
REQUIRE(clazz_1_type);
SUBCASE("") {
const meta::member member;
CHECK_FALSE(member);
CHECK_FALSE(member.is_valid());
CHECK(member == clazz_1_type.get_member("non-existent-member"));
}
SUBCASE("operators") {
meta::member int_member_m = clazz_1_type.get_member("int_member");
meta::member const_int_member_m = clazz_1_type.get_member("const_int_member");
CHECK(int_member_m == int_member_m);
CHECK(int_member_m != const_int_member_m);
CHECK((int_member_m < const_int_member_m || const_int_member_m < int_member_m));
}
SUBCASE("int") {
meta::member vm = clazz_1_type.get_member("int_member");
REQUIRE(vm);
CHECK(vm.get_type() == meta::resolve_type(&clazz_1::int_member));
CHECK(vm.get_name() == "int_member");
clazz_1 v;
CHECK(vm.get(v) == 1);
CHECK(vm.get(std::as_const(v)) == 1);
CHECK(vm.get(std::move(v)) == 1);
CHECK(vm.get(std::move(std::as_const(v))) == 1);
CHECK_NOTHROW(vm.set(v, 10)); CHECK(vm.get(v) == 10);
CHECK_THROWS(vm.set(std::as_const(v), 11)); CHECK(vm.get(v) == 10);
CHECK_NOTHROW(vm.set(std::move(v), 12)); CHECK(vm.get(v) == 12);
CHECK_THROWS(vm.set(std::move(std::as_const(v)), 13)); CHECK(vm.get(v) == 12);
}
SUBCASE("const int") {
meta::member vm = clazz_1_type.get_member("const_int_member");
REQUIRE(vm);
CHECK(vm.get_type() == meta::resolve_type(&clazz_1::const_int_member));
CHECK(vm.get_name() == "const_int_member");
clazz_1 v;
CHECK(vm.get(v) == 2);
CHECK(vm.get(std::as_const(v)) == 2);
CHECK(vm.get(std::move(v)) == 2);
CHECK(vm.get(std::move(std::as_const(v))) == 2);
CHECK_THROWS(vm.set(v, 10)); CHECK(vm.get(v) == 2);
CHECK_THROWS(vm.set(std::as_const(v), 11)); CHECK(vm.get(v) == 2);
CHECK_THROWS(vm.set(std::move(v), 12)); CHECK(vm.get(v) == 2);
CHECK_THROWS(vm.set(std::move(std::as_const(v)), 13)); CHECK(vm.get(v) == 2);
}
}

View File

@@ -0,0 +1,829 @@
/*******************************************************************************
* This file is part of the "https://github.com/blackmatov/meta.hpp"
* For conditions of distribution and use, see copyright notice in LICENSE.md
* Copyright (C) 2021, by Matvey Cherevko (blackmatov@gmail.com)
******************************************************************************/
#include "../meta_tests.hpp"
namespace
{
struct clazz {
clazz() = default;
clazz(clazz&&) = delete;
clazz(const clazz&) = delete;
clazz& operator=(clazz&&) = delete;
clazz& operator=(const clazz&) = delete;
//
int non_const_method() { return 1; }
int non_const_method_noexcept() noexcept { return 2; }
int const_method() const { return 3; }
int const_method_noexcept() const noexcept { return 4; }
int non_const_method_ref() & { return 5; }
int non_const_method_noexcept_ref() & noexcept { return 6; }
int const_method_ref() const & { return 7; }
int const_method_noexcept_ref() const & noexcept { return 8; }
int non_const_method_rref() && { return 9; }
int non_const_method_noexcept_rref() && noexcept { return 10; }
int const_method_rref() const && { return 11; }
int const_method_noexcept_rref() const && noexcept { return 12; }
//
int non_const_method_volatile() volatile { return 1; }
int non_const_method_noexcept_volatile() volatile noexcept { return 2; }
int const_method_volatile() volatile const { return 3; }
int const_method_noexcept_volatile() volatile const noexcept { return 4; }
int non_const_method_ref_volatile() volatile & { return 5; }
int non_const_method_noexcept_ref_volatile() volatile & noexcept { return 6; }
int const_method_ref_volatile() volatile const & { return 7; }
int const_method_noexcept_ref_volatile() volatile const & noexcept { return 8; }
int non_const_method_rref_volatile() volatile && { return 9; }
int non_const_method_noexcept_rref_volatile() volatile && noexcept { return 10; }
int const_method_rref_volatile() volatile const && { return 11; }
int const_method_noexcept_rref_volatile() volatile const && noexcept { return 12; }
};
struct clazz2 {};
}
TEST_CASE("meta/meta_states/method") {
namespace meta = meta_hpp;
meta::class_<clazz>()
.method_("non_const_method", &clazz::non_const_method)
.method_("non_const_method_noexcept", &clazz::non_const_method_noexcept)
.method_("const_method", &clazz::const_method)
.method_("const_method_noexcept", &clazz::const_method_noexcept)
.method_("non_const_method_ref", &clazz::non_const_method_ref)
.method_("non_const_method_noexcept_ref", &clazz::non_const_method_noexcept_ref)
.method_("const_method_ref", &clazz::const_method_ref)
.method_("const_method_noexcept_ref", &clazz::const_method_noexcept_ref)
.method_("non_const_method_rref", &clazz::non_const_method_rref)
.method_("non_const_method_noexcept_rref", &clazz::non_const_method_noexcept_rref)
.method_("const_method_rref", &clazz::const_method_rref)
.method_("const_method_noexcept_rref", &clazz::const_method_noexcept_rref)
.method_("non_const_method_volatile", &clazz::non_const_method_volatile)
.method_("non_const_method_noexcept_volatile", &clazz::non_const_method_noexcept_volatile)
.method_("const_method_volatile", &clazz::const_method_volatile)
.method_("const_method_noexcept_volatile", &clazz::const_method_noexcept_volatile)
.method_("non_const_method_ref_volatile", &clazz::non_const_method_ref_volatile)
.method_("non_const_method_noexcept_ref_volatile", &clazz::non_const_method_noexcept_ref_volatile)
.method_("const_method_ref_volatile", &clazz::const_method_ref_volatile)
.method_("const_method_noexcept_ref_volatile", &clazz::const_method_noexcept_ref_volatile)
.method_("non_const_method_rref_volatile", &clazz::non_const_method_rref_volatile)
.method_("non_const_method_noexcept_rref_volatile", &clazz::non_const_method_noexcept_rref_volatile)
.method_("const_method_rref_volatile", &clazz::const_method_rref_volatile)
.method_("const_method_noexcept_rref_volatile", &clazz::const_method_noexcept_rref_volatile);
const meta::class_type ct = meta::resolve_type<clazz>();
REQUIRE(ct);
SUBCASE("") {
const meta::method method;
CHECK_FALSE(method);
CHECK_FALSE(method.is_valid());
CHECK(method == ct.get_method("non-existent-method"));
}
SUBCASE("operators") {
const meta::method non_const_method_m = ct.get_method("non_const_method");
const meta::method non_const_method_volatile_m = ct.get_method("non_const_method_volatile");
CHECK(non_const_method_m == non_const_method_m);
CHECK(non_const_method_m != non_const_method_volatile_m);
CHECK((non_const_method_m < non_const_method_volatile_m || non_const_method_volatile_m < non_const_method_m));
}
SUBCASE("non_const_method") {
const meta::method mi = ct.get_method("non_const_method");
REQUIRE(mi);
const meta::method mi2 = ct.get_method("non_const_method_volatile");
REQUIRE(mi2);
CHECK(mi.get_name() == "non_const_method");
CHECK(mi2.get_name() == "non_const_method_volatile");
{
CHECK(mi.get_type().get_arity() == 0);
CHECK(mi.get_type().get_owner_type() == meta::resolve_type<clazz>());
CHECK(mi.get_type().get_return_type() == meta::resolve_type<int>());
CHECK(mi.get_type().get_flags() == meta::method_flags{});
CHECK(mi2.get_type().get_arity() == 0);
CHECK(mi2.get_type().get_owner_type() == meta::resolve_type<clazz>());
CHECK(mi2.get_type().get_return_type() == meta::resolve_type<int>());
CHECK(mi2.get_type().get_flags() == meta::method_flags::is_volatile);
}
{
CHECK(mi.is_invocable_with<clazz&>());
CHECK_FALSE(mi.is_invocable_with<const clazz&>());
CHECK(mi.is_invocable_with<clazz&&>());
CHECK_FALSE(mi.is_invocable_with<const clazz&&>());
CHECK(mi2.is_invocable_with<clazz&>());
CHECK_FALSE(mi2.is_invocable_with<const clazz&>());
CHECK(mi2.is_invocable_with<clazz&&>());
CHECK_FALSE(mi2.is_invocable_with<const clazz&&>());
}
{
clazz cl;
CHECK(mi.invoke(cl).value() == 1);
CHECK_THROWS(mi.invoke(std::as_const(cl)));
CHECK(mi.invoke(std::move(cl)).value() == 1);
CHECK_THROWS(mi.invoke(std::move(std::as_const(cl))));
CHECK(mi2.invoke(cl).value() == 1);
CHECK_THROWS(mi2.invoke(std::as_const(cl)));
CHECK(mi2.invoke(std::move(cl)).value() == 1);
CHECK_THROWS(mi2.invoke(std::move(std::as_const(cl))));
}
static_assert(std::is_invocable_v<decltype(&clazz::non_const_method), clazz&>);
static_assert(!std::is_invocable_v<decltype(&clazz::non_const_method), const clazz&>);
static_assert(std::is_invocable_v<decltype(&clazz::non_const_method), clazz&&>);
static_assert(!std::is_invocable_v<decltype(&clazz::non_const_method), const clazz&&>);
static_assert(std::is_invocable_v<decltype(&clazz::non_const_method_volatile), clazz&>);
static_assert(!std::is_invocable_v<decltype(&clazz::non_const_method_volatile), const clazz&>);
static_assert(std::is_invocable_v<decltype(&clazz::non_const_method_volatile), clazz&&>);
static_assert(!std::is_invocable_v<decltype(&clazz::non_const_method_volatile), const clazz&&>);
}
SUBCASE("non_const_method_noexcept") {
const meta::method mi = ct.get_method("non_const_method_noexcept");
REQUIRE(mi);
const meta::method mi2 = ct.get_method("non_const_method_noexcept_volatile");
REQUIRE(mi2);
CHECK(mi.get_name() == "non_const_method_noexcept");
CHECK(mi2.get_name() == "non_const_method_noexcept_volatile");
{
CHECK(mi.get_type().get_arity() == 0);
CHECK(mi.get_type().get_owner_type() == meta::resolve_type<clazz>());
CHECK(mi.get_type().get_return_type() == meta::resolve_type<int>());
CHECK(mi.get_type().get_flags() == meta::method_flags::is_noexcept);
CHECK(mi2.get_type().get_arity() == 0);
CHECK(mi2.get_type().get_owner_type() == meta::resolve_type<clazz>());
CHECK(mi2.get_type().get_return_type() == meta::resolve_type<int>());
CHECK(mi2.get_type().get_flags() == (meta::method_flags::is_noexcept | meta::method_flags::is_volatile));
}
{
CHECK(mi.is_invocable_with<clazz&>());
CHECK_FALSE(mi.is_invocable_with<const clazz&>());
CHECK(mi.is_invocable_with<clazz&&>());
CHECK_FALSE(mi.is_invocable_with<const clazz&&>());
CHECK(mi2.is_invocable_with<clazz&>());
CHECK_FALSE(mi2.is_invocable_with<const clazz&>());
CHECK(mi2.is_invocable_with<clazz&&>());
CHECK_FALSE(mi2.is_invocable_with<const clazz&&>());
}
{
clazz cl;
CHECK(mi.invoke(cl).value() == 2);
CHECK_THROWS(mi.invoke(std::as_const(cl)));
CHECK(mi.invoke(std::move(cl)).value() == 2);
CHECK_THROWS(mi.invoke(std::move(std::as_const(cl))));
CHECK(mi2.invoke(cl).value() == 2);
CHECK_THROWS(mi2.invoke(std::as_const(cl)));
CHECK(mi2.invoke(std::move(cl)).value() == 2);
CHECK_THROWS(mi2.invoke(std::move(std::as_const(cl))));
}
static_assert(std::is_invocable_v<decltype(&clazz::non_const_method_noexcept), clazz&>);
static_assert(!std::is_invocable_v<decltype(&clazz::non_const_method_noexcept), const clazz&>);
static_assert(std::is_invocable_v<decltype(&clazz::non_const_method_noexcept), clazz&&>);
static_assert(!std::is_invocable_v<decltype(&clazz::non_const_method_noexcept), const clazz&&>);
static_assert(std::is_invocable_v<decltype(&clazz::non_const_method_noexcept_volatile), clazz&>);
static_assert(!std::is_invocable_v<decltype(&clazz::non_const_method_noexcept_volatile), const clazz&>);
static_assert(std::is_invocable_v<decltype(&clazz::non_const_method_noexcept_volatile), clazz&&>);
static_assert(!std::is_invocable_v<decltype(&clazz::non_const_method_noexcept_volatile), const clazz&&>);
}
SUBCASE("const_method") {
const meta::method mi = ct.get_method("const_method");
REQUIRE(mi);
const meta::method mi2 = ct.get_method("const_method_volatile");
REQUIRE(mi2);
CHECK(mi.get_name() == "const_method");
CHECK(mi2.get_name() == "const_method_volatile");
{
CHECK(mi.get_type().get_arity() == 0);
CHECK(mi.get_type().get_owner_type() == meta::resolve_type<clazz>());
CHECK(mi.get_type().get_return_type() == meta::resolve_type<int>());
CHECK(mi.get_type().get_flags() == meta::method_flags::is_const);
CHECK(mi2.get_type().get_arity() == 0);
CHECK(mi2.get_type().get_owner_type() == meta::resolve_type<clazz>());
CHECK(mi2.get_type().get_return_type() == meta::resolve_type<int>());
CHECK(mi2.get_type().get_flags() == (meta::method_flags::is_const | meta::method_flags::is_volatile));
}
{
CHECK(mi.is_invocable_with<clazz&>());
CHECK(mi.is_invocable_with<const clazz&>());
CHECK(mi.is_invocable_with<clazz&&>());
CHECK(mi.is_invocable_with<const clazz&&>());
CHECK(mi2.is_invocable_with<clazz&>());
CHECK(mi2.is_invocable_with<const clazz&>());
CHECK(mi2.is_invocable_with<clazz&&>());
CHECK(mi2.is_invocable_with<const clazz&&>());
}
{
clazz cl;
CHECK(mi.invoke(cl).value() == 3);
CHECK(mi.invoke(std::as_const(cl)).value() == 3);
CHECK(mi.invoke(std::move(cl)).value() == 3);
CHECK(mi.invoke(std::move(std::as_const(cl))).value() == 3);
CHECK(mi2.invoke(cl).value() == 3);
CHECK(mi2.invoke(std::as_const(cl)).value() == 3);
CHECK(mi2.invoke(std::move(cl)).value() == 3);
CHECK(mi2.invoke(std::move(std::as_const(cl))).value() == 3);
}
static_assert(std::is_invocable_v<decltype(&clazz::const_method), clazz&>);
static_assert(std::is_invocable_v<decltype(&clazz::const_method), const clazz&>);
static_assert(std::is_invocable_v<decltype(&clazz::const_method), clazz&&>);
static_assert(std::is_invocable_v<decltype(&clazz::const_method), const clazz&&>);
static_assert(std::is_invocable_v<decltype(&clazz::const_method_volatile), clazz&>);
static_assert(std::is_invocable_v<decltype(&clazz::const_method_volatile), const clazz&>);
static_assert(std::is_invocable_v<decltype(&clazz::const_method_volatile), clazz&&>);
static_assert(std::is_invocable_v<decltype(&clazz::const_method_volatile), const clazz&&>);
}
SUBCASE("const_method_noexcept") {
const meta::method mi = ct.get_method("const_method_noexcept");
REQUIRE(mi);
const meta::method mi2 = ct.get_method("const_method_noexcept_volatile");
REQUIRE(mi2);
CHECK(mi.get_name() == "const_method_noexcept");
CHECK(mi2.get_name() == "const_method_noexcept_volatile");
{
CHECK(mi.get_type().get_arity() == 0);
CHECK(mi.get_type().get_owner_type() == meta::resolve_type<clazz>());
CHECK(mi.get_type().get_return_type() == meta::resolve_type<int>());
CHECK(mi.get_type().get_flags() == (meta::method_flags::is_const | meta::method_flags::is_noexcept));
CHECK(mi2.get_type().get_arity() == 0);
CHECK(mi2.get_type().get_owner_type() == meta::resolve_type<clazz>());
CHECK(mi2.get_type().get_return_type() == meta::resolve_type<int>());
CHECK(mi2.get_type().get_flags() == (meta::method_flags::is_const | meta::method_flags::is_noexcept | meta::method_flags::is_volatile));
}
{
CHECK(mi.is_invocable_with<clazz&>());
CHECK(mi.is_invocable_with<const clazz&>());
CHECK(mi.is_invocable_with<clazz&&>());
CHECK(mi.is_invocable_with<const clazz&&>());
CHECK(mi2.is_invocable_with<clazz&>());
CHECK(mi2.is_invocable_with<const clazz&>());
CHECK(mi2.is_invocable_with<clazz&&>());
CHECK(mi2.is_invocable_with<const clazz&&>());
}
{
clazz cl;
CHECK(mi.invoke(cl).value() == 4);
CHECK(mi.invoke(std::as_const(cl)).value() == 4);
CHECK(mi.invoke(std::move(cl)).value() == 4);
CHECK(mi.invoke(std::move(std::as_const(cl))).value() == 4);
CHECK(mi2.invoke(cl).value() == 4);
CHECK(mi2.invoke(std::as_const(cl)).value() == 4);
CHECK(mi2.invoke(std::move(cl)).value() == 4);
CHECK(mi2.invoke(std::move(std::as_const(cl))).value() == 4);
}
static_assert(std::is_invocable_v<decltype(&clazz::const_method_noexcept), clazz&>);
static_assert(std::is_invocable_v<decltype(&clazz::const_method_noexcept), const clazz&>);
static_assert(std::is_invocable_v<decltype(&clazz::const_method_noexcept), clazz&&>);
static_assert(std::is_invocable_v<decltype(&clazz::const_method_noexcept), const clazz&&>);
static_assert(std::is_invocable_v<decltype(&clazz::const_method_noexcept_volatile), clazz&>);
static_assert(std::is_invocable_v<decltype(&clazz::const_method_noexcept_volatile), const clazz&>);
static_assert(std::is_invocable_v<decltype(&clazz::const_method_noexcept_volatile), clazz&&>);
static_assert(std::is_invocable_v<decltype(&clazz::const_method_noexcept_volatile), const clazz&&>);
}
SUBCASE("non_const_method_ref") {
const meta::method mi = ct.get_method("non_const_method_ref");
REQUIRE(mi);
const meta::method mi2 = ct.get_method("non_const_method_ref_volatile");
REQUIRE(mi2);
CHECK(mi.get_name() == "non_const_method_ref");
CHECK(mi2.get_name() == "non_const_method_ref_volatile");
{
CHECK(mi.get_type().get_arity() == 0);
CHECK(mi.get_type().get_owner_type() == meta::resolve_type<clazz>());
CHECK(mi.get_type().get_return_type() == meta::resolve_type<int>());
CHECK(mi.get_type().get_flags() == meta::method_flags::is_lvalue_qualified);
CHECK(mi2.get_type().get_arity() == 0);
CHECK(mi2.get_type().get_owner_type() == meta::resolve_type<clazz>());
CHECK(mi2.get_type().get_return_type() == meta::resolve_type<int>());
CHECK(mi2.get_type().get_flags() == (meta::method_flags::is_volatile | meta::method_flags::is_lvalue_qualified));
}
{
CHECK(mi.is_invocable_with<clazz&>());
CHECK_FALSE(mi.is_invocable_with<const clazz&>());
CHECK_FALSE(mi.is_invocable_with<clazz&&>());
CHECK_FALSE(mi.is_invocable_with<const clazz&&>());
CHECK(mi2.is_invocable_with<clazz&>());
CHECK_FALSE(mi2.is_invocable_with<const clazz&>());
CHECK_FALSE(mi2.is_invocable_with<clazz&&>());
CHECK_FALSE(mi2.is_invocable_with<const clazz&&>());
}
{
clazz cl;
CHECK(mi.invoke(cl).value() == 5);
CHECK_THROWS(mi.invoke(std::as_const(cl)));
CHECK_THROWS(mi.invoke(std::move(cl)));
CHECK_THROWS(mi.invoke(std::move(std::as_const(cl))));
CHECK(mi2.invoke(cl).value() == 5);
CHECK_THROWS(mi2.invoke(std::as_const(cl)));
CHECK_THROWS(mi2.invoke(std::move(cl)));
CHECK_THROWS(mi2.invoke(std::move(std::as_const(cl))));
}
static_assert(std::is_invocable_v<decltype(&clazz::non_const_method_ref), clazz&>);
static_assert(!std::is_invocable_v<decltype(&clazz::non_const_method_ref), const clazz&>);
static_assert(!std::is_invocable_v<decltype(&clazz::non_const_method_ref), clazz&&>);
static_assert(!std::is_invocable_v<decltype(&clazz::non_const_method_ref), const clazz&&>);
static_assert(std::is_invocable_v<decltype(&clazz::non_const_method_ref_volatile), clazz&>);
static_assert(!std::is_invocable_v<decltype(&clazz::non_const_method_ref_volatile), const clazz&>);
static_assert(!std::is_invocable_v<decltype(&clazz::non_const_method_ref_volatile), clazz&&>);
static_assert(!std::is_invocable_v<decltype(&clazz::non_const_method_ref_volatile), const clazz&&>);
}
SUBCASE("non_const_method_noexcept_ref") {
const meta::method mi = ct.get_method("non_const_method_noexcept_ref");
REQUIRE(mi);
const meta::method mi2 = ct.get_method("non_const_method_noexcept_ref_volatile");
REQUIRE(mi2);
CHECK(mi.get_name() == "non_const_method_noexcept_ref");
CHECK(mi2.get_name() == "non_const_method_noexcept_ref_volatile");
{
CHECK(mi.get_type().get_arity() == 0);
CHECK(mi.get_type().get_owner_type() == meta::resolve_type<clazz>());
CHECK(mi.get_type().get_return_type() == meta::resolve_type<int>());
CHECK(mi.get_type().get_flags() == (meta::method_flags::is_noexcept | meta::method_flags::is_lvalue_qualified));
CHECK(mi2.get_type().get_arity() == 0);
CHECK(mi2.get_type().get_owner_type() == meta::resolve_type<clazz>());
CHECK(mi2.get_type().get_return_type() == meta::resolve_type<int>());
CHECK(mi2.get_type().get_flags() == (meta::method_flags::is_noexcept | meta::method_flags::is_volatile | meta::method_flags::is_lvalue_qualified));
}
{
CHECK(mi.is_invocable_with<clazz&>());
CHECK_FALSE(mi.is_invocable_with<const clazz&>());
CHECK_FALSE(mi.is_invocable_with<clazz&&>());
CHECK_FALSE(mi.is_invocable_with<const clazz&&>());
CHECK(mi2.is_invocable_with<clazz&>());
CHECK_FALSE(mi2.is_invocable_with<const clazz&>());
CHECK_FALSE(mi2.is_invocable_with<clazz&&>());
CHECK_FALSE(mi2.is_invocable_with<const clazz&&>());
}
{
clazz cl;
CHECK(mi.invoke(cl).value() == 6);
CHECK_THROWS(mi.invoke(std::as_const(cl)));
CHECK_THROWS(mi.invoke(std::move(cl)));
CHECK_THROWS(mi.invoke(std::move(std::as_const(cl))));
CHECK(mi2.invoke(cl).value() == 6);
CHECK_THROWS(mi2.invoke(std::as_const(cl)));
CHECK_THROWS(mi2.invoke(std::move(cl)));
CHECK_THROWS(mi2.invoke(std::move(std::as_const(cl))));
}
static_assert(std::is_invocable_v<decltype(&clazz::non_const_method_noexcept_ref), clazz&>);
static_assert(!std::is_invocable_v<decltype(&clazz::non_const_method_noexcept_ref), const clazz&>);
static_assert(!std::is_invocable_v<decltype(&clazz::non_const_method_noexcept_ref), clazz&&>);
static_assert(!std::is_invocable_v<decltype(&clazz::non_const_method_noexcept_ref), const clazz&&>);
static_assert(std::is_invocable_v<decltype(&clazz::non_const_method_noexcept_ref_volatile), clazz&>);
static_assert(!std::is_invocable_v<decltype(&clazz::non_const_method_noexcept_ref_volatile), const clazz&>);
static_assert(!std::is_invocable_v<decltype(&clazz::non_const_method_noexcept_ref_volatile), clazz&&>);
static_assert(!std::is_invocable_v<decltype(&clazz::non_const_method_noexcept_ref_volatile), const clazz&&>);
}
SUBCASE("const_method_ref") {
const meta::method mi = ct.get_method("const_method_ref");
REQUIRE(mi);
const meta::method mi2 = ct.get_method("const_method_ref_volatile");
REQUIRE(mi2);
CHECK(mi.get_name() == "const_method_ref");
CHECK(mi2.get_name() == "const_method_ref_volatile");
{
CHECK(mi.get_type().get_arity() == 0);
CHECK(mi.get_type().get_owner_type() == meta::resolve_type<clazz>());
CHECK(mi.get_type().get_return_type() == meta::resolve_type<int>());
CHECK(mi.get_type().get_flags() == (meta::method_flags::is_const | meta::method_flags::is_lvalue_qualified));
CHECK(mi2.get_type().get_arity() == 0);
CHECK(mi2.get_type().get_owner_type() == meta::resolve_type<clazz>());
CHECK(mi2.get_type().get_return_type() == meta::resolve_type<int>());
CHECK(mi2.get_type().get_flags() == (meta::method_flags::is_const | meta::method_flags::is_volatile | meta::method_flags::is_lvalue_qualified));
}
{
CHECK(mi.is_invocable_with<clazz&>());
CHECK(mi.is_invocable_with<const clazz&>());
CHECK_FALSE(mi.is_invocable_with<clazz&&>());
CHECK_FALSE(mi.is_invocable_with<const clazz&&>());
CHECK(mi2.is_invocable_with<clazz&>());
CHECK(mi2.is_invocable_with<const clazz&>());
CHECK_FALSE(mi2.is_invocable_with<clazz&&>());
CHECK_FALSE(mi2.is_invocable_with<const clazz&&>());
}
{
clazz cl;
CHECK(mi.invoke(cl).value() == 7);
CHECK(mi.invoke(std::as_const(cl)).value() == 7);
CHECK_THROWS(mi.invoke(std::move(cl)));
CHECK_THROWS(mi.invoke(std::move(std::as_const(cl))));
CHECK(mi2.invoke(cl).value() == 7);
CHECK(mi2.invoke(std::as_const(cl)).value() == 7);
CHECK_THROWS(mi2.invoke(std::move(cl)));
CHECK_THROWS(mi2.invoke(std::move(std::as_const(cl))));
}
static_assert(std::is_invocable_v<decltype(&clazz::const_method_ref), clazz&>);
static_assert(std::is_invocable_v<decltype(&clazz::const_method_ref), const clazz&>);
//static_assert(!std::is_invocable_v<decltype(&clazz::const_method_ref), clazz&&>); // msvc issue
//static_assert(!std::is_invocable_v<decltype(&clazz::const_method_ref), const clazz&&>); // msvc issue
static_assert(std::is_invocable_v<decltype(&clazz::const_method_ref_volatile), clazz&>);
static_assert(std::is_invocable_v<decltype(&clazz::const_method_ref_volatile), const clazz&>);
static_assert(!std::is_invocable_v<decltype(&clazz::const_method_ref_volatile), clazz&&>);
static_assert(!std::is_invocable_v<decltype(&clazz::const_method_ref_volatile), const clazz&&>);
}
SUBCASE("const_method_noexcept_ref") {
const meta::method mi = ct.get_method("const_method_noexcept_ref");
REQUIRE(mi);
const meta::method mi2 = ct.get_method("const_method_noexcept_ref_volatile");
REQUIRE(mi2);
CHECK(mi.get_name() == "const_method_noexcept_ref");
CHECK(mi2.get_name() == "const_method_noexcept_ref_volatile");
{
CHECK(mi.get_type().get_arity() == 0);
CHECK(mi.get_type().get_owner_type() == meta::resolve_type<clazz>());
CHECK(mi.get_type().get_return_type() == meta::resolve_type<int>());
CHECK(mi.get_type().get_flags() == (meta::method_flags::is_const | meta::method_flags::is_noexcept | meta::method_flags::is_lvalue_qualified));
CHECK(mi2.get_type().get_arity() == 0);
CHECK(mi2.get_type().get_owner_type() == meta::resolve_type<clazz>());
CHECK(mi2.get_type().get_return_type() == meta::resolve_type<int>());
CHECK(mi2.get_type().get_flags() == (meta::method_flags::is_const | meta::method_flags::is_noexcept | meta::method_flags::is_volatile | meta::method_flags::is_lvalue_qualified));
}
{
CHECK(mi.is_invocable_with<clazz&>());
CHECK(mi.is_invocable_with<const clazz&>());
CHECK_FALSE(mi.is_invocable_with<clazz&&>());
CHECK_FALSE(mi.is_invocable_with<const clazz&&>());
CHECK(mi2.is_invocable_with<clazz&>());
CHECK(mi2.is_invocable_with<const clazz&>());
CHECK_FALSE(mi2.is_invocable_with<clazz&&>());
CHECK_FALSE(mi2.is_invocable_with<const clazz&&>());
}
{
clazz cl;
CHECK(mi.invoke(cl).value() == 8);
CHECK(mi.invoke(std::as_const(cl)).value() == 8);
CHECK_THROWS(mi.invoke(std::move(cl)));
CHECK_THROWS(mi.invoke(std::move(std::as_const(cl))));
CHECK(mi2.invoke(cl).value() == 8);
CHECK(mi2.invoke(std::as_const(cl)).value() == 8);
CHECK_THROWS(mi2.invoke(std::move(cl)));
CHECK_THROWS(mi2.invoke(std::move(std::as_const(cl))));
}
static_assert(std::is_invocable_v<decltype(&clazz::const_method_noexcept_ref), clazz&>);
static_assert(std::is_invocable_v<decltype(&clazz::const_method_noexcept_ref), const clazz&>);
//static_assert(!std::is_invocable_v<decltype(&clazz::const_method_noexcept_ref), clazz&&>); // msvc issue
//static_assert(!std::is_invocable_v<decltype(&clazz::const_method_noexcept_ref), const clazz&&>); // msvc issue
static_assert(std::is_invocable_v<decltype(&clazz::const_method_noexcept_ref_volatile), clazz&>);
static_assert(std::is_invocable_v<decltype(&clazz::const_method_noexcept_ref_volatile), const clazz&>);
static_assert(!std::is_invocable_v<decltype(&clazz::const_method_noexcept_ref_volatile), clazz&&>);
static_assert(!std::is_invocable_v<decltype(&clazz::const_method_noexcept_ref_volatile), const clazz&&>);
}
SUBCASE("non_const_method_rref") {
const meta::method mi = ct.get_method("non_const_method_rref");
REQUIRE(mi);
const meta::method mi2 = ct.get_method("non_const_method_rref_volatile");
REQUIRE(mi2);
CHECK(mi.get_name() == "non_const_method_rref");
CHECK(mi2.get_name() == "non_const_method_rref_volatile");
{
CHECK(mi.get_type().get_arity() == 0);
CHECK(mi.get_type().get_owner_type() == meta::resolve_type<clazz>());
CHECK(mi.get_type().get_return_type() == meta::resolve_type<int>());
CHECK(mi.get_type().get_flags() == meta::method_flags::is_rvalue_qualified);
CHECK(mi2.get_type().get_arity() == 0);
CHECK(mi2.get_type().get_owner_type() == meta::resolve_type<clazz>());
CHECK(mi2.get_type().get_return_type() == meta::resolve_type<int>());
CHECK(mi2.get_type().get_flags() == (meta::method_flags::is_volatile | meta::method_flags::is_rvalue_qualified));
}
{
CHECK_FALSE(mi.is_invocable_with<clazz&>());
CHECK_FALSE(mi.is_invocable_with<const clazz&>());
CHECK(mi.is_invocable_with<clazz&&>());
CHECK_FALSE(mi.is_invocable_with<const clazz&&>());
CHECK_FALSE(mi2.is_invocable_with<clazz&>());
CHECK_FALSE(mi2.is_invocable_with<const clazz&>());
CHECK(mi2.is_invocable_with<clazz&&>());
CHECK_FALSE(mi2.is_invocable_with<const clazz&&>());
}
{
clazz cl;
CHECK_THROWS(mi.invoke(cl));
CHECK_THROWS(mi.invoke(std::as_const(cl)));
CHECK(mi.invoke(std::move(cl)).value() == 9);
CHECK_THROWS(mi.invoke(std::move(std::as_const(cl))));
CHECK_THROWS(mi2.invoke(cl));
CHECK_THROWS(mi2.invoke(std::as_const(cl)));
CHECK(mi2.invoke(std::move(cl)).value() == 9);
CHECK_THROWS(mi2.invoke(std::move(std::as_const(cl))));
}
static_assert(!std::is_invocable_v<decltype(&clazz::non_const_method_rref), clazz&>);
static_assert(!std::is_invocable_v<decltype(&clazz::non_const_method_rref), const clazz&>);
static_assert(std::is_invocable_v<decltype(&clazz::non_const_method_rref), clazz&&>);
static_assert(!std::is_invocable_v<decltype(&clazz::non_const_method_rref), const clazz&&>);
static_assert(!std::is_invocable_v<decltype(&clazz::non_const_method_rref_volatile), clazz&>);
static_assert(!std::is_invocable_v<decltype(&clazz::non_const_method_rref_volatile), const clazz&>);
static_assert(std::is_invocable_v<decltype(&clazz::non_const_method_rref_volatile), clazz&&>);
static_assert(!std::is_invocable_v<decltype(&clazz::non_const_method_rref_volatile), const clazz&&>);
}
SUBCASE("non_const_method_noexcept_rref") {
const meta::method mi = ct.get_method("non_const_method_noexcept_rref");
REQUIRE(mi);
const meta::method mi2 = ct.get_method("non_const_method_noexcept_rref_volatile");
REQUIRE(mi2);
CHECK(mi.get_name() == "non_const_method_noexcept_rref");
CHECK(mi2.get_name() == "non_const_method_noexcept_rref_volatile");
{
CHECK(mi.get_type().get_arity() == 0);
CHECK(mi.get_type().get_owner_type() == meta::resolve_type<clazz>());
CHECK(mi.get_type().get_return_type() == meta::resolve_type<int>());
CHECK(mi.get_type().get_flags() == (meta::method_flags::is_noexcept | meta::method_flags::is_rvalue_qualified));
CHECK(mi2.get_type().get_arity() == 0);
CHECK(mi2.get_type().get_owner_type() == meta::resolve_type<clazz>());
CHECK(mi2.get_type().get_return_type() == meta::resolve_type<int>());
CHECK(mi2.get_type().get_flags() == (meta::method_flags::is_noexcept | meta::method_flags::is_volatile | meta::method_flags::is_rvalue_qualified));
}
{
CHECK_FALSE(mi.is_invocable_with<clazz&>());
CHECK_FALSE(mi.is_invocable_with<const clazz&>());
CHECK(mi.is_invocable_with<clazz&&>());
CHECK_FALSE(mi.is_invocable_with<const clazz&&>());
CHECK_FALSE(mi2.is_invocable_with<clazz&>());
CHECK_FALSE(mi2.is_invocable_with<const clazz&>());
CHECK(mi2.is_invocable_with<clazz&&>());
CHECK_FALSE(mi2.is_invocable_with<const clazz&&>());
}
{
clazz cl;
CHECK_THROWS(mi.invoke(cl));
CHECK_THROWS(mi.invoke(std::as_const(cl)));
CHECK(mi.invoke(std::move(cl)).value() == 10);
CHECK_THROWS(mi.invoke(std::move(std::as_const(cl))));
CHECK_THROWS(mi2.invoke(cl));
CHECK_THROWS(mi2.invoke(std::as_const(cl)));
CHECK(mi2.invoke(std::move(cl)).value() == 10);
CHECK_THROWS(mi2.invoke(std::move(std::as_const(cl))));
}
static_assert(!std::is_invocable_v<decltype(&clazz::non_const_method_noexcept_rref), clazz&>);
static_assert(!std::is_invocable_v<decltype(&clazz::non_const_method_noexcept_rref), const clazz&>);
static_assert(std::is_invocable_v<decltype(&clazz::non_const_method_noexcept_rref), clazz&&>);
static_assert(!std::is_invocable_v<decltype(&clazz::non_const_method_noexcept_rref), const clazz&&>);
static_assert(!std::is_invocable_v<decltype(&clazz::non_const_method_noexcept_rref_volatile), clazz&>);
static_assert(!std::is_invocable_v<decltype(&clazz::non_const_method_noexcept_rref_volatile), const clazz&>);
static_assert(std::is_invocable_v<decltype(&clazz::non_const_method_noexcept_rref_volatile), clazz&&>);
static_assert(!std::is_invocable_v<decltype(&clazz::non_const_method_noexcept_rref_volatile), const clazz&&>);
}
SUBCASE("const_method_rref") {
const meta::method mi = ct.get_method("const_method_rref");
REQUIRE(mi);
const meta::method mi2 = ct.get_method("const_method_rref_volatile");
REQUIRE(mi2);
CHECK(mi.get_name() == "const_method_rref");
CHECK(mi2.get_name() == "const_method_rref_volatile");
{
CHECK(mi.get_type().get_arity() == 0);
CHECK(mi.get_type().get_owner_type() == meta::resolve_type<clazz>());
CHECK(mi.get_type().get_return_type() == meta::resolve_type<int>());
CHECK(mi.get_type().get_flags() == (meta::method_flags::is_const | meta::method_flags::is_rvalue_qualified));
CHECK(mi2.get_type().get_arity() == 0);
CHECK(mi2.get_type().get_owner_type() == meta::resolve_type<clazz>());
CHECK(mi2.get_type().get_return_type() == meta::resolve_type<int>());
CHECK(mi2.get_type().get_flags() == (meta::method_flags::is_const | meta::method_flags::is_volatile | meta::method_flags::is_rvalue_qualified));
}
{
CHECK_FALSE(mi.is_invocable_with<clazz&>());
CHECK_FALSE(mi.is_invocable_with<const clazz&>());
CHECK(mi.is_invocable_with<clazz&&>());
CHECK(mi.is_invocable_with<const clazz&&>());
CHECK_FALSE(mi2.is_invocable_with<clazz&>());
CHECK_FALSE(mi2.is_invocable_with<const clazz&>());
CHECK(mi2.is_invocable_with<clazz&&>());
CHECK(mi2.is_invocable_with<const clazz&&>());
}
{
clazz cl;
CHECK_THROWS(mi.invoke(cl));
CHECK_THROWS(mi.invoke(std::as_const(cl)));
CHECK(mi.invoke(std::move(cl)).value() == 11);
CHECK(mi.invoke(std::move(std::as_const(cl))).value() == 11);
CHECK_THROWS(mi2.invoke(cl));
CHECK_THROWS(mi2.invoke(std::as_const(cl)));
CHECK(mi2.invoke(std::move(cl)).value() == 11);
CHECK(mi2.invoke(std::move(std::as_const(cl))).value() == 11);
}
static_assert(!std::is_invocable_v<decltype(&clazz::const_method_rref), clazz&>);
static_assert(!std::is_invocable_v<decltype(&clazz::const_method_rref), const clazz&>);
static_assert(std::is_invocable_v<decltype(&clazz::const_method_rref), clazz&&>);
static_assert(std::is_invocable_v<decltype(&clazz::const_method_rref), const clazz&&>);
static_assert(!std::is_invocable_v<decltype(&clazz::const_method_rref_volatile), clazz&>);
static_assert(!std::is_invocable_v<decltype(&clazz::const_method_rref_volatile), const clazz&>);
static_assert(std::is_invocable_v<decltype(&clazz::const_method_rref_volatile), clazz&&>);
static_assert(std::is_invocable_v<decltype(&clazz::const_method_rref_volatile), const clazz&&>);
}
SUBCASE("const_method_noexcept_rref") {
const meta::method mi = ct.get_method("const_method_noexcept_rref");
REQUIRE(mi);
const meta::method mi2 = ct.get_method("const_method_noexcept_rref_volatile");
REQUIRE(mi2);
CHECK(mi.get_name() == "const_method_noexcept_rref");
CHECK(mi2.get_name() == "const_method_noexcept_rref_volatile");
{
CHECK(mi.get_type().get_arity() == 0);
CHECK(mi.get_type().get_owner_type() == meta::resolve_type<clazz>());
CHECK(mi.get_type().get_return_type() == meta::resolve_type<int>());
CHECK(mi.get_type().get_flags() == (meta::method_flags::is_const | meta::method_flags::is_noexcept | meta::method_flags::is_rvalue_qualified));
CHECK(mi2.get_type().get_arity() == 0);
CHECK(mi2.get_type().get_owner_type() == meta::resolve_type<clazz>());
CHECK(mi2.get_type().get_return_type() == meta::resolve_type<int>());
CHECK(mi2.get_type().get_flags() == (meta::method_flags::is_const | meta::method_flags::is_noexcept | meta::method_flags::is_volatile | meta::method_flags::is_rvalue_qualified));
}
{
CHECK_FALSE(mi.is_invocable_with<clazz&>());
CHECK_FALSE(mi.is_invocable_with<const clazz&>());
CHECK(mi.is_invocable_with<clazz&&>());
CHECK(mi.is_invocable_with<const clazz&&>());
CHECK_FALSE(mi2.is_invocable_with<clazz&>());
CHECK_FALSE(mi2.is_invocable_with<const clazz&>());
CHECK(mi2.is_invocable_with<clazz&&>());
CHECK(mi2.is_invocable_with<const clazz&&>());
}
{
clazz cl;
CHECK_THROWS(mi.invoke(cl));
CHECK_THROWS(mi.invoke(std::as_const(cl)));
CHECK(mi.invoke(std::move(cl)).value() == 12);
CHECK(mi.invoke(std::move(std::as_const(cl))).value() == 12);
CHECK_THROWS(mi2.invoke(cl));
CHECK_THROWS(mi2.invoke(std::as_const(cl)));
CHECK(mi2.invoke(std::move(cl)).value() == 12);
CHECK(mi2.invoke(std::move(std::as_const(cl))).value() == 12);
}
static_assert(!std::is_invocable_v<decltype(&clazz::const_method_noexcept_rref), clazz&>);
static_assert(!std::is_invocable_v<decltype(&clazz::const_method_noexcept_rref), const clazz&>);
static_assert(std::is_invocable_v<decltype(&clazz::const_method_noexcept_rref), clazz&&>);
static_assert(std::is_invocable_v<decltype(&clazz::const_method_noexcept_rref), const clazz&&>);
static_assert(!std::is_invocable_v<decltype(&clazz::const_method_noexcept_rref_volatile), clazz&>);
static_assert(!std::is_invocable_v<decltype(&clazz::const_method_noexcept_rref_volatile), const clazz&>);
static_assert(std::is_invocable_v<decltype(&clazz::const_method_noexcept_rref_volatile), clazz&&>);
static_assert(std::is_invocable_v<decltype(&clazz::const_method_noexcept_rref_volatile), const clazz&&>);
}
}

View File

@@ -0,0 +1,114 @@
/*******************************************************************************
* This file is part of the "https://github.com/blackmatov/meta.hpp"
* For conditions of distribution and use, see copyright notice in LICENSE.md
* Copyright (C) 2021, by Matvey Cherevko (blackmatov@gmail.com)
******************************************************************************/
#include "../meta_tests.hpp"
namespace
{
enum class color {
red,
green,
blue,
};
struct ivec2 {
int x{};
int y{};
};
struct ivec3 {
int x{};
int y{};
int z{};
};
ivec2 iadd2(const ivec2& l, const ivec2& r) noexcept {
return {l.x + r.x, l.y + r.y};
}
ivec3 iadd3(const ivec3& l, const ivec3& r) noexcept {
return {l.x + r.x, l.y + r.y, l.z + r.z};
}
ivec2 global_ivec2 = ivec2{1, 0};
const ivec3 global_const_ivec3 = ivec3{1, 0};
}
TEST_CASE("meta/meta_states/scope") {
namespace meta = meta_hpp;
meta::scope_("meta/meta_states/scope/math")
.enum_<color>("color")
.class_<ivec2>("ivec2")
.class_<ivec3>("ivec3")
.function_("iadd2", &iadd2)
.function_("iadd3", &iadd3)
.variable_("global_ivec2", &global_ivec2)
.variable_("global_const_ivec3", &global_const_ivec3);
const meta::scope math_scope = meta::resolve_scope("meta/meta_states/scope/math");
REQUIRE(math_scope);
REQUIRE(math_scope.is_valid());
CHECK(math_scope.get_name() == "meta/meta_states/scope/math");
CHECK(math_scope.get_classes().size() == 2);
CHECK(math_scope.get_enums().size() == 1);
CHECK(math_scope.get_functions().size() == 2);
CHECK(math_scope.get_variables().size() == 2);
SUBCASE("") {
const meta::scope scope;
CHECK_FALSE(scope);
CHECK_FALSE(scope.is_valid());
}
SUBCASE("operators") {
const meta::scope math1_s = meta::resolve_scope("meta/meta_states/scope/math1");
const meta::scope math2_s = meta::resolve_scope("meta/meta_states/scope/math2");
CHECK(math1_s == math1_s);
CHECK(math1_s != math2_s);
CHECK((math1_s < math2_s || math2_s < math1_s));
}
SUBCASE("classes") {
CHECK_FALSE(math_scope.get_class("non-existent-class"));
const meta::class_type ivec2_type = math_scope.get_class("ivec2");
REQUIRE(ivec2_type);
const meta::class_type ivec3_type = math_scope.get_class("ivec3");
REQUIRE(ivec3_type);
}
SUBCASE("enums") {
CHECK_FALSE(math_scope.get_enum("non-existent-enum"));
const meta::enum_type color_type = math_scope.get_enum("color");
REQUIRE(color_type);
}
SUBCASE("functions") {
CHECK_FALSE(math_scope.get_function("non-existent-function"));
const meta::function iadd2_func = math_scope.get_function("iadd2");
REQUIRE(iadd2_func);
const meta::function iadd3_func = math_scope.get_function("iadd3");
REQUIRE(iadd3_func);
}
SUBCASE("variables") {
CHECK_FALSE(math_scope.get_variable("non-existent-variable"));
const meta::variable global_ivec2_var = math_scope.get_variable("global_ivec2");
REQUIRE(global_ivec2_var);
CHECK(global_ivec2_var.get_type().get_data_type() == meta::resolve_type<ivec2>());
const meta::variable global_const_ivec3_var = math_scope.get_variable("global_const_ivec3");
REQUIRE(global_const_ivec3_var);
CHECK(global_const_ivec3_var.get_type().get_data_type() == meta::resolve_type<ivec3>());
}
}

View File

@@ -0,0 +1,100 @@
/*******************************************************************************
* This file is part of the "https://github.com/blackmatov/meta.hpp"
* For conditions of distribution and use, see copyright notice in LICENSE.md
* Copyright (C) 2021, by Matvey Cherevko (blackmatov@gmail.com)
******************************************************************************/
#include "../meta_tests.hpp"
namespace
{
struct clazz_1 {
static int int_variable;
static const int const_int_variable;
static int& ref_int_variable;
static const int& const_ref_int_variable;
};
int clazz_1::int_variable = 1;
const int clazz_1::const_int_variable = 2;
int& clazz_1::ref_int_variable = clazz_1::int_variable;
const int& clazz_1::const_ref_int_variable = clazz_1::const_int_variable;
}
TEST_CASE("meta/meta_states/variable") {
namespace meta = meta_hpp;
meta::class_<clazz_1>()
.variable_("int_variable", &clazz_1::int_variable)
.variable_("const_int_variable", &clazz_1::const_int_variable)
.variable_("ref_int_variable", &clazz_1::ref_int_variable)
.variable_("const_ref_int_variable", &clazz_1::const_ref_int_variable);
const meta::class_type clazz_1_type = meta::resolve_type<clazz_1>();
REQUIRE(clazz_1_type);
SUBCASE("") {
const meta::variable variable;
CHECK_FALSE(variable);
CHECK_FALSE(variable.is_valid());
CHECK(variable == clazz_1_type.get_variable("non-existent-variable"));
}
SUBCASE("operators") {
meta::variable int_variable_v = clazz_1_type.get_variable("int_variable");
meta::variable const_int_variable_v = clazz_1_type.get_variable("const_int_variable");
CHECK(int_variable_v == int_variable_v);
CHECK(int_variable_v != const_int_variable_v);
CHECK((int_variable_v < const_int_variable_v || const_int_variable_v < int_variable_v));
}
SUBCASE("int") {
meta::variable vm = clazz_1_type.get_variable("int_variable");
REQUIRE(vm);
CHECK(vm.get_type() == meta::resolve_type(&clazz_1::int_variable));
CHECK(vm.get_name() == "int_variable");
CHECK(vm.get() == 1);
CHECK_NOTHROW(vm.set(10)); CHECK(vm.get() == 10);
}
SUBCASE("const int") {
meta::variable vm = clazz_1_type.get_variable("const_int_variable");
REQUIRE(vm);
CHECK(vm.get_type() == meta::resolve_type(&clazz_1::const_int_variable));
CHECK(vm.get_name() == "const_int_variable");
CHECK(vm.get() == 2);
CHECK_THROWS(vm.set(10)); CHECK(vm.get() == 2);
}
SUBCASE("ref int") {
meta::variable vm = clazz_1_type.get_variable("ref_int_variable");
REQUIRE(vm);
CHECK(vm.get_type() == meta::resolve_type(&clazz_1::ref_int_variable));
CHECK(vm.get_name() == "ref_int_variable");
CHECK(vm.get() == 10);
CHECK_NOTHROW(vm.set(20)); CHECK(vm.get() == 20);
}
SUBCASE("const ref int") {
meta::variable vm = clazz_1_type.get_variable("const_ref_int_variable");
REQUIRE(vm);
CHECK(vm.get_type() == meta::resolve_type(&clazz_1::const_ref_int_variable));
CHECK(vm.get_name() == "const_ref_int_variable");
CHECK(vm.get() == 2);
CHECK_THROWS(vm.set(10)); CHECK(vm.get() == 2);
}
}

View File

@@ -0,0 +1,41 @@
/*******************************************************************************
* This file is part of the "https://github.com/blackmatov/meta.hpp"
* For conditions of distribution and use, see copyright notice in LICENSE.md
* Copyright (C) 2021, by Matvey Cherevko (blackmatov@gmail.com)
******************************************************************************/
#include "../meta_tests.hpp"
namespace
{
}
TEST_CASE("meta/meta_types/array_type") {
namespace meta = meta_hpp;
SUBCASE("") {
const meta::array_type type;
CHECK_FALSE(type);
CHECK_FALSE(type.is_valid());
}
SUBCASE("int[]") {
const meta::array_type type = meta::resolve_type<int[]>();
REQUIRE(type);
CHECK(type.get_flags() == (meta::array_flags::is_unbounded));
CHECK(type.get_extent() == 0);
CHECK(type.get_data_type() == meta::resolve_type<int>());
}
SUBCASE("const unsigned[42][21]") {
const meta::array_type type = meta::resolve_type<const unsigned[42][21]>();
REQUIRE(type);
CHECK(type.get_flags() == (meta::array_flags::is_bounded));
CHECK(type.get_extent() == 42);
CHECK(type.get_data_type() == meta::resolve_type<const unsigned[21]>());
}
}

View File

@@ -0,0 +1,465 @@
/*******************************************************************************
* This file is part of the "https://github.com/blackmatov/meta.hpp"
* For conditions of distribution and use, see copyright notice in LICENSE.md
* Copyright (C) 2021, by Matvey Cherevko (blackmatov@gmail.com)
******************************************************************************/
#include "../meta_tests.hpp"
namespace
{
struct base_clazz_1 {
base_clazz_1(int) {}
int base_member_1 = 1;
int base_method_1() { return 1; }
static int base_function_1() { return 1; }
int base_method_1_overloaded(int i0) const { return i0; }
int base_method_1_overloaded(float f0) const { return static_cast<int>(f0); }
static int base_function_1_overloaded(int i0) { return i0; }
static int base_function_1_overloaded(int i0, int i1) { return i0 + i1; }
static int base_variable_1;
};
int base_clazz_1::base_variable_1 = 1;
struct base_clazz_2 {
base_clazz_2(float) {}
float base_member_2 = 2.0f;
float base_method_2() { return 2.0f; }
static float base_function_2() { return 2.f; }
static float base_variable_2;
};
float base_clazz_2::base_variable_2 = 2.0f;
struct derived_clazz final : base_clazz_1, base_clazz_2 {
derived_clazz(int i, float f)
: base_clazz_1{i}
, base_clazz_2{f} {}
double derived_member = 3.0;
double derived_method() { return 3.0; }
static double derived_function() { return 3.0; }
static constexpr double derived_variable = 3.0;
};
template < typename... Args >
struct variadic_clazz {};
}
TEST_CASE("meta/meta_types/class_type") {
namespace meta = meta_hpp;
meta::class_<base_clazz_1>()
.ctor_<int>()
.member_("base_member_1", &base_clazz_1::base_member_1)
.method_("base_method_1", &base_clazz_1::base_method_1)
.function_("base_function_1", &base_clazz_1::base_function_1)
.method_("base_method_1_overloaded", meta::select<int(int) const>(&base_clazz_1::base_method_1_overloaded))
.method_("base_method_1_overloaded", meta::select<int(float) const>(&base_clazz_1::base_method_1_overloaded))
.function_("base_function_1_overloaded", meta::select<int(int)>(&base_clazz_1::base_function_1_overloaded))
.function_("base_function_1_overloaded", meta::select<int(int,int)>(&base_clazz_1::base_function_1_overloaded))
.variable_("base_variable_1", &base_clazz_1::base_variable_1);
meta::class_<base_clazz_2>()
.ctor_<float>()
.member_("base_member_2", &base_clazz_2::base_member_2)
.method_("base_method_2", &base_clazz_2::base_method_2)
.function_("base_function_2", &base_clazz_2::base_function_2)
.variable_("base_variable_2", &base_clazz_2::base_variable_2);
meta::class_<derived_clazz>()
.ctor_<int, float>()
.base_<base_clazz_1>()
.base_<base_clazz_2>()
.member_("derived_member", &derived_clazz::derived_member)
.method_("derived_method", &derived_clazz::derived_method)
.function_("derived_function", &derived_clazz::derived_function)
.variable_("derived_variable", &derived_clazz::derived_variable);
const meta::class_type base_clazz_1_type = meta::resolve_type<base_clazz_1>();
REQUIRE(base_clazz_1_type);
const meta::class_type base_clazz_2_type = meta::resolve_type<base_clazz_2>();
REQUIRE(base_clazz_2_type);
const meta::class_type derived_clazz_type = meta::resolve_type<const derived_clazz>();
REQUIRE(derived_clazz_type);
const meta::class_type variadic_clazz_int_type = meta::resolve_type<variadic_clazz<int>>();
REQUIRE(variadic_clazz_int_type);
const meta::class_type variadic_clazz_int_float_type = meta::resolve_type<variadic_clazz<int, float>>();
REQUIRE(variadic_clazz_int_float_type);
SUBCASE("get_flags") {
CHECK(base_clazz_1_type.get_flags() == meta::class_flags{});
CHECK(base_clazz_2_type.get_flags() == meta::class_flags{});
CHECK(derived_clazz_type.get_flags() == meta::class_flags::is_final);
CHECK(variadic_clazz_int_type.get_flags() == (meta::class_flags::is_empty | meta::class_flags::is_template_instantiation));
CHECK(variadic_clazz_int_float_type.get_flags() == (meta::class_flags::is_empty | meta::class_flags::is_template_instantiation));
}
SUBCASE("get_size") {
CHECK(base_clazz_1_type.get_size() == sizeof(base_clazz_1));
CHECK(base_clazz_2_type.get_size() == sizeof(base_clazz_2));
CHECK(derived_clazz_type.get_size() == sizeof(derived_clazz));
}
SUBCASE("get_arity") {
{
const meta::class_type type = meta::resolve_type<derived_clazz>();
REQUIRE(type);
CHECK(type.get_arity() == 0);
}
{
const meta::class_type type = meta::resolve_type<variadic_clazz<int>>();
REQUIRE(type);
CHECK(type.get_arity() == 1);
}
{
const meta::class_type type = meta::resolve_type<variadic_clazz<int, float>>();
REQUIRE(type);
CHECK(type.get_arity() == 2);
}
}
SUBCASE("get_argument_type") {
{
const meta::class_type type = meta::resolve_type<derived_clazz>();
REQUIRE(type);
CHECK_FALSE(type.get_argument_type(0));
}
{
const meta::class_type type = meta::resolve_type<variadic_clazz<int>>();
REQUIRE(type);
CHECK(type.get_argument_type(0) == meta::resolve_type<int>());
CHECK_FALSE(type.get_argument_type(1));
}
{
const meta::class_type type = meta::resolve_type<variadic_clazz<int, float>>();
REQUIRE(type);
CHECK(type.get_argument_type(0) == meta::resolve_type<int>());
CHECK(type.get_argument_type(1) == meta::resolve_type<float>());
CHECK_FALSE(type.get_argument_type(2));
}
}
SUBCASE("get_argument_types") {
{
const meta::class_type type = meta::resolve_type<derived_clazz>();
REQUIRE(type);
CHECK(type.get_argument_types() == std::vector<meta::any_type>{});
}
{
const meta::class_type type = meta::resolve_type<variadic_clazz<int>>();
REQUIRE(type);
CHECK(type.get_argument_types() == std::vector<meta::any_type>{meta::resolve_type<int>()});
}
{
const meta::class_type type = meta::resolve_type<variadic_clazz<int, float>>();
REQUIRE(type);
CHECK(type.get_argument_types() == std::vector<meta::any_type>{meta::resolve_type<int>(), meta::resolve_type<float>()});
}
}
SUBCASE("get_ctors") {
CHECK(base_clazz_1_type.get_ctors().size() == 1);
CHECK(base_clazz_2_type.get_ctors().size() == 1);
CHECK(derived_clazz_type.get_ctors().size() == 1);
}
SUBCASE("get_bases") {
CHECK(base_clazz_1_type.get_bases() == meta::class_set{});
CHECK(base_clazz_2_type.get_bases() == meta::class_set{});
CHECK(derived_clazz_type.get_bases() == meta::class_set{base_clazz_1_type, base_clazz_2_type});
}
SUBCASE("get_functions") {
CHECK(base_clazz_1_type.get_functions().size() == 3);
CHECK(base_clazz_2_type.get_functions().size() == 1);
CHECK(derived_clazz_type.get_functions().size() == 1);
}
SUBCASE("get_members") {
CHECK(base_clazz_1_type.get_members().size() == 1);
CHECK(base_clazz_2_type.get_members().size() == 1);
CHECK(derived_clazz_type.get_members().size() == 1);
}
SUBCASE("get_methods") {
CHECK(base_clazz_1_type.get_methods().size() == 3);
CHECK(base_clazz_2_type.get_methods().size() == 1);
CHECK(derived_clazz_type.get_methods().size() == 1);
}
SUBCASE("get_variables") {
CHECK(base_clazz_1_type.get_variables().size() == 1);
CHECK(base_clazz_2_type.get_variables().size() == 1);
CHECK(derived_clazz_type.get_variables().size() == 1);
}
SUBCASE("is_base_of") {
{
CHECK_FALSE(base_clazz_1_type.is_base_of<base_clazz_1>());
CHECK_FALSE(base_clazz_1_type.is_base_of(base_clazz_1_type));
CHECK_FALSE(base_clazz_1_type.is_base_of<base_clazz_2>());
CHECK_FALSE(base_clazz_1_type.is_base_of(base_clazz_2_type));
CHECK(base_clazz_1_type.is_base_of<derived_clazz>());
CHECK(base_clazz_1_type.is_base_of(derived_clazz_type));
}
{
CHECK_FALSE(base_clazz_2_type.is_base_of<base_clazz_1>());
CHECK_FALSE(base_clazz_2_type.is_base_of(base_clazz_1_type));
CHECK_FALSE(base_clazz_2_type.is_base_of<base_clazz_2>());
CHECK_FALSE(base_clazz_2_type.is_base_of(base_clazz_2_type));
CHECK(base_clazz_2_type.is_base_of<derived_clazz>());
CHECK(base_clazz_2_type.is_base_of(derived_clazz_type));
}
{
CHECK_FALSE(derived_clazz_type.is_base_of<base_clazz_1>());
CHECK_FALSE(derived_clazz_type.is_base_of(base_clazz_1_type));
CHECK_FALSE(derived_clazz_type.is_base_of<base_clazz_2>());
CHECK_FALSE(derived_clazz_type.is_base_of(base_clazz_2_type));
CHECK_FALSE(derived_clazz_type.is_base_of<derived_clazz>());
CHECK_FALSE(derived_clazz_type.is_base_of(derived_clazz_type));
}
}
SUBCASE("is_derived_from") {
{
CHECK_FALSE(base_clazz_1_type.is_derived_from<base_clazz_1>());
CHECK_FALSE(base_clazz_1_type.is_derived_from(base_clazz_1_type));
CHECK_FALSE(base_clazz_1_type.is_derived_from<base_clazz_2>());
CHECK_FALSE(base_clazz_1_type.is_derived_from(base_clazz_2_type));
CHECK_FALSE(base_clazz_1_type.is_derived_from<derived_clazz>());
CHECK_FALSE(base_clazz_1_type.is_derived_from(derived_clazz_type));
}
{
CHECK_FALSE(base_clazz_2_type.is_derived_from<base_clazz_1>());
CHECK_FALSE(base_clazz_2_type.is_derived_from(base_clazz_1_type));
CHECK_FALSE(base_clazz_2_type.is_derived_from<base_clazz_2>());
CHECK_FALSE(base_clazz_2_type.is_derived_from(base_clazz_2_type));
CHECK_FALSE(base_clazz_2_type.is_derived_from<derived_clazz>());
CHECK_FALSE(base_clazz_2_type.is_derived_from(derived_clazz_type));
}
{
CHECK(derived_clazz_type.is_derived_from<base_clazz_1>());
CHECK(derived_clazz_type.is_derived_from(base_clazz_1_type));
CHECK(derived_clazz_type.is_derived_from<base_clazz_2>());
CHECK(derived_clazz_type.is_derived_from(base_clazz_2_type));
CHECK_FALSE(derived_clazz_type.is_derived_from<derived_clazz>());
CHECK_FALSE(derived_clazz_type.is_derived_from(derived_clazz_type));
}
}
SUBCASE("get_function") {
CHECK(base_clazz_1_type.get_function("base_function_1"));
CHECK_FALSE(base_clazz_1_type.get_function("base_function_2"));
CHECK_FALSE(base_clazz_1_type.get_function("derived_function"));
CHECK_FALSE(base_clazz_2_type.get_function("base_function_1"));
CHECK(base_clazz_2_type.get_function("base_function_2"));
CHECK_FALSE(base_clazz_2_type.get_function("derived_function"));
CHECK(derived_clazz_type.get_function("base_function_1"));
CHECK(derived_clazz_type.get_function("base_function_2"));
CHECK(derived_clazz_type.get_function("derived_function"));
}
SUBCASE("get_member") {
CHECK(base_clazz_1_type.get_member("base_member_1"));
CHECK_FALSE(base_clazz_1_type.get_member("base_member_2"));
CHECK_FALSE(base_clazz_1_type.get_member("derived_member"));
CHECK_FALSE(base_clazz_2_type.get_member("base_member_1"));
CHECK(base_clazz_2_type.get_member("base_member_2"));
CHECK_FALSE(base_clazz_2_type.get_member("derived_member"));
CHECK(derived_clazz_type.get_member("base_member_1"));
CHECK(derived_clazz_type.get_member("base_member_2"));
CHECK(derived_clazz_type.get_member("derived_member"));
}
SUBCASE("get_method") {
CHECK(base_clazz_1_type.get_method("base_method_1"));
CHECK_FALSE(base_clazz_1_type.get_method("base_method_2"));
CHECK_FALSE(base_clazz_1_type.get_method("derived_method"));
CHECK_FALSE(base_clazz_2_type.get_method("base_method_1"));
CHECK(base_clazz_2_type.get_method("base_method_2"));
CHECK_FALSE(base_clazz_2_type.get_method("derived_method"));
CHECK(derived_clazz_type.get_method("base_method_1"));
CHECK(derived_clazz_type.get_method("base_method_2"));
CHECK(derived_clazz_type.get_method("derived_method"));
}
SUBCASE("get_variable") {
CHECK(base_clazz_1_type.get_variable("base_variable_1"));
CHECK_FALSE(base_clazz_1_type.get_variable("base_variable_2"));
CHECK_FALSE(base_clazz_1_type.get_variable("derived_variable"));
CHECK_FALSE(base_clazz_2_type.get_variable("base_variable_1"));
CHECK(base_clazz_2_type.get_variable("base_variable_2"));
CHECK_FALSE(base_clazz_2_type.get_variable("derived_variable"));
CHECK(derived_clazz_type.get_variable("base_variable_1"));
CHECK(derived_clazz_type.get_variable("base_variable_2"));
CHECK(derived_clazz_type.get_variable("derived_variable"));
}
SUBCASE("get_ctor_with") {
{
CHECK_FALSE(base_clazz_1_type.get_ctor_with<>());
CHECK(base_clazz_1_type.get_ctor_with<int>());
CHECK_FALSE(base_clazz_1_type.get_ctor_with<float>());
}
{
CHECK_FALSE(base_clazz_2_type.get_ctor_with<>());
CHECK_FALSE(base_clazz_2_type.get_ctor_with<int>());
CHECK(base_clazz_2_type.get_ctor_with<float>());
}
{
CHECK_FALSE(derived_clazz_type.get_ctor_with<>());
CHECK_FALSE(derived_clazz_type.get_ctor_with<int>());
CHECK_FALSE(derived_clazz_type.get_ctor_with<float>());
CHECK(derived_clazz_type.get_ctor_with<int, float>());
CHECK_FALSE(derived_clazz_type.get_ctor_with<float, int>());
}
}
SUBCASE("get_function_with") {
CHECK(base_clazz_1_type.get_function("base_function_1_overloaded"));
{
CHECK_FALSE(base_clazz_1_type.get_function_with<>("base_function_1_overloaded"));
CHECK(base_clazz_1_type.get_function_with<int>("base_function_1_overloaded"));
CHECK_FALSE(base_clazz_1_type.get_function_with<int, float>("base_function_1_overloaded"));
CHECK_FALSE(base_clazz_1_type.get_function_with<>("base_function_1_overloaded"));
CHECK_FALSE(base_clazz_1_type.get_function_with<float>("base_function_1_overloaded"));
CHECK(base_clazz_1_type.get_function_with<int, int>("base_function_1_overloaded"));
CHECK_FALSE(base_clazz_1_type.get_function_with<float, float>("base_function_1_overloaded"));
CHECK_FALSE(base_clazz_1_type.get_function_with<>("base_function_1_overloaded"));
CHECK_FALSE(base_clazz_1_type.get_function_with<double>("base_function_1_overloaded"));
CHECK_FALSE(base_clazz_1_type.get_function_with<double, double>("base_function_1_overloaded"));
}
{
meta::number_type int_type = meta::resolve_type<int>();
meta::number_type float_type = meta::resolve_type<float>();
meta::number_type double_type = meta::resolve_type<double>();
CHECK_FALSE(base_clazz_1_type.get_function_with<>("base_function_1_overloaded"));
CHECK(base_clazz_1_type.get_function_with("base_function_1_overloaded", {int_type}));
CHECK_FALSE(base_clazz_1_type.get_function_with("base_function_1_overloaded", {int_type, float_type}));
CHECK_FALSE(base_clazz_1_type.get_function_with("base_function_1_overloaded"));
CHECK_FALSE(base_clazz_1_type.get_function_with("base_function_1_overloaded", {float_type}));
CHECK(base_clazz_1_type.get_function_with("base_function_1_overloaded", {int_type, int_type}));
CHECK_FALSE(base_clazz_1_type.get_function_with("base_function_1_overloaded", {float_type, float_type}));
CHECK_FALSE(base_clazz_1_type.get_function_with<>("base_function_1_overloaded"));
CHECK_FALSE(base_clazz_1_type.get_function_with("base_function_1_overloaded", {double_type}));
CHECK_FALSE(base_clazz_1_type.get_function_with("base_function_1_overloaded", {double_type, double_type}));
}
{
meta::number_type int_type = meta::resolve_type<int>();
meta::number_type float_type = meta::resolve_type<float>();
meta::number_type double_type = meta::resolve_type<double>();
CHECK_FALSE(base_clazz_1_type.get_function_with<>("base_function_1_overloaded"));
CHECK(base_clazz_1_type.get_function_with("base_function_1_overloaded", std::vector<meta::any_type>{int_type}));
CHECK_FALSE(base_clazz_1_type.get_function_with("base_function_1_overloaded", std::vector<meta::any_type>{int_type, float_type}));
CHECK_FALSE(base_clazz_1_type.get_function_with("base_function_1_overloaded"));
CHECK_FALSE(base_clazz_1_type.get_function_with("base_function_1_overloaded", std::vector<meta::any_type>{float_type}));
CHECK(base_clazz_1_type.get_function_with("base_function_1_overloaded", std::vector<meta::any_type>{int_type, int_type}));
CHECK_FALSE(base_clazz_1_type.get_function_with("base_function_1_overloaded", std::vector<meta::any_type>{float_type, float_type}));
CHECK_FALSE(base_clazz_1_type.get_function_with<>("base_function_1_overloaded"));
CHECK_FALSE(base_clazz_1_type.get_function_with("base_function_1_overloaded", std::vector<meta::any_type>{double_type}));
CHECK_FALSE(base_clazz_1_type.get_function_with("base_function_1_overloaded", std::vector<meta::any_type>{double_type, double_type}));
}
}
SUBCASE("get_method_with") {
CHECK(base_clazz_1_type.get_method("base_method_1_overloaded"));
{
CHECK_FALSE(base_clazz_1_type.get_method_with<>("base_method_1_overloaded"));
CHECK(base_clazz_1_type.get_method_with<int>("base_method_1_overloaded"));
CHECK_FALSE(base_clazz_1_type.get_method_with<int, int>("base_method_1_overloaded"));
CHECK_FALSE(base_clazz_1_type.get_method_with<>("base_method_1_overloaded"));
CHECK(base_clazz_1_type.get_method_with<float>("base_method_1_overloaded"));
CHECK_FALSE(base_clazz_1_type.get_method_with<float, float>("base_method_1_overloaded"));
CHECK_FALSE(base_clazz_1_type.get_method_with<>("base_method_1_overloaded"));
CHECK_FALSE(base_clazz_1_type.get_method_with<double>("base_method_1_overloaded"));
CHECK_FALSE(base_clazz_1_type.get_method_with<double, double>("base_method_1_overloaded"));
}
{
meta::number_type int_type = meta::resolve_type<int>();
meta::number_type float_type = meta::resolve_type<float>();
meta::number_type double_type = meta::resolve_type<double>();
CHECK_FALSE(base_clazz_1_type.get_method_with<>("base_method_1_overloaded"));
CHECK(base_clazz_1_type.get_method_with("base_method_1_overloaded", {int_type}));
CHECK_FALSE(base_clazz_1_type.get_method_with("base_method_1_overloaded", {int_type, int_type}));
CHECK_FALSE(base_clazz_1_type.get_method_with("base_method_1_overloaded"));
CHECK(base_clazz_1_type.get_method_with("base_method_1_overloaded", {float_type}));
CHECK_FALSE(base_clazz_1_type.get_method_with("base_method_1_overloaded", {float_type, float_type}));
CHECK_FALSE(base_clazz_1_type.get_method_with<>("base_method_1_overloaded"));
CHECK_FALSE(base_clazz_1_type.get_method_with("base_method_1_overloaded", {double_type}));
CHECK_FALSE(base_clazz_1_type.get_method_with("base_method_1_overloaded", {double_type, double_type}));
}
{
meta::number_type int_type = meta::resolve_type<int>();
meta::number_type float_type = meta::resolve_type<float>();
meta::number_type double_type = meta::resolve_type<double>();
CHECK_FALSE(base_clazz_1_type.get_method_with<>("base_method_1_overloaded"));
CHECK(base_clazz_1_type.get_method_with("base_method_1_overloaded", std::vector<meta::any_type>{int_type}));
CHECK_FALSE(base_clazz_1_type.get_method_with("base_method_1_overloaded", std::vector<meta::any_type>{int_type, int_type}));
CHECK_FALSE(base_clazz_1_type.get_method_with("base_method_1_overloaded"));
CHECK(base_clazz_1_type.get_method_with("base_method_1_overloaded", std::vector<meta::any_type>{float_type}));
CHECK_FALSE(base_clazz_1_type.get_method_with("base_method_1_overloaded", std::vector<meta::any_type>{float_type, float_type}));
CHECK_FALSE(base_clazz_1_type.get_method_with<>("base_method_1_overloaded"));
CHECK_FALSE(base_clazz_1_type.get_method_with("base_method_1_overloaded", std::vector<meta::any_type>{double_type}));
CHECK_FALSE(base_clazz_1_type.get_method_with("base_method_1_overloaded", std::vector<meta::any_type>{double_type, double_type}));
}
}
}

View File

@@ -0,0 +1,98 @@
/*******************************************************************************
* This file is part of the "https://github.com/blackmatov/meta.hpp"
* For conditions of distribution and use, see copyright notice in LICENSE.md
* Copyright (C) 2021, by Matvey Cherevko (blackmatov@gmail.com)
******************************************************************************/
#include "../meta_tests.hpp"
namespace
{
enum class color : unsigned {
red = 0xFF0000,
green = 0x00FF00,
blue = 0x0000FF,
white = red | green | blue,
};
}
TEST_CASE("meta/meta_types/enum_type") {
namespace meta = meta_hpp;
meta::enum_<color>()
.evalue_("red", color::red)
.evalue_("green", color::green)
.evalue_("blue", color::blue)
.evalue_("white", color::white);
SUBCASE("color") {
const meta::enum_type color_type = meta::resolve_type<color>();
REQUIRE(color_type);
CHECK(color_type.get_id() == meta::resolve_type(color{}).get_id());
CHECK(color_type.get_underlying_type() == meta::resolve_type<unsigned>());
CHECK(color_type.get_evalues().size() == 4);
}
SUBCASE("const color") {
const meta::enum_type color_type = meta::resolve_type<const color>();
REQUIRE(color_type);
CHECK(color_type.get_id() == meta::resolve_type(color{}).get_id());
CHECK(color_type.get_underlying_type() == meta::resolve_type<unsigned>());
CHECK(color_type.get_evalues().size() == 4);
}
SUBCASE("get_evalue") {
const meta::enum_type color_type = meta::resolve_type<color>();
REQUIRE(color_type);
{
const meta::evalue green_value = color_type.get_evalue("green");
REQUIRE(green_value);
CHECK(green_value.get_value() == color::green);
}
{
const meta::evalue yellow_value = color_type.get_evalue("yellow");
CHECK_FALSE(yellow_value);
}
}
SUBCASE("value_to_name") {
const meta::enum_type color_type = meta::resolve_type<color>();
REQUIRE(color_type);
{
REQUIRE(color_type.value_to_name(color::red));
CHECK(color_type.value_to_name(color::red) == "red");
}
{
REQUIRE(color_type.value_to_name(meta::value{color::blue}));
CHECK(color_type.value_to_name(color::blue) == "blue");
}
{
REQUIRE_FALSE(color_type.value_to_name(100500));
REQUIRE_FALSE(color_type.value_to_name(color{100500}));
}
}
SUBCASE("name_to_value") {
const meta::enum_type color_type = meta::resolve_type<color>();
REQUIRE(color_type);
{
REQUIRE(color_type.name_to_value("blue"));
CHECK(color_type.name_to_value("blue") == color::blue);
}
{
REQUIRE_FALSE(color_type.name_to_value("yellow"));
}
}
}

View File

@@ -0,0 +1,68 @@
/*******************************************************************************
* This file is part of the "https://github.com/blackmatov/meta.hpp"
* For conditions of distribution and use, see copyright notice in LICENSE.md
* Copyright (C) 2021, by Matvey Cherevko (blackmatov@gmail.com)
******************************************************************************/
#include "../meta_tests.hpp"
namespace
{
struct ivec2 {
int x{};
int y{};
};
void arg_copy(ivec2) {}
void arg_ref_noexcept(ivec2&) noexcept {}
void arg_cref_noexcept(const ivec2&) noexcept {}
}
TEST_CASE("meta/meta_types/function_type") {
namespace meta = meta_hpp;
SUBCASE("") {
const meta::function_type type;
CHECK_FALSE(type);
CHECK_FALSE(type.is_valid());
}
SUBCASE("arg_copy") {
const meta::function_type type = meta::resolve_type(&arg_copy);
REQUIRE(type);
CHECK(type.get_id() == meta::resolve_type(&arg_copy).get_id());
CHECK(type.get_flags() == meta::function_flags{});
CHECK(type.get_arity() == 1);
CHECK(type.get_return_type() == meta::resolve_type<void>());
CHECK(type.get_argument_types() == std::vector<meta::any_type>{meta::resolve_type<ivec2>()});
CHECK(type.get_argument_type(0) == meta::resolve_type<ivec2>());
CHECK_FALSE(type.get_argument_type(1));
}
SUBCASE("arg_ref_noexcept") {
const meta::function_type type = meta::resolve_type(&arg_ref_noexcept);
REQUIRE(type);
CHECK(type.get_id() == meta::resolve_type(&arg_ref_noexcept).get_id());
CHECK(type.get_flags() == meta::function_flags::is_noexcept);
CHECK(type.get_argument_types() == std::vector<meta::any_type>{meta::resolve_type<ivec2&>()});
CHECK(type.get_argument_type(0) == meta::resolve_type<ivec2&>());
CHECK_FALSE(type.get_argument_type(1));
}
SUBCASE("arg_cref_noexcept") {
const meta::function_type type = meta::resolve_type(&arg_cref_noexcept);
REQUIRE(type);
CHECK(type.get_id() == meta::resolve_type(&arg_cref_noexcept).get_id());
CHECK(type.get_flags() == meta::function_flags::is_noexcept);
CHECK(type.get_argument_types() == std::vector<meta::any_type>{meta::resolve_type<const ivec2&>()});
CHECK(type.get_argument_type(0) == meta::resolve_type<const ivec2&>());
CHECK_FALSE(type.get_argument_type(1));
}
}

View File

@@ -0,0 +1,47 @@
/*******************************************************************************
* This file is part of the "https://github.com/blackmatov/meta.hpp"
* For conditions of distribution and use, see copyright notice in LICENSE.md
* Copyright (C) 2021, by Matvey Cherevko (blackmatov@gmail.com)
******************************************************************************/
#include "../meta_tests.hpp"
namespace
{
struct clazz_1 {
int int_member = 1;
const int const_int_member = 2;
};
}
TEST_CASE("meta/meta_types/member_type") {
namespace meta = meta_hpp;
SUBCASE("") {
const meta::member_type type;
CHECK_FALSE(type);
CHECK_FALSE(type.is_valid());
}
SUBCASE("int") {
const meta::member_type type = meta::resolve_type(&clazz_1::int_member);
REQUIRE(type);
CHECK(type.get_id() == meta::resolve_type(&clazz_1::int_member).get_id());
CHECK(type.get_flags() == meta::member_flags{});
CHECK(type.get_owner_type() == meta::resolve_type<clazz_1>());
CHECK(type.get_value_type() == meta::resolve_type<int>());
}
SUBCASE("const int") {
const meta::member_type type = meta::resolve_type(&clazz_1::const_int_member);
REQUIRE(type);
CHECK(type.get_id() == meta::resolve_type(&clazz_1::const_int_member).get_id());
CHECK(type.get_flags() == meta::member_flags{});
CHECK(type.get_owner_type() == meta::resolve_type<clazz_1>());
CHECK(type.get_value_type() == meta::resolve_type<int>());
}
}

View File

@@ -0,0 +1,68 @@
/*******************************************************************************
* This file is part of the "https://github.com/blackmatov/meta.hpp"
* For conditions of distribution and use, see copyright notice in LICENSE.md
* Copyright (C) 2021, by Matvey Cherevko (blackmatov@gmail.com)
******************************************************************************/
#include "../meta_tests.hpp"
namespace
{
struct ivec2 {
int x{};
int y{};
int& at(std::size_t i) {
switch ( i ) {
case 0: return x;
case 1: return y;
default: throw std::out_of_range("ivec2::at");
}
}
int length2() const noexcept {
return x * x + y * y;
}
};
}
TEST_CASE("meta/meta_types/method_type") {
namespace meta = meta_hpp;
SUBCASE("") {
const meta::method_type type;
CHECK_FALSE(type);
CHECK_FALSE(type.is_valid());
}
SUBCASE("ivec2::at") {
const meta::method_type type = meta::resolve_type(&ivec2::at);
REQUIRE(type);
CHECK(type.get_id() == meta::resolve_type(&ivec2::at).get_id());
CHECK(type.get_flags() == meta::method_flags{});
CHECK(type.get_arity() == 1);
CHECK(type.get_owner_type() == meta::resolve_type<ivec2>());
CHECK(type.get_return_type() == meta::resolve_type<int&>());
CHECK(type.get_argument_types() == std::vector<meta::any_type>{meta::resolve_type<std::size_t>()});
CHECK(type.get_argument_type(0) == meta::resolve_type<std::size_t>());
CHECK_FALSE(type.get_argument_type(1));
}
SUBCASE("ivec2::length2") {
const meta::method_type type = meta::resolve_type(&ivec2::length2);
REQUIRE(type);
CHECK(type.get_id() == meta::resolve_type(&ivec2::length2).get_id());
CHECK(type.get_flags() == (meta::method_flags::is_const | meta::method_flags::is_noexcept));
CHECK(type.get_arity() == 0);
CHECK(type.get_owner_type() == meta::resolve_type<ivec2>());
CHECK(type.get_return_type() == meta::resolve_type<int>());
CHECK(type.get_argument_types() == std::vector<meta::any_type>{});
CHECK_FALSE(type.get_argument_type(0));
}
}

View File

@@ -0,0 +1,51 @@
/*******************************************************************************
* This file is part of the "https://github.com/blackmatov/meta.hpp"
* For conditions of distribution and use, see copyright notice in LICENSE.md
* Copyright (C) 2021, by Matvey Cherevko (blackmatov@gmail.com)
******************************************************************************/
#include "../meta_tests.hpp"
namespace
{
}
TEST_CASE("meta/meta_types/number_type") {
namespace meta = meta_hpp;
SUBCASE("") {
const meta::number_type type;
CHECK_FALSE(type);
CHECK_FALSE(type.is_valid());
}
SUBCASE("int") {
const meta::number_type type = meta::resolve_type<int>();
REQUIRE(type);
CHECK(type.get_size() == sizeof(int));
CHECK(type.get_flags() == (
meta::number_flags::is_signed |
meta::number_flags::is_integral));
}
SUBCASE("const float") {
const meta::number_type type = meta::resolve_type<const float>();
REQUIRE(type);
CHECK(type.get_size() == sizeof(float));
CHECK(type.get_flags() == (
meta::number_flags::is_signed |
meta::number_flags::is_floating_point));
}
SUBCASE("const unsigned") {
const meta::number_type type = meta::resolve_type<const unsigned>();
REQUIRE(type);
CHECK(type.get_size() == sizeof(unsigned));
CHECK(type.get_flags() == (
meta::number_flags::is_unsigned |
meta::number_flags::is_integral));
}
}

View File

@@ -0,0 +1,53 @@
/*******************************************************************************
* This file is part of the "https://github.com/blackmatov/meta.hpp"
* For conditions of distribution and use, see copyright notice in LICENSE.md
* Copyright (C) 2021, by Matvey Cherevko (blackmatov@gmail.com)
******************************************************************************/
#include "../meta_tests.hpp"
namespace
{
}
TEST_CASE("meta/meta_types/pointer_type") {
namespace meta = meta_hpp;
SUBCASE("") {
const meta::pointer_type type;
CHECK_FALSE(type);
CHECK_FALSE(type.is_valid());
}
SUBCASE("int*") {
const meta::pointer_type type = meta::resolve_type<int*>();
REQUIRE(type);
CHECK(type.get_id() == meta::resolve_type<int*>().get_id());
CHECK(type.get_data_type() == meta::resolve_type<int>());
}
SUBCASE("const int* const") {
const meta::pointer_type type = meta::resolve_type<const int* const>();
REQUIRE(type);
CHECK(type.get_id() == meta::resolve_type<const int*>().get_id());
CHECK(type.get_data_type() == meta::resolve_type<const int>());
}
SUBCASE("int**") {
const meta::pointer_type type = meta::resolve_type<int**>();
REQUIRE(type);
CHECK(type.get_id() == meta::resolve_type<int**>().get_id());
CHECK(type.get_data_type() == meta::resolve_type<int*>());
}
SUBCASE("const int** const") {
const meta::pointer_type type = meta::resolve_type<const int** const>();
REQUIRE(type);
CHECK(type.get_id() == meta::resolve_type<const int**>().get_id());
CHECK(type.get_data_type() == meta::resolve_type<const int*>());
}
}

View File

@@ -0,0 +1,61 @@
/*******************************************************************************
* This file is part of the "https://github.com/blackmatov/meta.hpp"
* For conditions of distribution and use, see copyright notice in LICENSE.md
* Copyright (C) 2021, by Matvey Cherevko (blackmatov@gmail.com)
******************************************************************************/
#include "../meta_tests.hpp"
namespace
{
}
TEST_CASE("meta/meta_types/reference_type") {
namespace meta = meta_hpp;
SUBCASE("") {
const meta::reference_type type;
CHECK_FALSE(type);
CHECK_FALSE(type.is_valid());
}
SUBCASE("int&") {
const meta::reference_type type = meta::resolve_type<int&>();
REQUIRE(type);
CHECK(type.get_flags() == (meta::reference_flags::is_lvalue));
CHECK(type.get_id() == meta::resolve_type<int&>().get_id());
CHECK(type.get_data_type() == meta::resolve_type<int>());
}
SUBCASE("const int&") {
const meta::reference_type type = meta::resolve_type<const int&>();
REQUIRE(type);
CHECK(type.get_flags() == (meta::reference_flags::is_readonly | meta::reference_flags::is_lvalue));
CHECK(type.get_id() == meta::resolve_type<const int&>().get_id());
CHECK(type.get_data_type() == meta::resolve_type<const int>());
}
SUBCASE("int&&") {
const meta::reference_type type = meta::resolve_type<int&&>();
REQUIRE(type);
CHECK(type.get_flags() == (meta::reference_flags::is_rvalue));
CHECK(type.get_id() == meta::resolve_type<int&&>().get_id());
CHECK(type.get_data_type() == meta::resolve_type<int>());
}
SUBCASE("const int&&") {
const meta::reference_type type = meta::resolve_type<const int&&>();
REQUIRE(type);
CHECK(type.get_flags() == (meta::reference_flags::is_readonly | meta::reference_flags::is_rvalue));
CHECK(type.get_id() == meta::resolve_type<const int&&>().get_id());
CHECK(type.get_data_type() == meta::resolve_type<const int>());
}
}

View File

@@ -0,0 +1,29 @@
/*******************************************************************************
* This file is part of the "https://github.com/blackmatov/meta.hpp"
* For conditions of distribution and use, see copyright notice in LICENSE.md
* Copyright (C) 2021, by Matvey Cherevko (blackmatov@gmail.com)
******************************************************************************/
#include "../meta_tests.hpp"
namespace
{
}
TEST_CASE("meta/meta_types/void_type") {
namespace meta = meta_hpp;
SUBCASE("") {
const meta::void_type type;
CHECK_FALSE(type);
CHECK_FALSE(type.is_valid());
}
SUBCASE("void") {
const meta::void_type type = meta::resolve_type<void>();
REQUIRE(type);
CHECK(type.get_id() == meta::resolve_type<void>().get_id());
CHECK(type.get_flags() == meta::void_flags{});
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,72 @@
/*******************************************************************************
* This file is part of the "https://github.com/blackmatov/meta.hpp"
* For conditions of distribution and use, see copyright notice in LICENSE.md
* Copyright (C) 2021, by Matvey Cherevko (blackmatov@gmail.com)
******************************************************************************/
#include "../meta_tests.hpp"
namespace
{
struct ivec2 {
int x{};
int y{};
[[maybe_unused]] ivec2() = default;
[[maybe_unused]] explicit ivec2(int v): x{v}, y{v} {}
[[maybe_unused]] ivec2(int x, int y): x{x}, y{y} {}
[[maybe_unused]] ivec2(ivec2&& other) noexcept {
x = other.x;
y = other.y;
other.x = 0;
other.y = 0;
}
[[maybe_unused]] ivec2(const ivec2& other) noexcept {
x = other.x;
y = other.y;
}
ivec2& operator=(ivec2&&) = delete;
ivec2& operator=(const ivec2&) = delete;
};
}
TEST_CASE("features/meta_utilities/inst") {
namespace meta = meta_hpp;
SUBCASE("ref") {
ivec2 v{1,2};
ivec2& vr = v;
meta::detail::inst a{vr};
CHECK(a.get_raw_type() == meta::resolve_type<ivec2>());
CHECK(a.get_ref_type() == meta::detail::inst::ref_types::ref);
}
SUBCASE("cref") {
const ivec2 v{1,2};
const ivec2& vr = v;
meta::detail::inst a{vr};
CHECK(a.get_raw_type() == meta::resolve_type<ivec2>());
CHECK(a.get_ref_type() == meta::detail::inst::ref_types::cref);
}
SUBCASE("rref") {
ivec2 v{1,2};
meta::detail::inst a{std::move(v)};
CHECK(a.get_raw_type() == meta::resolve_type<ivec2>());
CHECK(a.get_ref_type() == meta::detail::inst::ref_types::rref);
}
SUBCASE("crref") {
const ivec2 v{1,2};
meta::detail::inst a{std::move(v)};
CHECK(a.get_raw_type() == meta::resolve_type<ivec2>());
CHECK(a.get_ref_type() == meta::detail::inst::ref_types::crref);
}
}

View File

@@ -0,0 +1,295 @@
/*******************************************************************************
* This file is part of the "https://github.com/blackmatov/meta.hpp"
* For conditions of distribution and use, see copyright notice in LICENSE.md
* Copyright (C) 2021, by Matvey Cherevko (blackmatov@gmail.com)
******************************************************************************/
#include "../meta_tests.hpp"
namespace
{
struct ivec2 {
int x{};
int y{};
[[maybe_unused]] ivec2() = default;
[[maybe_unused]] explicit ivec2(int v): x{v}, y{v} {}
[[maybe_unused]] ivec2(int x, int y): x{x}, y{y} {}
ivec2(ivec2&& other) noexcept
: x{other.x}
, y{other.y} {
other.x = 0;
other.y = 0;
++move_ctor_counter;
}
ivec2(const ivec2& other) noexcept
: x{other.x}
, y{other.y} {
++copy_ctor_counter;
}
ivec2& operator=(ivec2&& other) = delete;
ivec2& operator=(const ivec2& other) = delete;
public:
static int move_ctor_counter;
static int copy_ctor_counter;
};
int ivec2::move_ctor_counter{0};
int ivec2::copy_ctor_counter{0};
bool operator==(const ivec2& l, const ivec2& r) noexcept {
return l.x == r.x && l.y == r.y;
}
}
TEST_CASE("meta/meta_utilities/value") {
namespace meta = meta_hpp;
ivec2::move_ctor_counter = 0;
ivec2::copy_ctor_counter = 0;
SUBCASE("cast types") {
static_assert(std::is_same_v<
decltype(std::declval<meta::value&>().cast<ivec2>()),
ivec2&>);
static_assert(std::is_same_v<
decltype(std::declval<meta::value&&>().cast<ivec2>()),
ivec2&&>);
static_assert(std::is_same_v<
decltype(std::declval<const meta::value&>().cast<ivec2>()),
const ivec2&>);
static_assert(std::is_same_v<
decltype(std::declval<const meta::value&&>().cast<ivec2>()),
const ivec2&&>);
}
SUBCASE("try_cast types") {
static_assert(std::is_same_v<
decltype(std::declval<meta::value>().try_cast<ivec2>()),
ivec2*>);
static_assert(std::is_same_v<
decltype(std::declval<const meta::value>().try_cast<ivec2>()),
const ivec2*>);
}
SUBCASE("ivec2&") {
ivec2 v{1,2};
ivec2& vr = v;
meta::value val{vr};
CHECK(ivec2::move_ctor_counter == 0);
CHECK(ivec2::copy_ctor_counter == 1);
CHECK(val.get_type() == meta::resolve_type<ivec2>());
CHECK(!std::memcmp(val.data(), &vr, sizeof(ivec2)));
CHECK(!std::memcmp(val.cdata(), &vr, sizeof(ivec2)));
CHECK(!std::memcmp(std::as_const(val).data(), &vr, sizeof(ivec2)));
CHECK(!std::memcmp(std::as_const(val).cdata(), &vr, sizeof(ivec2)));
CHECK(val == ivec2{1,2});
CHECK(val == meta::value{ivec2{1,2}});
CHECK(val.cast<ivec2>() == ivec2{1,2});
CHECK(std::as_const(val).cast<ivec2>() == ivec2{1,2});
CHECK(*val.try_cast<ivec2>() == ivec2{1,2});
CHECK(*std::as_const(val).try_cast<ivec2>() == ivec2{1,2});
}
SUBCASE("const ivec2&") {
const ivec2 v{1,2};
const ivec2& vr = v;
meta::value val{vr};
CHECK(ivec2::move_ctor_counter == 0);
CHECK(ivec2::copy_ctor_counter == 1);
CHECK(val.get_type() == meta::resolve_type<ivec2>());
CHECK(!std::memcmp(val.data(), &vr, sizeof(ivec2)));
CHECK(!std::memcmp(val.cdata(), &vr, sizeof(ivec2)));
CHECK(!std::memcmp(std::as_const(val).data(), &vr, sizeof(ivec2)));
CHECK(!std::memcmp(std::as_const(val).cdata(), &vr, sizeof(ivec2)));
CHECK(val == ivec2{1,2});
CHECK(val == meta::value{ivec2{1,2}});
CHECK(val.cast<ivec2>() == ivec2{1,2});
CHECK(std::as_const(val).cast<ivec2>() == ivec2{1,2});
CHECK(*val.try_cast<ivec2>() == ivec2{1,2});
CHECK(*std::as_const(val).try_cast<ivec2>() == ivec2{1,2});
}
SUBCASE("ivec2&&") {
ivec2 v{1,2};
meta::value val{std::move(v)};
CHECK(ivec2::move_ctor_counter == 1);
CHECK(ivec2::copy_ctor_counter == 0);
CHECK(val.get_type() == meta::resolve_type<ivec2>());
CHECK(val == ivec2{1,2});
CHECK(val == meta::value{ivec2{1,2}});
CHECK(val.cast<ivec2>() == ivec2{1,2});
CHECK(std::as_const(val).cast<ivec2>() == ivec2{1,2});
CHECK(*val.try_cast<ivec2>() == ivec2{1,2});
CHECK(*std::as_const(val).try_cast<ivec2>() == ivec2{1,2});
}
SUBCASE("const ivec2&&") {
const ivec2 v{1,2};
meta::value val{std::move(v)};
CHECK(ivec2::move_ctor_counter == 0);
CHECK(ivec2::copy_ctor_counter == 1);
CHECK(val.get_type() == meta::resolve_type<ivec2>());
CHECK(val == ivec2{1,2});
CHECK(val == meta::value{ivec2{1,2}});
CHECK(val.cast<ivec2>() == ivec2{1,2});
CHECK(std::as_const(val).cast<ivec2>() == ivec2{1,2});
CHECK(*val.try_cast<ivec2>() == ivec2{1,2});
CHECK(*std::as_const(val).try_cast<ivec2>() == ivec2{1,2});
}
SUBCASE("value(value&&)") {
ivec2 v{1,2};
meta::value val_src{std::move(v)};
CHECK(ivec2::move_ctor_counter == 1);
CHECK(ivec2::copy_ctor_counter == 0);
meta::value val_dst{std::move(val_src)};
CHECK(val_dst == ivec2{1,2});
CHECK(ivec2::move_ctor_counter == 2);
CHECK(ivec2::copy_ctor_counter == 0);
CHECK(val_src == ivec2{0,0});
CHECK(val_src.data() != val_dst.data());
}
SUBCASE("value(const meta::value&)") {
const ivec2 v{1,2};
meta::value val_src{v};
CHECK(ivec2::move_ctor_counter == 0);
CHECK(ivec2::copy_ctor_counter == 1);
meta::value val_dst{val_src};
CHECK(val_dst == ivec2{1,2});
CHECK(ivec2::move_ctor_counter == 0);
CHECK(ivec2::copy_ctor_counter == 2);
CHECK(val_src == ivec2{1,2});
CHECK(val_src.data() != val_dst.data());
}
SUBCASE("value& operator=(value&&)") {
meta::value val_src1{std::string("world")};
meta::value val_src2{ivec2{1,2}};
CHECK(ivec2::move_ctor_counter == 1);
CHECK(ivec2::copy_ctor_counter == 0);
meta::value val_dst{std::string("hello")};
val_dst = std::move(val_src1);
CHECK(val_dst == std::string("world"));
CHECK(ivec2::move_ctor_counter == 1);
CHECK(ivec2::copy_ctor_counter == 0);
val_dst = std::move(val_src2);
CHECK(val_dst == ivec2{1,2});
CHECK(ivec2::move_ctor_counter == 2);
CHECK(ivec2::copy_ctor_counter == 0);
CHECK(val_src2 == ivec2{0,0});
CHECK(val_src2.data() != val_dst.data());
}
SUBCASE("value& operator=(const meta::value&)") {
meta::value val_src1{std::string("world")};
meta::value val_src2{ivec2{1,2}};
CHECK(ivec2::move_ctor_counter == 1);
CHECK(ivec2::copy_ctor_counter == 0);
meta::value val_dst{std::string("hello")};
val_dst = val_src1;
CHECK(val_dst == std::string("world"));
CHECK(ivec2::move_ctor_counter == 1);
CHECK(ivec2::copy_ctor_counter == 0);
val_dst = val_src2;
CHECK(val_dst == ivec2{1,2});
CHECK(ivec2::move_ctor_counter == 1);
CHECK(ivec2::copy_ctor_counter == 1);
CHECK(val_src2 == ivec2{1,2});
CHECK(val_src2.data() != val_dst.data());
}
SUBCASE("swap") {
meta::value val1{std::string("world")};
meta::value val2{ivec2{1,2}};
CHECK(ivec2::move_ctor_counter == 1);
CHECK(ivec2::copy_ctor_counter == 0);
val1.swap(val2);
CHECK(val1 == ivec2{1,2});
CHECK(val2 == std::string("world"));
CHECK((ivec2::move_ctor_counter == 2 || ivec2::move_ctor_counter == 3));
CHECK(ivec2::copy_ctor_counter == 0);
swap(val1, val2);
CHECK(val1 == std::string("world"));
CHECK(val2 == ivec2{1,2});
}
SUBCASE("ostream") {
std::stringstream str_stream;
CHECK_NOTHROW(str_stream << meta::value{21} << " " << meta::value{42});
CHECK_THROWS((str_stream << meta::value{ivec2{1,2}}));
REQUIRE(str_stream.str() == "21 42");
}
SUBCASE("istream") {
std::stringstream str_stream{"21 42"};
meta::value v{ivec2{1,2}};
CHECK_THROWS(str_stream >> v);
v = meta::value{0};
CHECK_NOTHROW(str_stream >> v);
CHECK(v == 21);
CHECK_NOTHROW(str_stream >> v);
CHECK(v == 42);
}
SUBCASE("operator==") {
CHECK(meta::value{ivec2{1,2}} == ivec2{1,2});
CHECK_FALSE(meta::value{ivec2{1,2}} == ivec2{1,3});
CHECK(ivec2{1,2} == meta::value{ivec2{1,2}});
CHECK_FALSE(ivec2{1,3} == meta::value{ivec2{1,2}});
CHECK(meta::value{ivec2{1,2}} == meta::value{ivec2{1,2}});
CHECK_FALSE(meta::value{ivec2{1,2}} == meta::value{ivec2{1,3}});
{
class empty_class1 {};
class empty_class2 {};
CHECK_FALSE(operator==(meta::value{empty_class1{}}, meta::value{empty_class2{}}));
CHECK_THROWS(operator==(meta::value{empty_class1{}}, meta::value{empty_class1{}}));
}
}
}