mirror of
https://github.com/BlackMATov/meta.hpp.git
synced 2025-12-15 03:45:30 +07:00
first dirty proof of concept
This commit is contained in:
@@ -6,6 +6,14 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
namespace meta_hpp
|
||||
{
|
||||
}
|
||||
#include "meta_fwd.hpp"
|
||||
|
||||
#include "meta_value.hpp"
|
||||
#include "meta_registry.hpp"
|
||||
|
||||
#include "meta_class.hpp"
|
||||
#include "meta_field.hpp"
|
||||
#include "meta_function.hpp"
|
||||
#include "meta_method.hpp"
|
||||
#include "meta_namespace.hpp"
|
||||
#include "meta_variable.hpp"
|
||||
|
||||
141
headers/meta.hpp/meta_class.hpp
Normal file
141
headers/meta.hpp/meta_class.hpp
Normal file
@@ -0,0 +1,141 @@
|
||||
/*******************************************************************************
|
||||
* 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_fwd.hpp"
|
||||
|
||||
#include "meta_field.hpp"
|
||||
#include "meta_function.hpp"
|
||||
#include "meta_method.hpp"
|
||||
#include "meta_variable.hpp"
|
||||
|
||||
namespace meta_hpp
|
||||
{
|
||||
class class_info {
|
||||
public:
|
||||
class_info() = delete;
|
||||
|
||||
class_info(class_info&&) = default;
|
||||
class_info(const class_info&) = default;
|
||||
|
||||
class_info& operator=(class_info&&) = default;
|
||||
class_info& operator=(const class_info&) = default;
|
||||
|
||||
class_info(std::string id)
|
||||
: id_(std::move(id)) {}
|
||||
|
||||
const std::string& id() const noexcept {
|
||||
return id_;
|
||||
}
|
||||
|
||||
std::optional<class_info> get_class(std::string_view id) const {
|
||||
return detail::find_opt(classes_, id);
|
||||
}
|
||||
|
||||
std::optional<field_info> get_field(std::string_view id) const {
|
||||
return detail::find_opt(fields_, id);
|
||||
}
|
||||
|
||||
std::optional<function_info> get_function(std::string_view id) const {
|
||||
return detail::find_opt(functions_, id);
|
||||
}
|
||||
|
||||
std::optional<method_info> get_method(std::string_view id) const {
|
||||
return detail::find_opt(methods_, id);
|
||||
}
|
||||
|
||||
std::optional<variable_info> get_variable(std::string_view id) const {
|
||||
return detail::find_opt(variables_, id);
|
||||
}
|
||||
private:
|
||||
friend class namespace_info;
|
||||
template < typename Class > friend class class_;
|
||||
friend class namespace_;
|
||||
private:
|
||||
void merge_with_(const class_info& other) {
|
||||
detail::merge_with(classes_, other.classes_, &class_info::merge_with_);
|
||||
detail::merge_with(fields_, other.fields_, &field_info::merge_with_);
|
||||
detail::merge_with(functions_, other.functions_, &function_info::merge_with_);
|
||||
detail::merge_with(methods_, other.methods_, &method_info::merge_with_);
|
||||
detail::merge_with(variables_, other.variables_, &variable_info::merge_with_);
|
||||
}
|
||||
private:
|
||||
std::string id_;
|
||||
std::map<std::string, class_info, std::less<>> classes_;
|
||||
std::map<std::string, field_info, std::less<>> fields_;
|
||||
std::map<std::string, function_info, std::less<>> functions_;
|
||||
std::map<std::string, method_info, std::less<>> methods_;
|
||||
std::map<std::string, variable_info, std::less<>> variables_;
|
||||
};
|
||||
}
|
||||
|
||||
namespace meta_hpp
|
||||
{
|
||||
template < typename Class >
|
||||
class class_ {
|
||||
public:
|
||||
explicit class_(std::string id)
|
||||
: info_(std::move(id)) {}
|
||||
|
||||
const class_info& info() const noexcept {
|
||||
return info_;
|
||||
}
|
||||
|
||||
template < typename... Internals >
|
||||
class_& operator()(Internals&&...internals) {
|
||||
(add_(std::forward<Internals>(internals)), ...);
|
||||
return *this;
|
||||
}
|
||||
private:
|
||||
template < typename InternalClass >
|
||||
void add_(const class_<InternalClass>& internal) {
|
||||
detail::merge_with(
|
||||
info_.classes_,
|
||||
internal.info().id(),
|
||||
internal.info(),
|
||||
&class_info::merge_with_);
|
||||
}
|
||||
|
||||
template < auto InternalField >
|
||||
void add_(const field_<InternalField>& internal) {
|
||||
detail::merge_with(
|
||||
info_.fields_,
|
||||
internal.info().id(),
|
||||
internal.info(),
|
||||
&field_info::merge_with_);
|
||||
}
|
||||
|
||||
template < auto InternalFunction >
|
||||
void add_(const function_<InternalFunction>& internal) {
|
||||
detail::merge_with(
|
||||
info_.functions_,
|
||||
internal.info().id(),
|
||||
internal.info(),
|
||||
&function_info::merge_with_);
|
||||
}
|
||||
|
||||
template < auto InternalMethod >
|
||||
void add_(const method_<InternalMethod>& internal) {
|
||||
detail::merge_with(
|
||||
info_.methods_,
|
||||
internal.info().id(),
|
||||
internal.info(),
|
||||
&method_info::merge_with_);
|
||||
}
|
||||
|
||||
template < auto InternalVariable >
|
||||
void add_(const variable_<InternalVariable>& internal) {
|
||||
detail::merge_with(
|
||||
info_.variables_,
|
||||
internal.info().id(),
|
||||
internal.info(),
|
||||
&variable_info::merge_with_);
|
||||
}
|
||||
private:
|
||||
class_info info_;
|
||||
};
|
||||
}
|
||||
120
headers/meta.hpp/meta_field.hpp
Normal file
120
headers/meta.hpp/meta_field.hpp
Normal file
@@ -0,0 +1,120 @@
|
||||
/*******************************************************************************
|
||||
* 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_fwd.hpp"
|
||||
|
||||
#include "meta_value.hpp"
|
||||
|
||||
namespace meta_hpp::field_detail
|
||||
{
|
||||
template < typename Field >
|
||||
struct field_traits;
|
||||
|
||||
template < typename T, typename Base >
|
||||
struct field_traits<T Base::*> {
|
||||
static constexpr bool is_const = false;
|
||||
using value_type = T;
|
||||
using instance_type = Base;
|
||||
};
|
||||
|
||||
template < typename T, typename Base >
|
||||
struct field_traits<const T Base::*> {
|
||||
static constexpr bool is_const = true;
|
||||
using value_type = T;
|
||||
using instance_type = Base;
|
||||
};
|
||||
|
||||
template < auto Field >
|
||||
value getter(const void* instance) {
|
||||
using ft = field_traits<decltype(Field)>;
|
||||
using value_type = typename ft::value_type;
|
||||
using instance_type = typename ft::instance_type;
|
||||
|
||||
auto instance_ptr = static_cast<const instance_type*>(instance);
|
||||
value_type typed_value = std::invoke(Field, *instance_ptr);
|
||||
|
||||
return value{std::move(typed_value)};
|
||||
}
|
||||
|
||||
template < auto Field >
|
||||
void setter(void* instance, value value) {
|
||||
using ft = field_traits<decltype(Field)>;
|
||||
using value_type = typename ft::value_type;
|
||||
using instance_type = typename ft::instance_type;
|
||||
|
||||
if constexpr ( !ft::is_const ) {
|
||||
auto instance_ptr = static_cast<instance_type*>(instance);
|
||||
std::invoke(Field, *instance_ptr) = value.cast<value_type>();
|
||||
} else {
|
||||
throw std::logic_error("an attempt to change a constant field");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
namespace meta_hpp
|
||||
{
|
||||
class field_info {
|
||||
public:
|
||||
field_info() = delete;
|
||||
|
||||
field_info(field_info&&) = default;
|
||||
field_info(const field_info&) = default;
|
||||
|
||||
field_info& operator=(field_info&&) = default;
|
||||
field_info& operator=(const field_info&) = default;
|
||||
|
||||
field_info(std::string id)
|
||||
: id_(std::move(id)) {}
|
||||
|
||||
const std::string& id() const noexcept {
|
||||
return id_;
|
||||
}
|
||||
public:
|
||||
value get(const void* instance) const {
|
||||
return getter_(instance);
|
||||
}
|
||||
|
||||
template < typename Value >
|
||||
void set(void* instance, Value&& value) const {
|
||||
return setter_(instance, std::forward<Value>(value));
|
||||
}
|
||||
private:
|
||||
friend class class_info;
|
||||
template < typename Class > friend class class_;
|
||||
template < auto Field > friend class field_;
|
||||
private:
|
||||
void merge_with_(const field_info& other) {
|
||||
(void)other;
|
||||
}
|
||||
private:
|
||||
std::string id_;
|
||||
value(*getter_)(const void*);
|
||||
void(*setter_)(void*, value);
|
||||
};
|
||||
}
|
||||
|
||||
namespace meta_hpp
|
||||
{
|
||||
template < auto Field >
|
||||
class field_ {
|
||||
public:
|
||||
static_assert(std::is_member_object_pointer_v<decltype(Field)>);
|
||||
|
||||
explicit field_(std::string id)
|
||||
: info_(std::move(id)) {
|
||||
info_.getter_ = &field_detail::getter<Field>;
|
||||
info_.setter_ = &field_detail::setter<Field>;
|
||||
}
|
||||
|
||||
const field_info& info() const noexcept {
|
||||
return info_;
|
||||
}
|
||||
private:
|
||||
field_info info_;
|
||||
};
|
||||
}
|
||||
125
headers/meta.hpp/meta_function.hpp
Normal file
125
headers/meta.hpp/meta_function.hpp
Normal file
@@ -0,0 +1,125 @@
|
||||
/*******************************************************************************
|
||||
* 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_fwd.hpp"
|
||||
|
||||
#include "meta_value.hpp"
|
||||
|
||||
namespace meta_hpp::function_detail
|
||||
{
|
||||
template < typename Function >
|
||||
struct function_traits;
|
||||
|
||||
template < typename R, typename... Args >
|
||||
struct function_traits<R(*)(Args...)> {
|
||||
static constexpr std::size_t arity = sizeof...(Args);
|
||||
using return_type = R;
|
||||
using argument_types = std::tuple<Args...>;
|
||||
};
|
||||
|
||||
template < typename R, typename... Args >
|
||||
struct function_traits<R(*)(Args...) noexcept>
|
||||
: function_traits<R(*)(Args...)> {};
|
||||
|
||||
template < auto Function, std::size_t... Is >
|
||||
value invoke(value* args, std::index_sequence<Is...>) {
|
||||
using ft = function_traits<decltype(Function)>;
|
||||
using return_type = typename ft::return_type;
|
||||
using argument_types = typename ft::argument_types;
|
||||
|
||||
auto typed_arguments = std::make_tuple(
|
||||
(args + Is)->try_cast<std::tuple_element_t<Is, argument_types>>()...);
|
||||
|
||||
if ( !(std::get<Is>(typed_arguments) && ...) ) {
|
||||
throw std::logic_error("an attempt to call a function with incorrect argument types");
|
||||
}
|
||||
|
||||
if constexpr ( std::is_void_v<return_type> ) {
|
||||
std::invoke(Function,
|
||||
*std::get<Is>(typed_arguments)...);
|
||||
return value{};
|
||||
} else {
|
||||
return_type return_value = std::invoke(Function,
|
||||
*std::get<Is>(typed_arguments)...);
|
||||
return value{std::move(return_value)};
|
||||
}
|
||||
}
|
||||
|
||||
template < auto Function >
|
||||
value invoke(value* args, std::size_t arg_count) {
|
||||
using ft = function_traits<decltype(Function)>;
|
||||
|
||||
if ( arg_count != ft::arity ) {
|
||||
throw std::logic_error("an attempt to call a function with an incorrect arity");
|
||||
}
|
||||
|
||||
return invoke<Function>(args, std::make_index_sequence<ft::arity>());
|
||||
}
|
||||
}
|
||||
|
||||
namespace meta_hpp
|
||||
{
|
||||
class function_info {
|
||||
public:
|
||||
function_info() = delete;
|
||||
|
||||
function_info(function_info&&) = default;
|
||||
function_info(const function_info&) = default;
|
||||
|
||||
function_info& operator=(function_info&&) = default;
|
||||
function_info& operator=(const function_info&) = default;
|
||||
|
||||
function_info(std::string id)
|
||||
: id_(std::move(id)) {}
|
||||
|
||||
const std::string& id() const noexcept {
|
||||
return id_;
|
||||
}
|
||||
public:
|
||||
template < typename... Args >
|
||||
value invoke(Args&&... args) const {
|
||||
std::array<value, sizeof...(Args)> vargs{{std::forward<Args>(args)...}};
|
||||
return invoke_(vargs.data(), vargs.size());
|
||||
}
|
||||
private:
|
||||
friend class class_info;
|
||||
friend class namespace_info;
|
||||
|
||||
template < typename Class > friend class class_;
|
||||
friend class namespace_;
|
||||
|
||||
template < auto Function > friend class function_;
|
||||
private:
|
||||
void merge_with_(const function_info& other) {
|
||||
(void)other;
|
||||
}
|
||||
private:
|
||||
std::string id_;
|
||||
value(*invoke_)(value*, std::size_t);
|
||||
};
|
||||
}
|
||||
|
||||
namespace meta_hpp
|
||||
{
|
||||
template < auto Function >
|
||||
class function_ {
|
||||
public:
|
||||
static_assert(std::is_function_v<std::remove_pointer_t<decltype(Function)>>);
|
||||
|
||||
explicit function_(std::string id)
|
||||
: info_(std::move(id)) {
|
||||
info_.invoke_ = &function_detail::invoke<Function>;
|
||||
}
|
||||
|
||||
const function_info& info() const noexcept {
|
||||
return info_;
|
||||
}
|
||||
private:
|
||||
function_info info_;
|
||||
};
|
||||
}
|
||||
99
headers/meta.hpp/meta_fwd.hpp
Normal file
99
headers/meta.hpp/meta_fwd.hpp
Normal 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)
|
||||
******************************************************************************/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <any>
|
||||
#include <array>
|
||||
#include <functional>
|
||||
#include <map>
|
||||
#include <optional>
|
||||
#include <stdexcept>
|
||||
#include <string_view>
|
||||
#include <string>
|
||||
#include <tuple>
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
|
||||
namespace meta_hpp
|
||||
{
|
||||
class value;
|
||||
class registry;
|
||||
|
||||
class class_info;
|
||||
class field_info;
|
||||
class function_info;
|
||||
class method_info;
|
||||
class namespace_info;
|
||||
class variable_info;
|
||||
|
||||
template < typename Class >
|
||||
class class_;
|
||||
|
||||
template < auto Field >
|
||||
class field_;
|
||||
|
||||
template < auto Function >
|
||||
class function_;
|
||||
|
||||
template < auto Method >
|
||||
class method_;
|
||||
|
||||
class namespace_;
|
||||
|
||||
template < auto Variable >
|
||||
class variable_;
|
||||
}
|
||||
|
||||
namespace meta_hpp
|
||||
{
|
||||
template < typename Signature >
|
||||
constexpr auto select(Signature* f) noexcept {
|
||||
return f;
|
||||
}
|
||||
|
||||
template < typename Signature, typename Base >
|
||||
constexpr auto select(Signature Base::*f) noexcept {
|
||||
return f;
|
||||
}
|
||||
|
||||
template < typename R, typename Base, typename... Args >
|
||||
constexpr auto select_const(R (Base::*f)(Args...) const) noexcept {
|
||||
return f;
|
||||
}
|
||||
|
||||
template < typename R, typename Base, typename... Args >
|
||||
constexpr auto select_non_const(R(Base::*f)(Args...)) noexcept {
|
||||
return f;
|
||||
}
|
||||
}
|
||||
|
||||
namespace meta_hpp::detail
|
||||
{
|
||||
template < typename K, typename V, typename C, typename K2 >
|
||||
std::optional<V> find_opt(const std::map<K, V, C>& src, K2&& key) {
|
||||
if ( auto iter = src.find(key); iter != src.end() ) {
|
||||
return iter->second;
|
||||
}
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
template < typename K, typename V, typename C, typename K2, typename V2, typename F >
|
||||
void merge_with(std::map<K, V, C>& dst, K2&& key, V2&& value, F&& f) {
|
||||
if ( auto iter = dst.find(key); iter != dst.end() ) {
|
||||
std::invoke(std::forward<F>(f), iter->second, std::forward<V2>(value));
|
||||
} else {
|
||||
dst.emplace(std::forward<K2>(key), std::forward<V2>(value));
|
||||
}
|
||||
}
|
||||
|
||||
template < typename K, typename V, typename C, typename F >
|
||||
void merge_with(std::map<K, V, C>& dst, const std::map<K, V, C>& src, F&& f) {
|
||||
for ( auto [key, value] : src ) {
|
||||
merge_with(dst, key, value, f);
|
||||
}
|
||||
}
|
||||
}
|
||||
186
headers/meta.hpp/meta_method.hpp
Normal file
186
headers/meta.hpp/meta_method.hpp
Normal file
@@ -0,0 +1,186 @@
|
||||
/*******************************************************************************
|
||||
* 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_fwd.hpp"
|
||||
|
||||
#include "meta_value.hpp"
|
||||
|
||||
namespace meta_hpp::method_detail
|
||||
{
|
||||
template < typename Method >
|
||||
struct method_traits;
|
||||
|
||||
template < typename R, typename Base, typename... Args >
|
||||
struct method_traits<R(Base::*)(Args...)> {
|
||||
static constexpr bool is_const = false;
|
||||
static constexpr std::size_t arity = sizeof...(Args);
|
||||
using return_type = R;
|
||||
using instance_type = Base;
|
||||
using argument_types = std::tuple<Args...>;
|
||||
};
|
||||
|
||||
template < typename R, typename Base, typename... Args >
|
||||
struct method_traits<R(Base::*)(Args...) const>
|
||||
: method_traits<R(Base::*)(Args...)> {
|
||||
static constexpr bool is_const = true;
|
||||
};
|
||||
|
||||
template < typename R, typename Base, typename... Args >
|
||||
struct method_traits<R(Base::*)(Args...) noexcept>
|
||||
: method_traits<R(Base::*)(Args...)> {};
|
||||
|
||||
template < typename R, typename Base, typename... Args >
|
||||
struct method_traits<R(Base::*)(Args...) const noexcept>
|
||||
: method_traits<R(Base::*)(Args...) const> {};
|
||||
|
||||
template < auto Method, std::size_t... Is >
|
||||
value invoke(void* instance, value* args, std::index_sequence<Is...>) {
|
||||
using mt = method_traits<decltype(Method)>;
|
||||
using return_type = typename mt::return_type;
|
||||
using instance_type = typename mt::instance_type;
|
||||
using argument_types = typename mt::argument_types;
|
||||
|
||||
auto typed_arguments = std::make_tuple(
|
||||
(args + Is)->try_cast<std::tuple_element_t<Is, argument_types>>()...);
|
||||
|
||||
if ( !(std::get<Is>(typed_arguments) && ...) ) {
|
||||
throw std::logic_error("an attempt to call a method with incorrect argument types");
|
||||
}
|
||||
|
||||
if constexpr ( std::is_void_v<return_type> ) {
|
||||
std::invoke(Method,
|
||||
std::ref(*static_cast<instance_type*>(instance)),
|
||||
*std::get<Is>(typed_arguments)...);
|
||||
return value{};
|
||||
} else {
|
||||
return_type return_value = std::invoke(Method,
|
||||
std::ref(*static_cast<instance_type*>(instance)),
|
||||
*std::get<Is>(typed_arguments)...);
|
||||
return value{std::move(return_value)};
|
||||
}
|
||||
}
|
||||
|
||||
template < auto Method >
|
||||
value invoke(void* instance, value* args, std::size_t arg_count) {
|
||||
using mt = method_traits<decltype(Method)>;
|
||||
|
||||
if ( arg_count != mt::arity ) {
|
||||
throw std::logic_error("an attempt to call a method with an incorrect arity");
|
||||
}
|
||||
|
||||
return invoke<Method>(instance, args, std::make_index_sequence<mt::arity>());
|
||||
}
|
||||
|
||||
template < auto Method, std::size_t... Is >
|
||||
value cinvoke(const void* instance, value* args, std::index_sequence<Is...>) {
|
||||
using mt = method_traits<decltype(Method)>;
|
||||
using return_type = typename mt::return_type;
|
||||
using instance_type = typename mt::instance_type;
|
||||
using argument_types = typename mt::argument_types;
|
||||
|
||||
auto typed_arguments = std::make_tuple(
|
||||
(args + Is)->try_cast<std::tuple_element_t<Is, argument_types>>()...);
|
||||
|
||||
if ( !(std::get<Is>(typed_arguments) && ...) ) {
|
||||
throw std::logic_error("an attempt to call a method with incorrect argument types");
|
||||
}
|
||||
|
||||
if constexpr ( mt::is_const ) {
|
||||
if constexpr ( std::is_void_v<return_type> ) {
|
||||
std::invoke(Method,
|
||||
std::ref(*static_cast<const instance_type*>(instance)),
|
||||
*std::get<Is>(typed_arguments)...);
|
||||
return value{};
|
||||
} else {
|
||||
return_type return_value = std::invoke(Method,
|
||||
std::ref(*static_cast<const instance_type*>(instance)),
|
||||
*std::get<Is>(typed_arguments)...);
|
||||
return value{std::move(return_value)};
|
||||
}
|
||||
} else {
|
||||
throw std::logic_error("an attempt to call a non-constant method by constant instance");
|
||||
}
|
||||
}
|
||||
|
||||
template < auto Method >
|
||||
value cinvoke(const void* instance, value* args, std::size_t arg_count) {
|
||||
using mt = method_traits<decltype(Method)>;
|
||||
|
||||
if ( arg_count != mt::arity ) {
|
||||
throw std::logic_error("an attempt to call a method with a different arity");
|
||||
}
|
||||
|
||||
return cinvoke<Method>(instance, args, std::make_index_sequence<mt::arity>());
|
||||
}
|
||||
}
|
||||
|
||||
namespace meta_hpp
|
||||
{
|
||||
class method_info {
|
||||
public:
|
||||
method_info() = delete;
|
||||
|
||||
method_info(method_info&&) = default;
|
||||
method_info(const method_info&) = default;
|
||||
|
||||
method_info& operator=(method_info&&) = default;
|
||||
method_info& operator=(const method_info&) = default;
|
||||
|
||||
method_info(std::string id)
|
||||
: id_(std::move(id)) {}
|
||||
|
||||
const std::string& id() const noexcept {
|
||||
return id_;
|
||||
}
|
||||
public:
|
||||
template < typename... Args >
|
||||
value invoke(void* instance, Args&&... args) const {
|
||||
std::array<value, sizeof...(Args)> vargs{{std::forward<Args>(args)...}};
|
||||
return invoke_(instance, vargs.data(), vargs.size());
|
||||
}
|
||||
|
||||
template < typename... Args >
|
||||
value invoke(const void* instance, Args&&... args) const {
|
||||
std::array<value, sizeof...(Args)> vargs{{std::forward<Args>(args)...}};
|
||||
return cinvoke_(instance, vargs.data(), vargs.size());
|
||||
}
|
||||
private:
|
||||
friend class class_info;
|
||||
template < typename Class > friend class class_;
|
||||
template < auto Method > friend class method_;
|
||||
private:
|
||||
void merge_with_(const method_info& other) {
|
||||
(void)other;
|
||||
}
|
||||
private:
|
||||
std::string id_;
|
||||
value(*invoke_)(void*, value*, std::size_t);
|
||||
value(*cinvoke_)(const void*, value*, std::size_t);
|
||||
};
|
||||
}
|
||||
|
||||
namespace meta_hpp
|
||||
{
|
||||
template < auto Method >
|
||||
class method_ {
|
||||
public:
|
||||
static_assert(std::is_member_function_pointer_v<decltype(Method)>);
|
||||
|
||||
explicit method_(std::string id)
|
||||
: info_(std::move(id)) {
|
||||
info_.invoke_ = &method_detail::invoke<Method>;
|
||||
info_.cinvoke_ = &method_detail::cinvoke<Method>;
|
||||
}
|
||||
|
||||
const method_info& info() const noexcept {
|
||||
return info_;
|
||||
}
|
||||
private:
|
||||
method_info info_;
|
||||
};
|
||||
}
|
||||
121
headers/meta.hpp/meta_namespace.hpp
Normal file
121
headers/meta.hpp/meta_namespace.hpp
Normal file
@@ -0,0 +1,121 @@
|
||||
/*******************************************************************************
|
||||
* 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_fwd.hpp"
|
||||
|
||||
#include "meta_class.hpp"
|
||||
#include "meta_function.hpp"
|
||||
#include "meta_variable.hpp"
|
||||
|
||||
namespace meta_hpp
|
||||
{
|
||||
class namespace_info {
|
||||
public:
|
||||
namespace_info() = delete;
|
||||
|
||||
namespace_info(namespace_info&&) = default;
|
||||
namespace_info(const namespace_info&) = default;
|
||||
|
||||
namespace_info& operator=(namespace_info&&) = default;
|
||||
namespace_info& operator=(const namespace_info&) = default;
|
||||
|
||||
namespace_info(std::string id)
|
||||
: id_(std::move(id)) {}
|
||||
|
||||
const std::string& id() const noexcept {
|
||||
return id_;
|
||||
}
|
||||
|
||||
std::optional<class_info> get_class(std::string_view id) const {
|
||||
return detail::find_opt(classes_, id);
|
||||
}
|
||||
|
||||
std::optional<function_info> get_function(std::string_view id) const {
|
||||
return detail::find_opt(functions_, id);
|
||||
}
|
||||
|
||||
std::optional<namespace_info> get_namespace(std::string_view id) const {
|
||||
return detail::find_opt(namespaces_, id);
|
||||
}
|
||||
|
||||
std::optional<variable_info> get_variable(std::string_view id) const {
|
||||
return detail::find_opt(variables_, id);
|
||||
}
|
||||
private:
|
||||
friend class namespace_;
|
||||
private:
|
||||
void merge_with_(const namespace_info& other) {
|
||||
detail::merge_with(classes_, other.classes_, &class_info::merge_with_);
|
||||
detail::merge_with(functions_, other.functions_, &function_info::merge_with_);
|
||||
detail::merge_with(namespaces_, other.namespaces_, &namespace_info::merge_with_);
|
||||
detail::merge_with(variables_, other.variables_, &variable_info::merge_with_);
|
||||
}
|
||||
private:
|
||||
std::string id_;
|
||||
std::map<std::string, class_info, std::less<>> classes_;
|
||||
std::map<std::string, function_info, std::less<>> functions_;
|
||||
std::map<std::string, namespace_info, std::less<>> namespaces_;
|
||||
std::map<std::string, variable_info, std::less<>> variables_;
|
||||
};
|
||||
}
|
||||
|
||||
namespace meta_hpp
|
||||
{
|
||||
class namespace_ {
|
||||
public:
|
||||
explicit namespace_(std::string id)
|
||||
: info_(std::move(id)) {}
|
||||
|
||||
const namespace_info& info() const noexcept {
|
||||
return info_;
|
||||
}
|
||||
|
||||
template < typename... Internals >
|
||||
namespace_& operator()(Internals&&...internals) {
|
||||
(add_(std::forward<Internals>(internals)), ...);
|
||||
return *this;
|
||||
}
|
||||
private:
|
||||
template < typename InternalClass >
|
||||
void add_(const class_<InternalClass>& internal) {
|
||||
detail::merge_with(
|
||||
info_.classes_,
|
||||
internal.info().id(),
|
||||
internal.info(),
|
||||
&class_info::merge_with_);
|
||||
}
|
||||
|
||||
template < auto InternalFunction >
|
||||
void add_(const function_<InternalFunction>& internal) {
|
||||
detail::merge_with(
|
||||
info_.functions_,
|
||||
internal.info().id(),
|
||||
internal.info(),
|
||||
&function_info::merge_with_);
|
||||
}
|
||||
|
||||
void add_(const namespace_& internal) {
|
||||
detail::merge_with(
|
||||
info_.namespaces_,
|
||||
internal.info().id(),
|
||||
internal.info(),
|
||||
&namespace_info::merge_with_);
|
||||
}
|
||||
|
||||
template < auto Internalvariable >
|
||||
void add_(const variable_<Internalvariable>& internal) {
|
||||
detail::merge_with(
|
||||
info_.variables_,
|
||||
internal.info().id(),
|
||||
internal.info(),
|
||||
&variable_info::merge_with_);
|
||||
}
|
||||
private:
|
||||
namespace_info info_;
|
||||
};
|
||||
}
|
||||
46
headers/meta.hpp/meta_registry.hpp
Normal file
46
headers/meta.hpp/meta_registry.hpp
Normal file
@@ -0,0 +1,46 @@
|
||||
/*******************************************************************************
|
||||
* 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_fwd.hpp"
|
||||
|
||||
#include "meta_class.hpp"
|
||||
#include "meta_function.hpp"
|
||||
#include "meta_namespace.hpp"
|
||||
#include "meta_variable.hpp"
|
||||
|
||||
namespace meta_hpp
|
||||
{
|
||||
class registry {
|
||||
public:
|
||||
registry() = default;
|
||||
|
||||
template < typename... Internals >
|
||||
registry& operator()(Internals&&...internals) {
|
||||
default_namespace_(std::forward<Internals>(internals)...);
|
||||
return *this;
|
||||
}
|
||||
|
||||
std::optional<class_info> get_class(std::string_view id) const {
|
||||
return default_namespace_.info().get_class(id);
|
||||
}
|
||||
|
||||
std::optional<function_info> get_function(std::string_view id) const {
|
||||
return default_namespace_.info().get_function(id);
|
||||
}
|
||||
|
||||
std::optional<namespace_info> get_namespace(std::string_view id) const {
|
||||
return default_namespace_.info().get_namespace(id);
|
||||
}
|
||||
|
||||
std::optional<variable_info> get_variable(std::string_view id) const {
|
||||
return default_namespace_.info().get_variable(id);
|
||||
}
|
||||
private:
|
||||
namespace_ default_namespace_{""};
|
||||
};
|
||||
}
|
||||
38
headers/meta.hpp/meta_value.hpp
Normal file
38
headers/meta.hpp/meta_value.hpp
Normal 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)
|
||||
******************************************************************************/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "meta_fwd.hpp"
|
||||
|
||||
namespace meta_hpp
|
||||
{
|
||||
class value {
|
||||
public:
|
||||
value() = default;
|
||||
|
||||
template < typename T >
|
||||
value(T&& value)
|
||||
: raw_{std::forward<T>(value)} {}
|
||||
|
||||
template < typename T >
|
||||
auto cast() const {
|
||||
return std::any_cast<T>(raw_);
|
||||
}
|
||||
|
||||
template < typename T >
|
||||
auto try_cast() noexcept {
|
||||
return std::any_cast<T>(&raw_);
|
||||
}
|
||||
|
||||
template < typename T >
|
||||
auto try_cast() const noexcept {
|
||||
return std::any_cast<T>(&raw_);
|
||||
}
|
||||
private:
|
||||
std::any raw_;
|
||||
};
|
||||
}
|
||||
116
headers/meta.hpp/meta_variable.hpp
Normal file
116
headers/meta.hpp/meta_variable.hpp
Normal file
@@ -0,0 +1,116 @@
|
||||
/*******************************************************************************
|
||||
* 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_fwd.hpp"
|
||||
|
||||
#include "meta_value.hpp"
|
||||
|
||||
namespace meta_hpp::variable_detail
|
||||
{
|
||||
template < typename Variable >
|
||||
struct variable_traits;
|
||||
|
||||
template < typename T >
|
||||
struct variable_traits<T*> {
|
||||
static constexpr bool is_const = false;
|
||||
using value_type = T;
|
||||
};
|
||||
|
||||
template < typename T >
|
||||
struct variable_traits<const T*> {
|
||||
static constexpr bool is_const = true;
|
||||
using value_type = T;
|
||||
};
|
||||
|
||||
template < auto Variable >
|
||||
value getter() {
|
||||
using vt = variable_traits<decltype(Variable)>;
|
||||
using value_type = typename vt::value_type;
|
||||
|
||||
value_type typed_value = *Variable;
|
||||
|
||||
return value{std::move(typed_value)};
|
||||
}
|
||||
|
||||
template < auto Variable >
|
||||
void setter(value value) {
|
||||
using vt = variable_traits<decltype(Variable)>;
|
||||
using value_type = typename vt::value_type;
|
||||
|
||||
if constexpr ( !vt::is_const ) {
|
||||
*Variable = value.cast<value_type>();
|
||||
} else {
|
||||
throw std::logic_error("an attempt to change a constant variable");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
namespace meta_hpp
|
||||
{
|
||||
class variable_info {
|
||||
public:
|
||||
variable_info() = delete;
|
||||
|
||||
variable_info(variable_info&&) = default;
|
||||
variable_info(const variable_info&) = default;
|
||||
|
||||
variable_info& operator=(variable_info&&) = default;
|
||||
variable_info& operator=(const variable_info&) = default;
|
||||
|
||||
variable_info(std::string id)
|
||||
: id_(std::move(id)) {}
|
||||
|
||||
const std::string& id() const noexcept {
|
||||
return id_;
|
||||
}
|
||||
public:
|
||||
value get() const {
|
||||
return getter_();
|
||||
}
|
||||
|
||||
template < typename Value >
|
||||
void set(Value&& value) const {
|
||||
return setter_(std::forward<Value>(value));
|
||||
}
|
||||
private:
|
||||
friend class class_info;
|
||||
friend class namespace_info;
|
||||
template < typename Class > friend class class_;
|
||||
friend class namespace_;
|
||||
template < auto Variable > friend class variable_;
|
||||
private:
|
||||
void merge_with_(const variable_info& other) {
|
||||
(void)other;
|
||||
}
|
||||
private:
|
||||
std::string id_;
|
||||
value(*getter_)();
|
||||
void(*setter_)(value);
|
||||
};
|
||||
}
|
||||
|
||||
namespace meta_hpp
|
||||
{
|
||||
template < auto Variable >
|
||||
class variable_ {
|
||||
public:
|
||||
static_assert(std::is_pointer_v<decltype(Variable)>);
|
||||
|
||||
explicit variable_(std::string id)
|
||||
: info_(std::move(id)) {
|
||||
info_.getter_ = &variable_detail::getter<Variable>;
|
||||
info_.setter_ = &variable_detail::setter<Variable>;
|
||||
}
|
||||
|
||||
const variable_info& info() const noexcept {
|
||||
return info_;
|
||||
}
|
||||
private:
|
||||
variable_info info_;
|
||||
};
|
||||
}
|
||||
107
untests/meta_class_tests.cpp
Normal file
107
untests/meta_class_tests.cpp
Normal 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.hpp/meta_class.hpp>
|
||||
#include "doctest/doctest.hpp"
|
||||
|
||||
namespace
|
||||
{
|
||||
class clazz {
|
||||
public:
|
||||
class clazz2 {
|
||||
};
|
||||
|
||||
int field{1};
|
||||
const int cfield{2};
|
||||
|
||||
static int func(int a) { return a; }
|
||||
|
||||
int method(int a) { return a; }
|
||||
int cmethod(int a) const { return a; }
|
||||
|
||||
static int variable;
|
||||
static const int cvariable;
|
||||
};
|
||||
|
||||
int clazz::variable{1};
|
||||
const int clazz::cvariable{2};
|
||||
}
|
||||
|
||||
TEST_CASE("meta/class") {
|
||||
namespace meta = meta_hpp;
|
||||
|
||||
meta::class_<clazz> class_{"clazz"};
|
||||
const meta::class_<clazz>& cclass_ = class_;
|
||||
const meta::class_info& clazz_info = cclass_.info();
|
||||
|
||||
CHECK_FALSE(clazz_info.get_class("clazz2"));
|
||||
CHECK_FALSE(clazz_info.get_field("field"));
|
||||
CHECK_FALSE(clazz_info.get_field("cfield"));
|
||||
CHECK_FALSE(clazz_info.get_function("func"));
|
||||
CHECK_FALSE(clazz_info.get_method("method"));
|
||||
CHECK_FALSE(clazz_info.get_method("cmethod"));
|
||||
CHECK_FALSE(clazz_info.get_variable("variable"));
|
||||
CHECK_FALSE(clazz_info.get_variable("cvariable"));
|
||||
|
||||
class_(
|
||||
meta::class_<clazz::clazz2>("clazz2"),
|
||||
meta::field_<&clazz::field>("field"),
|
||||
meta::field_<&clazz::cfield>("cfield"),
|
||||
meta::function_<&clazz::func>("func"),
|
||||
meta::method_<&clazz::method>("method"),
|
||||
meta::method_<&clazz::cmethod>("cmethod"),
|
||||
meta::variable_<&clazz::variable>("variable"),
|
||||
meta::variable_<&clazz::cvariable>("cvariable"));
|
||||
|
||||
CHECK(clazz_info.get_class("clazz2"));
|
||||
CHECK(clazz_info.get_field("field"));
|
||||
CHECK(clazz_info.get_field("cfield"));
|
||||
CHECK(clazz_info.get_function("func"));
|
||||
CHECK(clazz_info.get_method("method"));
|
||||
CHECK(clazz_info.get_method("cmethod"));
|
||||
CHECK(clazz_info.get_variable("variable"));
|
||||
CHECK(clazz_info.get_variable("cvariable"));
|
||||
|
||||
{
|
||||
meta::class_info clazz2_info = clazz_info.get_class("clazz2").value();
|
||||
CHECK(clazz2_info.id() == "clazz2");
|
||||
}
|
||||
|
||||
{
|
||||
meta::field_info field_info = clazz_info.get_field("field").value();
|
||||
CHECK(field_info.id() == "field");
|
||||
}
|
||||
|
||||
{
|
||||
meta::field_info cfield_info = clazz_info.get_field("cfield").value();
|
||||
CHECK(cfield_info.id() == "cfield");
|
||||
}
|
||||
|
||||
{
|
||||
meta::function_info function_info = clazz_info.get_function("func").value();
|
||||
CHECK(function_info.id() == "func");
|
||||
}
|
||||
|
||||
{
|
||||
meta::method_info method_info = clazz_info.get_method("method").value();
|
||||
CHECK(method_info.id() == "method");
|
||||
}
|
||||
|
||||
{
|
||||
meta::method_info cmethod_info = clazz_info.get_method("cmethod").value();
|
||||
CHECK(cmethod_info.id() == "cmethod");
|
||||
}
|
||||
|
||||
{
|
||||
meta::variable_info variable_info = clazz_info.get_variable("variable").value();
|
||||
CHECK(variable_info.id() == "variable");
|
||||
}
|
||||
|
||||
{
|
||||
meta::variable_info cvariable_info = clazz_info.get_variable("cvariable").value();
|
||||
CHECK(cvariable_info.id() == "cvariable");
|
||||
}
|
||||
}
|
||||
142
untests/meta_examples.cpp
Normal file
142
untests/meta_examples.cpp
Normal file
@@ -0,0 +1,142 @@
|
||||
/*******************************************************************************
|
||||
* 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.hpp/meta.hpp>
|
||||
#include "doctest/doctest.hpp"
|
||||
|
||||
namespace
|
||||
{
|
||||
class ivec2 {
|
||||
public:
|
||||
int x{};
|
||||
int y{};
|
||||
|
||||
ivec2() = default;
|
||||
explicit ivec2(int v): x{v}, y{v} {}
|
||||
ivec2(int x, int y): x{x}, y{y} {}
|
||||
|
||||
int dot(ivec2 other) const {
|
||||
return x * other.x + y * other.y;
|
||||
}
|
||||
|
||||
int length2() const {
|
||||
return dot(*this);
|
||||
}
|
||||
};
|
||||
|
||||
class ivec3 {
|
||||
public:
|
||||
int x{};
|
||||
int y{};
|
||||
int z{};
|
||||
|
||||
ivec3() = default;
|
||||
explicit ivec3(int v): x{v}, y{v}, z{v} {}
|
||||
ivec3(int x, int y, int z): x{x}, y{y}, z{z} {}
|
||||
|
||||
int dot(ivec3 other) const {
|
||||
return x * other.x + y * other.y + z * other.z;
|
||||
}
|
||||
|
||||
int length2() const {
|
||||
return dot(*this);
|
||||
}
|
||||
};
|
||||
|
||||
ivec2 add(ivec2 l, ivec2 r) {
|
||||
return {l.x + r.x, l.y + r.y};
|
||||
}
|
||||
|
||||
ivec3 add(ivec3 l, ivec3 r) {
|
||||
return {l.x + r.x, l.y + r.y, l.z + r.z};
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("meta/examples/ivec2") {
|
||||
SUBCASE("ctors") {
|
||||
CHECK(ivec2{}.x == 0);
|
||||
CHECK(ivec2{}.y == 0);
|
||||
|
||||
CHECK(ivec2{1}.x == 1);
|
||||
CHECK(ivec2{1}.y == 1);
|
||||
|
||||
CHECK(ivec2{2,3}.x == 2);
|
||||
CHECK(ivec2{2,3}.y == 3);
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("meta/examples/ivec3") {
|
||||
SUBCASE("ctors") {
|
||||
CHECK(ivec3{}.x == 0);
|
||||
CHECK(ivec3{}.y == 0);
|
||||
CHECK(ivec3{}.z == 0);
|
||||
|
||||
CHECK(ivec3{1}.x == 1);
|
||||
CHECK(ivec3{1}.y == 1);
|
||||
CHECK(ivec3{1}.z == 1);
|
||||
|
||||
CHECK(ivec3{2,3,4}.x == 2);
|
||||
CHECK(ivec3{2,3,4}.y == 3);
|
||||
CHECK(ivec3{2,3,4}.z == 4);
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("meta/examples/simple") {
|
||||
namespace meta = meta_hpp;
|
||||
|
||||
auto registry = meta::registry{}(
|
||||
meta::namespace_("vmath")(
|
||||
meta::class_<ivec2>("ivec2")(
|
||||
meta::field_<&ivec2::x>("x"),
|
||||
meta::field_<&ivec2::y>("y"),
|
||||
meta::method_<&ivec2::dot>("dot"),
|
||||
meta::method_<&ivec2::length2>("length2")
|
||||
),
|
||||
meta::class_<ivec3>("ivec3")(
|
||||
meta::field_<&ivec3::x>("x"),
|
||||
meta::field_<&ivec3::y>("y"),
|
||||
meta::field_<&ivec3::z>("z"),
|
||||
meta::method_<&ivec3::dot>("dot"),
|
||||
meta::method_<&ivec3::length2>("length2")
|
||||
),
|
||||
meta::function_<meta::select<ivec2(ivec2,ivec2)>(&add)>("iadd2"),
|
||||
meta::function_<meta::select<ivec3(ivec3,ivec3)>(&add)>("iadd3")
|
||||
)
|
||||
);
|
||||
|
||||
meta::namespace_info vmath_info = registry.get_namespace("vmath").value();
|
||||
|
||||
meta::class_info ivec2_info = vmath_info.get_class("ivec2").value();
|
||||
meta::field_info ivec2_x_info = ivec2_info.get_field("x").value();
|
||||
meta::field_info ivec2_y_info = ivec2_info.get_field("y").value();
|
||||
|
||||
meta::method_info ivec2_dot_info = ivec2_info.get_method("dot").value();
|
||||
meta::method_info ivec2_length2_info = ivec2_info.get_method("length2").value();
|
||||
|
||||
meta::function_info iadd2_info = vmath_info.get_function("iadd2").value();
|
||||
meta::function_info iadd3_info = vmath_info.get_function("iadd3").value();
|
||||
|
||||
{
|
||||
ivec2 v2{1,2};
|
||||
CHECK(ivec2_x_info.get(&v2).cast<int>() == 1);
|
||||
CHECK(ivec2_y_info.get(&v2).cast<int>() == 2);
|
||||
CHECK(ivec2_dot_info.invoke(&v2, v2).cast<int>() == 5);
|
||||
CHECK(ivec2_length2_info.invoke(&v2).cast<int>() == 5);
|
||||
}
|
||||
|
||||
{
|
||||
ivec2 v = iadd2_info.invoke(ivec2{1,2}, ivec2{3,4}).cast<ivec2>();
|
||||
CHECK(v.x == 4);
|
||||
CHECK(v.y == 6);
|
||||
}
|
||||
|
||||
{
|
||||
ivec3 v = iadd3_info.invoke(ivec3{1,2,3}, ivec3{3,4,5}).cast<ivec3>();
|
||||
CHECK(v.x == 4);
|
||||
CHECK(v.y == 6);
|
||||
CHECK(v.z == 8);
|
||||
}
|
||||
}
|
||||
63
untests/meta_field_tests.cpp
Normal file
63
untests/meta_field_tests.cpp
Normal file
@@ -0,0 +1,63 @@
|
||||
/*******************************************************************************
|
||||
* 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.hpp/meta_field.hpp>
|
||||
#include "doctest/doctest.hpp"
|
||||
|
||||
namespace
|
||||
{
|
||||
class clazz {
|
||||
public:
|
||||
int field{1};
|
||||
const int cfield{2};
|
||||
};
|
||||
}
|
||||
|
||||
TEST_CASE("meta/field") {
|
||||
namespace meta = meta_hpp;
|
||||
|
||||
meta::field_<&clazz::field> field_{"field"};
|
||||
meta::field_<&clazz::cfield> cfield_{"cfield"};
|
||||
|
||||
const meta::field_info& field_info = field_.info();
|
||||
const meta::field_info& cfield_info = cfield_.info();
|
||||
|
||||
{
|
||||
clazz instance;
|
||||
|
||||
CHECK(instance.field == 1);
|
||||
CHECK(field_info.get(&instance).cast<int>() == 1);
|
||||
CHECK(field_info.get(&std::as_const(instance)).cast<int>() == 1);
|
||||
|
||||
CHECK_NOTHROW(field_info.set(&instance, 3));
|
||||
|
||||
CHECK(instance.field == 3);
|
||||
CHECK(field_info.get(&instance).cast<int>() == 3);
|
||||
CHECK(field_info.get(&std::as_const(instance)).cast<int>() == 3);
|
||||
}
|
||||
|
||||
{
|
||||
clazz instance;
|
||||
|
||||
CHECK(instance.cfield == 2);
|
||||
CHECK(cfield_info.get(&instance).cast<int>() == 2);
|
||||
CHECK(cfield_info.get(&std::as_const(instance)).cast<int>() == 2);
|
||||
|
||||
CHECK_THROWS_AS(cfield_info.set(&instance, 4), std::logic_error);
|
||||
|
||||
CHECK(instance.cfield == 2);
|
||||
CHECK(cfield_info.get(&instance).cast<int>() == 2);
|
||||
CHECK(cfield_info.get(&std::as_const(instance)).cast<int>() == 2);
|
||||
}
|
||||
|
||||
{
|
||||
clazz instance;
|
||||
|
||||
instance.field = 5;
|
||||
CHECK(field_info.get(&instance).cast<int>() == 5);
|
||||
CHECK(field_info.get(&std::as_const(instance)).cast<int>() == 5);
|
||||
}
|
||||
}
|
||||
73
untests/meta_function_tests.cpp
Normal file
73
untests/meta_function_tests.cpp
Normal file
@@ -0,0 +1,73 @@
|
||||
/*******************************************************************************
|
||||
* 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.hpp/meta_function.hpp>
|
||||
#include "doctest/doctest.hpp"
|
||||
|
||||
namespace
|
||||
{
|
||||
void void_f_void() noexcept {}
|
||||
void void_f_int(int a) { (void)a; }
|
||||
void void_f_int2(int a, int b) { (void)a; (void)b; }
|
||||
|
||||
int int_f_void() noexcept { return 1; }
|
||||
int int_f_int(int a) { return a; }
|
||||
int int_f_int2(int a, int b) { return a + b; }
|
||||
}
|
||||
|
||||
TEST_CASE("meta/function") {
|
||||
namespace meta = meta_hpp;
|
||||
|
||||
meta::function_<&void_f_void> void_f_void_function_("void_f_void");
|
||||
meta::function_<&void_f_int> void_f_int_function_("void_f_int");
|
||||
meta::function_<&void_f_int2> void_f_int2_function_("void_f_int2");
|
||||
|
||||
meta::function_<&int_f_void> int_f_void_function_("int_f_void");
|
||||
meta::function_<&int_f_int> int_f_int_function_("int_f_int");
|
||||
meta::function_<&int_f_int2> int_f_int2_function_("int_f_int2");
|
||||
|
||||
const meta::function_info& void_f_void_info = void_f_void_function_.info();
|
||||
const meta::function_info& void_f_int_info = void_f_int_function_.info();
|
||||
const meta::function_info& void_f_int2_info = void_f_int2_function_.info();
|
||||
|
||||
const meta::function_info& int_f_void_info = int_f_void_function_.info();
|
||||
const meta::function_info& int_f_int_info = int_f_int_function_.info();
|
||||
const meta::function_info& int_f_int2_info = int_f_int2_function_.info();
|
||||
|
||||
SUBCASE("void_return") {
|
||||
CHECK_NOTHROW(void_f_void_info.invoke());
|
||||
CHECK_THROWS_AS(void_f_void_info.invoke(1), std::logic_error);
|
||||
|
||||
CHECK_THROWS_AS(void_f_int_info.invoke(), std::logic_error);
|
||||
CHECK_NOTHROW(void_f_int_info.invoke(1));
|
||||
CHECK_THROWS_AS(void_f_int_info.invoke(1.f), std::logic_error);
|
||||
CHECK_THROWS_AS(void_f_int_info.invoke(1, 2), std::logic_error);
|
||||
|
||||
CHECK_THROWS_AS(void_f_int2_info.invoke(), std::logic_error);
|
||||
CHECK_THROWS_AS(void_f_int2_info.invoke(1), std::logic_error);
|
||||
CHECK_NOTHROW(void_f_int2_info.invoke(1, 2));
|
||||
CHECK_THROWS_AS(void_f_int2_info.invoke(1.f, 2), std::logic_error);
|
||||
CHECK_THROWS_AS(void_f_int2_info.invoke(1, 2.f), std::logic_error);
|
||||
CHECK_THROWS_AS(void_f_int2_info.invoke(1, 2, 3), std::logic_error);
|
||||
}
|
||||
|
||||
SUBCASE("int_return") {
|
||||
CHECK(int_f_void_info.invoke().cast<int>() == 1);
|
||||
CHECK_THROWS_AS(int_f_void_info.invoke(1), std::logic_error);
|
||||
|
||||
CHECK_THROWS_AS(int_f_int_info.invoke(), std::logic_error);
|
||||
CHECK(int_f_int_info.invoke(1).cast<int>() == 1);
|
||||
CHECK_THROWS_AS(int_f_int_info.invoke(1.f), std::logic_error);
|
||||
CHECK_THROWS_AS(int_f_int_info.invoke(1, 2), std::logic_error);
|
||||
|
||||
CHECK_THROWS_AS(int_f_int2_info.invoke(), std::logic_error);
|
||||
CHECK_THROWS_AS(int_f_int2_info.invoke(1), std::logic_error);
|
||||
CHECK(int_f_int2_info.invoke(1, 2).cast<int>() == 3);
|
||||
CHECK_THROWS_AS(int_f_int2_info.invoke(1.f, 2), std::logic_error);
|
||||
CHECK_THROWS_AS(int_f_int2_info.invoke(1, 2.f), std::logic_error);
|
||||
CHECK_THROWS_AS(int_f_int2_info.invoke(1, 2, 3), std::logic_error);
|
||||
}
|
||||
}
|
||||
166
untests/meta_method_tests.cpp
Normal file
166
untests/meta_method_tests.cpp
Normal file
@@ -0,0 +1,166 @@
|
||||
/*******************************************************************************
|
||||
* 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.hpp/meta_method.hpp>
|
||||
#include "doctest/doctest.hpp"
|
||||
|
||||
namespace
|
||||
{
|
||||
class clazz {
|
||||
public:
|
||||
void void_f_void() noexcept {}
|
||||
void void_f_int(int a) { (void)a; }
|
||||
void void_f_int2(int a, int b) { (void)a; (void)b; }
|
||||
|
||||
int int_f_void() noexcept { return 1; }
|
||||
int int_f_int(int a) { return a; }
|
||||
int int_f_int2(int a, int b) { return a + b; }
|
||||
|
||||
void const_void_f_void() const noexcept {}
|
||||
void const_void_f_int(int a) const { (void)a; }
|
||||
void const_void_f_int2(int a, int b) const { (void)a; (void)b; }
|
||||
|
||||
int const_int_f_void() const noexcept { return 1; }
|
||||
int const_int_f_int(int a) const { return a; }
|
||||
int const_int_f_int2(int a, int b) const { return a + b; }
|
||||
};
|
||||
}
|
||||
|
||||
TEST_CASE("meta/non_const_method") {
|
||||
namespace meta = meta_hpp;
|
||||
|
||||
meta::method_<&clazz::void_f_void> void_f_void_method_("void_f_void");
|
||||
meta::method_<&clazz::void_f_int> void_f_int_method_("void_f_int");
|
||||
meta::method_<&clazz::void_f_int2> void_f_int2_method_("void_f_int2");
|
||||
|
||||
meta::method_<&clazz::int_f_void> int_f_void_method_("int_f_void");
|
||||
meta::method_<&clazz::int_f_int> int_f_int_method_("int_f_int");
|
||||
meta::method_<&clazz::int_f_int2> int_f_int2_method_("int_f_int2");
|
||||
|
||||
const meta::method_info& void_f_void_info = void_f_void_method_.info();
|
||||
const meta::method_info& void_f_int_info = void_f_int_method_.info();
|
||||
const meta::method_info& void_f_int2_info = void_f_int2_method_.info();
|
||||
|
||||
const meta::method_info& int_f_void_info = int_f_void_method_.info();
|
||||
const meta::method_info& int_f_int_info = int_f_int_method_.info();
|
||||
const meta::method_info& int_f_int2_info = int_f_int2_method_.info();
|
||||
|
||||
SUBCASE("void_return") {
|
||||
clazz instance;
|
||||
|
||||
CHECK_NOTHROW(void_f_void_info.invoke(&instance));
|
||||
CHECK_THROWS_AS(void_f_void_info.invoke(&instance, 1), std::logic_error);
|
||||
|
||||
CHECK_THROWS_AS(void_f_int_info.invoke(&instance), std::logic_error);
|
||||
CHECK_NOTHROW(void_f_int_info.invoke(&instance, 1));
|
||||
CHECK_THROWS_AS(void_f_int_info.invoke(&instance, 1.f), std::logic_error);
|
||||
CHECK_THROWS_AS(void_f_int_info.invoke(&instance, 1, 2), std::logic_error);
|
||||
|
||||
CHECK_THROWS_AS(void_f_int2_info.invoke(&instance), std::logic_error);
|
||||
CHECK_THROWS_AS(void_f_int2_info.invoke(&instance, 1), std::logic_error);
|
||||
CHECK_NOTHROW(void_f_int2_info.invoke(&instance, 1, 2));
|
||||
CHECK_THROWS_AS(void_f_int2_info.invoke(&instance, 1.f, 2), std::logic_error);
|
||||
CHECK_THROWS_AS(void_f_int2_info.invoke(&instance, 1, 2.f), std::logic_error);
|
||||
CHECK_THROWS_AS(void_f_int2_info.invoke(&instance, 1, 2, 3), std::logic_error);
|
||||
|
||||
const clazz& cinstance = instance;
|
||||
CHECK_THROWS_AS(void_f_void_info.invoke(&cinstance), std::logic_error);
|
||||
CHECK_THROWS_AS(void_f_int_info.invoke(&cinstance, 1), std::logic_error);
|
||||
CHECK_THROWS_AS(void_f_int2_info.invoke(&cinstance, 1, 2), std::logic_error);
|
||||
}
|
||||
|
||||
SUBCASE("int_return") {
|
||||
clazz instance;
|
||||
|
||||
CHECK(int_f_void_info.invoke(&instance).cast<int>() == 1);
|
||||
CHECK_THROWS_AS(int_f_void_info.invoke(&instance, 1), std::logic_error);
|
||||
|
||||
CHECK_THROWS_AS(int_f_int_info.invoke(&instance), std::logic_error);
|
||||
CHECK(int_f_int_info.invoke(&instance, 1).cast<int>() == 1);
|
||||
CHECK_THROWS_AS(int_f_int_info.invoke(&instance, 1.f), std::logic_error);
|
||||
CHECK_THROWS_AS(int_f_int_info.invoke(&instance, 1, 2), std::logic_error);
|
||||
|
||||
CHECK_THROWS_AS(int_f_int2_info.invoke(&instance), std::logic_error);
|
||||
CHECK_THROWS_AS(int_f_int2_info.invoke(&instance, 1), std::logic_error);
|
||||
CHECK(int_f_int2_info.invoke(&instance, 1, 2).cast<int>() == 3);
|
||||
CHECK_THROWS_AS(int_f_int2_info.invoke(&instance, 1.f, 2), std::logic_error);
|
||||
CHECK_THROWS_AS(int_f_int2_info.invoke(&instance, 1, 2.f), std::logic_error);
|
||||
CHECK_THROWS_AS(int_f_int2_info.invoke(&instance, 1, 2, 3), std::logic_error);
|
||||
|
||||
const clazz& cinstance = instance;
|
||||
CHECK_THROWS_AS(int_f_void_info.invoke(&cinstance), std::logic_error);
|
||||
CHECK_THROWS_AS(int_f_int_info.invoke(&cinstance, 1), std::logic_error);
|
||||
CHECK_THROWS_AS(int_f_int2_info.invoke(&cinstance, 1, 2), std::logic_error);
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("meta/const_method") {
|
||||
namespace meta = meta_hpp;
|
||||
|
||||
meta::method_<&clazz::const_void_f_void> void_f_void_method_("void_f_void");
|
||||
meta::method_<&clazz::const_void_f_int> void_f_int_method_("void_f_int");
|
||||
meta::method_<&clazz::const_void_f_int2> void_f_int2_method_("void_f_int2");
|
||||
|
||||
meta::method_<&clazz::const_int_f_void> int_f_void_method_("int_f_void");
|
||||
meta::method_<&clazz::const_int_f_int> int_f_int_method_("int_f_int");
|
||||
meta::method_<&clazz::const_int_f_int2> int_f_int2_method_("int_f_int2");
|
||||
|
||||
const meta::method_info& void_f_void_info = void_f_void_method_.info();
|
||||
const meta::method_info& void_f_int_info = void_f_int_method_.info();
|
||||
const meta::method_info& void_f_int2_info = void_f_int2_method_.info();
|
||||
|
||||
const meta::method_info& int_f_void_info = int_f_void_method_.info();
|
||||
const meta::method_info& int_f_int_info = int_f_int_method_.info();
|
||||
const meta::method_info& int_f_int2_info = int_f_int2_method_.info();
|
||||
|
||||
SUBCASE("void_return") {
|
||||
clazz instance;
|
||||
|
||||
CHECK_NOTHROW(void_f_void_info.invoke(&instance));
|
||||
CHECK_THROWS_AS(void_f_void_info.invoke(&instance, 1), std::logic_error);
|
||||
|
||||
CHECK_THROWS_AS(void_f_int_info.invoke(&instance), std::logic_error);
|
||||
CHECK_NOTHROW(void_f_int_info.invoke(&instance, 1));
|
||||
CHECK_THROWS_AS(void_f_int_info.invoke(&instance, 1.f), std::logic_error);
|
||||
CHECK_THROWS_AS(void_f_int_info.invoke(&instance, 1, 2), std::logic_error);
|
||||
|
||||
CHECK_THROWS_AS(void_f_int2_info.invoke(&instance), std::logic_error);
|
||||
CHECK_THROWS_AS(void_f_int2_info.invoke(&instance, 1), std::logic_error);
|
||||
CHECK_NOTHROW(void_f_int2_info.invoke(&instance, 1, 2));
|
||||
CHECK_THROWS_AS(void_f_int2_info.invoke(&instance, 1.f, 2), std::logic_error);
|
||||
CHECK_THROWS_AS(void_f_int2_info.invoke(&instance, 1, 2.f), std::logic_error);
|
||||
CHECK_THROWS_AS(void_f_int2_info.invoke(&instance, 1, 2, 3), std::logic_error);
|
||||
|
||||
const clazz& cinstance = instance;
|
||||
CHECK_NOTHROW(void_f_void_info.invoke(&cinstance));
|
||||
CHECK_NOTHROW(void_f_int_info.invoke(&cinstance, 1));
|
||||
CHECK_NOTHROW(void_f_int2_info.invoke(&cinstance, 1, 2));
|
||||
}
|
||||
|
||||
SUBCASE("int_return") {
|
||||
clazz instance;
|
||||
|
||||
CHECK(int_f_void_info.invoke(&instance).cast<int>() == 1);
|
||||
CHECK_THROWS_AS(int_f_void_info.invoke(&instance, 1), std::logic_error);
|
||||
|
||||
CHECK_THROWS_AS(int_f_int_info.invoke(&instance), std::logic_error);
|
||||
CHECK(int_f_int_info.invoke(&instance, 1).cast<int>() == 1);
|
||||
CHECK_THROWS_AS(int_f_int_info.invoke(&instance, 1.f), std::logic_error);
|
||||
CHECK_THROWS_AS(int_f_int_info.invoke(&instance, 1, 2), std::logic_error);
|
||||
|
||||
CHECK_THROWS_AS(int_f_int2_info.invoke(&instance), std::logic_error);
|
||||
CHECK_THROWS_AS(int_f_int2_info.invoke(&instance, 1), std::logic_error);
|
||||
CHECK(int_f_int2_info.invoke(&instance, 1, 2).cast<int>() == 3);
|
||||
CHECK_THROWS_AS(int_f_int2_info.invoke(&instance, 1.f, 2), std::logic_error);
|
||||
CHECK_THROWS_AS(int_f_int2_info.invoke(&instance, 1, 2.f), std::logic_error);
|
||||
CHECK_THROWS_AS(int_f_int2_info.invoke(&instance, 1, 2, 3), std::logic_error);
|
||||
|
||||
const clazz& cinstance = instance;
|
||||
CHECK(int_f_void_info.invoke(&cinstance).cast<int>() == 1);
|
||||
CHECK(int_f_int_info.invoke(&cinstance, 1).cast<int>() == 1);
|
||||
CHECK(int_f_int2_info.invoke(&cinstance, 1, 2).cast<int>() == 3);
|
||||
}
|
||||
}
|
||||
68
untests/meta_namespace_tests.cpp
Normal file
68
untests/meta_namespace_tests.cpp
Normal 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.hpp/meta_namespace.hpp>
|
||||
#include "doctest/doctest.hpp"
|
||||
|
||||
namespace
|
||||
{
|
||||
class clazz {};
|
||||
int func(int a) { return a; }
|
||||
int variable{1};
|
||||
const int cvariable{2};
|
||||
}
|
||||
|
||||
TEST_CASE("meta/namespace") {
|
||||
namespace meta = meta_hpp;
|
||||
|
||||
meta::namespace_ namespace_{"ns"};
|
||||
const meta::namespace_& cnamespace_ = namespace_;
|
||||
const meta::namespace_info& ns_info = cnamespace_.info();
|
||||
|
||||
CHECK_FALSE(ns_info.get_class("clazz"));
|
||||
CHECK_FALSE(ns_info.get_function("func"));
|
||||
CHECK_FALSE(ns_info.get_namespace("ns"));
|
||||
CHECK_FALSE(ns_info.get_variable("variable"));
|
||||
CHECK_FALSE(ns_info.get_variable("cvariable"));
|
||||
|
||||
namespace_(
|
||||
meta::class_<clazz>("clazz"),
|
||||
meta::function_<&func>("func"),
|
||||
meta::namespace_("ns2"),
|
||||
meta::variable_<&variable>("variable"),
|
||||
meta::variable_<&cvariable>("cvariable"));
|
||||
|
||||
CHECK(ns_info.get_class("clazz"));
|
||||
CHECK(ns_info.get_function("func"));
|
||||
CHECK(ns_info.get_namespace("ns2"));
|
||||
CHECK(ns_info.get_variable("variable"));
|
||||
CHECK(ns_info.get_variable("cvariable"));
|
||||
|
||||
{
|
||||
meta::class_info clazz_info = ns_info.get_class("clazz").value();
|
||||
CHECK(clazz_info.id() == "clazz");
|
||||
}
|
||||
|
||||
{
|
||||
meta::function_info clazz_info = ns_info.get_function("func").value();
|
||||
CHECK(clazz_info.id() == "func");
|
||||
}
|
||||
|
||||
{
|
||||
meta::namespace_info namespace_info = ns_info.get_namespace("ns2").value();
|
||||
CHECK(namespace_info.id() == "ns2");
|
||||
}
|
||||
|
||||
{
|
||||
meta::variable_info variable_info = ns_info.get_variable("variable").value();
|
||||
CHECK(variable_info.id() == "variable");
|
||||
}
|
||||
|
||||
{
|
||||
meta::variable_info cvariable_info = ns_info.get_variable("cvariable").value();
|
||||
CHECK(cvariable_info.id() == "cvariable");
|
||||
}
|
||||
}
|
||||
67
untests/meta_registry_tests.cpp
Normal file
67
untests/meta_registry_tests.cpp
Normal file
@@ -0,0 +1,67 @@
|
||||
/*******************************************************************************
|
||||
* 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.hpp/meta_registry.hpp>
|
||||
#include "doctest/doctest.hpp"
|
||||
|
||||
namespace
|
||||
{
|
||||
class clazz {};
|
||||
int func(int a) { return a; }
|
||||
int variable{1};
|
||||
const int cvariable{2};
|
||||
}
|
||||
|
||||
TEST_CASE("meta/registry") {
|
||||
namespace meta = meta_hpp;
|
||||
|
||||
meta::registry registry;
|
||||
const meta::registry& cregistry = registry;
|
||||
|
||||
CHECK_FALSE(cregistry.get_class("clazz"));
|
||||
CHECK_FALSE(cregistry.get_function("func"));
|
||||
CHECK_FALSE(cregistry.get_namespace("ns"));
|
||||
CHECK_FALSE(cregistry.get_variable("variable"));
|
||||
CHECK_FALSE(cregistry.get_variable("cvariable"));
|
||||
|
||||
registry(
|
||||
meta::class_<clazz>("clazz"),
|
||||
meta::function_<&func>("func"),
|
||||
meta::namespace_("ns"),
|
||||
meta::variable_<&variable>("variable"),
|
||||
meta::variable_<&cvariable>("cvariable"));
|
||||
|
||||
CHECK(cregistry.get_class("clazz"));
|
||||
CHECK(cregistry.get_function("func"));
|
||||
CHECK(cregistry.get_namespace("ns"));
|
||||
CHECK(cregistry.get_variable("variable"));
|
||||
CHECK(cregistry.get_variable("cvariable"));
|
||||
|
||||
{
|
||||
meta::class_info clazz_info = cregistry.get_class("clazz").value();
|
||||
CHECK(clazz_info.id() == "clazz");
|
||||
}
|
||||
|
||||
{
|
||||
meta::function_info clazz_info = cregistry.get_function("func").value();
|
||||
CHECK(clazz_info.id() == "func");
|
||||
}
|
||||
|
||||
{
|
||||
meta::namespace_info namespace_info = cregistry.get_namespace("ns").value();
|
||||
CHECK(namespace_info.id() == "ns");
|
||||
}
|
||||
|
||||
{
|
||||
meta::variable_info variable_info = cregistry.get_variable("variable").value();
|
||||
CHECK(variable_info.id() == "variable");
|
||||
}
|
||||
|
||||
{
|
||||
meta::variable_info cvariable_info = cregistry.get_variable("cvariable").value();
|
||||
CHECK(cvariable_info.id() == "cvariable");
|
||||
}
|
||||
}
|
||||
@@ -1,16 +0,0 @@
|
||||
/*******************************************************************************
|
||||
* 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
|
||||
{
|
||||
using namespace meta_hpp;
|
||||
using namespace meta_tests;
|
||||
}
|
||||
|
||||
TEST_CASE("meta") {
|
||||
}
|
||||
@@ -4,10 +4,13 @@
|
||||
* Copyright (C) 2021, by Matvey Cherevko (blackmatov@gmail.com)
|
||||
******************************************************************************/
|
||||
|
||||
#include <meta.hpp/meta.hpp>
|
||||
#include <meta.hpp/meta_value.hpp>
|
||||
#include "doctest/doctest.hpp"
|
||||
|
||||
namespace meta_tests
|
||||
namespace
|
||||
{
|
||||
using namespace meta_hpp;
|
||||
}
|
||||
|
||||
TEST_CASE("meta/value") {
|
||||
namespace meta = meta_hpp;
|
||||
}
|
||||
93
untests/meta_variable_tests.cpp
Normal file
93
untests/meta_variable_tests.cpp
Normal 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)
|
||||
******************************************************************************/
|
||||
|
||||
#include <meta.hpp/meta_variable.hpp>
|
||||
#include "doctest/doctest.hpp"
|
||||
|
||||
namespace
|
||||
{
|
||||
int variable{1};
|
||||
const int cvariable{2};
|
||||
|
||||
class clazz {
|
||||
public:
|
||||
static int variable;
|
||||
static const int cvariable;
|
||||
};
|
||||
|
||||
int clazz::variable{1};
|
||||
const int clazz::cvariable{2};
|
||||
}
|
||||
|
||||
TEST_CASE("meta/variable") {
|
||||
namespace meta = meta_hpp;
|
||||
|
||||
SUBCASE("in_namespace") {
|
||||
meta::variable_<&variable> variable_{"variable"};
|
||||
meta::variable_<&cvariable> cvariable_{"cvariable"};
|
||||
|
||||
const meta::variable_info& variable_info = variable_.info();
|
||||
const meta::variable_info& cvariable_info = cvariable_.info();
|
||||
|
||||
{
|
||||
CHECK(variable == 1);
|
||||
CHECK(variable_info.get().cast<int>() == 1);
|
||||
|
||||
CHECK_NOTHROW(variable_info.set(3));
|
||||
|
||||
CHECK(variable == 3);
|
||||
CHECK(variable_info.get().cast<int>() == 3);
|
||||
}
|
||||
|
||||
{
|
||||
CHECK(cvariable == 2);
|
||||
CHECK(cvariable_info.get().cast<int>() == 2);
|
||||
|
||||
CHECK_THROWS_AS(cvariable_info.set(4), std::logic_error);
|
||||
|
||||
CHECK(cvariable == 2);
|
||||
CHECK(cvariable_info.get().cast<int>() == 2);
|
||||
}
|
||||
|
||||
{
|
||||
variable = 5;
|
||||
CHECK(variable_info.get().cast<int>() == 5);
|
||||
}
|
||||
}
|
||||
|
||||
SUBCASE("in_class") {
|
||||
meta::variable_<&clazz::variable> variable_{"variable"};
|
||||
meta::variable_<&clazz::cvariable> cvariable_{"cvariable"};
|
||||
|
||||
const meta::variable_info& variable_info = variable_.info();
|
||||
const meta::variable_info& cvariable_info = cvariable_.info();
|
||||
|
||||
{
|
||||
CHECK(clazz::variable == 1);
|
||||
CHECK(variable_info.get().cast<int>() == 1);
|
||||
|
||||
CHECK_NOTHROW(variable_info.set(3));
|
||||
|
||||
CHECK(clazz::variable == 3);
|
||||
CHECK(variable_info.get().cast<int>() == 3);
|
||||
}
|
||||
|
||||
{
|
||||
CHECK(clazz::cvariable == 2);
|
||||
CHECK(cvariable_info.get().cast<int>() == 2);
|
||||
|
||||
CHECK_THROWS_AS(cvariable_info.set(4), std::logic_error);
|
||||
|
||||
CHECK(clazz::cvariable == 2);
|
||||
CHECK(cvariable_info.get().cast<int>() == 2);
|
||||
}
|
||||
|
||||
{
|
||||
clazz::variable = 5;
|
||||
CHECK(variable_info.get().cast<int>() == 5);
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user