diff --git a/headers/meta.hpp/meta.hpp b/headers/meta.hpp/meta.hpp index c4d3df7..5a4b00a 100644 --- a/headers/meta.hpp/meta.hpp +++ b/headers/meta.hpp/meta.hpp @@ -10,6 +10,7 @@ #include "meta_value.hpp" +#include "meta_registry.hpp" #include "meta_type.hpp" #include "meta_class.hpp" diff --git a/headers/meta.hpp/meta_fwd.hpp b/headers/meta.hpp/meta_fwd.hpp index 09be441..7e3a219 100644 --- a/headers/meta.hpp/meta_fwd.hpp +++ b/headers/meta.hpp/meta_fwd.hpp @@ -26,6 +26,7 @@ namespace meta_hpp { class value; + class registry; class type; class class_info; diff --git a/headers/meta.hpp/meta_registry.hpp b/headers/meta.hpp/meta_registry.hpp new file mode 100644 index 0000000..feb24ae --- /dev/null +++ b/headers/meta.hpp/meta_registry.hpp @@ -0,0 +1,108 @@ +/******************************************************************************* + * 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_type.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" + +namespace meta_hpp +{ + class registry { + public: + template < auto T > + std::optional resolve() const { + const family_id fid = get_family_id(); + return detail::find_opt(family_to_types_, fid); + } + + template < typename T > + std::optional resolve() const { + const family_id fid = get_family_id(); + return detail::find_opt(family_to_types_, fid); + } + + template < typename T > + std::optional resolve(const T&) const { + const family_id fid = get_family_id(); + return detail::find_opt(family_to_types_, fid); + } + + template < typename... Internals > + registry& operator()(Internals&&...internals) { + (add_(std::forward(internals)), ...); + return *this; + } + private: + void add_(const class_info& info) { + family_to_types_.emplace(info.fid(), info); + + info.each_class([this](const class_info& internal){ + add_(internal); + }); + + info.each_field([this](const field_info& internal){ + add_(internal); + }); + + info.each_function([this](const function_info& internal){ + add_(internal); + }); + + info.each_method([this](const method_info& internal){ + add_(internal); + }); + + info.each_variable([this](const variable_info& internal){ + add_(internal); + }); + } + + void add_(const field_info& info) { + family_to_types_.emplace(info.fid(), info); + } + + void add_(const function_info& info) { + family_to_types_.emplace(info.fid(), info); + } + + void add_(const method_info& info) { + family_to_types_.emplace(info.fid(), info); + } + + void add_(const namespace_info& info) { + info.each_class([this](const class_info& internal){ + add_(internal); + }); + + info.each_function([this](const function_info& internal){ + add_(internal); + }); + + info.each_namespace([this](const namespace_info& internal){ + add_(internal); + }); + + info.each_variable([this](const variable_info& internal){ + add_(internal); + }); + } + + void add_(const variable_info& info) { + family_to_types_.emplace(info.fid(), info); + } + private: + std::map> family_to_types_; + }; +} diff --git a/untests/meta_registry_tests.cpp b/untests/meta_registry_tests.cpp new file mode 100644 index 0000000..7dce6b8 --- /dev/null +++ b/untests/meta_registry_tests.cpp @@ -0,0 +1,171 @@ +/******************************************************************************* + * 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 +#include "doctest/doctest.hpp" + +namespace +{ + struct ivec2 { + int x{}; + int y{}; + + static ivec2 zero; + + int dot(ivec2 other) const { + return x * other.x + y * other.y; + } + }; + + struct ivec3 { + int x{}; + int y{}; + int z{}; + + static ivec3 zero; + + int dot(ivec3 other) const { + return x * other.x + y * other.y + z * other.z; + } + }; + + ivec2 ivec2::zero{}; + ivec3 ivec3::zero{}; + + ivec2 iadd2(ivec2 l, ivec2 r) { + return {l.x + r.x, l.y + r.y}; + } + + ivec3 iadd3(ivec3 l, ivec3 r) { + return {l.x + r.x, l.y + r.y, l.z + r.z}; + } +} + +TEST_CASE("meta/registry") { + namespace meta = meta_hpp; + using namespace std::string_literals; + + auto registry = meta::registry{}( + meta::namespace_("vmath")( + meta::class_("ivec2")( + meta::field_<&ivec2::x>("x"), + meta::field_<&ivec2::y>("y"), + meta::method_<&ivec2::dot>("dot"), + meta::variable_<&ivec2::zero>("zero") + ), + meta::class_("ivec3")( + meta::field_<&ivec3::x>("x"), + meta::field_<&ivec3::y>("y"), + meta::field_<&ivec3::z>("z"), + meta::method_<&ivec3::dot>("dot"), + meta::variable_<&ivec3::zero>("zero") + ), + meta::function_<&iadd2>("iadd2"), + meta::function_<&iadd3>("iadd3") + ) + ); + + SUBCASE("class_template") { + CHECK(registry.resolve()); + + const meta::type ivec2_type = registry.resolve().value(); + CHECK(ivec2_type.is_class()); + + const meta::class_info& ivec2_info = ivec2_type.get_class_info(); + CHECK(ivec2_info.id() == "ivec2"); + } + + SUBCASE("class_instance") { + ivec3 v3; + CHECK(registry.resolve(v3)); + + const meta::type ivec3_type = registry.resolve(v3).value(); + CHECK(ivec3_type.is_class()); + + const meta::class_info& ivec3_info = ivec3_type.get_class_info(); + CHECK(ivec3_info.id() == "ivec3"); + } + + SUBCASE("field_template") { + CHECK(registry.resolve<&ivec2::x>()); + + const meta::type ivec2_x_type = registry.resolve<&ivec2::x>().value(); + CHECK(ivec2_x_type.is_field()); + + const meta::field_info& ivec2_x_info = ivec2_x_type.get_field_info(); + CHECK(ivec2_x_info.id() == "x"); + } + + SUBCASE("field_instance") { + CHECK(registry.resolve(&ivec3::x)); + + const meta::type ivec3_x_type = registry.resolve<&ivec3::x>().value(); + CHECK(ivec3_x_type.is_field()); + + const meta::field_info& ivec3_x_info = ivec3_x_type.get_field_info(); + CHECK(ivec3_x_info.id() == "x"); + } + + SUBCASE("function_template") { + CHECK(registry.resolve<&iadd2>()); + + const meta::type iadd2_type = registry.resolve<&iadd2>().value(); + CHECK(iadd2_type.is_function()); + + const meta::function_info& iadd2_info = iadd2_type.get_function_info(); + CHECK(iadd2_info.id() == "iadd2"); + } + + SUBCASE("function_instance") { + CHECK(registry.resolve(&iadd3)); + + const meta::type iadd3_type = registry.resolve<&iadd3>().value(); + CHECK(iadd3_type.is_function()); + + const meta::function_info& iadd3_info = iadd3_type.get_function_info(); + CHECK(iadd3_info.id() == "iadd3"); + } + + SUBCASE("method_template") { + CHECK(registry.resolve<&ivec2::dot>()); + + const meta::type ivec2_dot_type = registry.resolve<&ivec2::dot>().value(); + CHECK(ivec2_dot_type.is_method()); + + const meta::method_info& ivec2_dot_info = ivec2_dot_type.get_method_info(); + CHECK(ivec2_dot_info.id() == "dot"); + } + + SUBCASE("method_instance") { + CHECK(registry.resolve(&ivec3::dot)); + + const meta::type ivec3_dot_type = registry.resolve<&ivec3::dot>().value(); + CHECK(ivec3_dot_type.is_method()); + + const meta::method_info& ivec3_dot_info = ivec3_dot_type.get_method_info(); + CHECK(ivec3_dot_info.id() == "dot"); + } + + SUBCASE("variable_template") { + CHECK(registry.resolve<&ivec2::zero>()); + + const meta::type ivec2_zero_type = registry.resolve<&ivec2::zero>().value(); + CHECK(ivec2_zero_type.is_variable()); + + const meta::variable_info& ivec2_x_info = ivec2_zero_type.get_variable_info(); + CHECK(ivec2_x_info.id() == "zero"); + } + + SUBCASE("variable_instance") { + CHECK(registry.resolve(&ivec3::zero)); + + const meta::type ivec3_zero_type = registry.resolve<&ivec3::zero>().value(); + CHECK(ivec3_zero_type.is_variable()); + + const meta::variable_info& ivec3_x_info = ivec3_zero_type.get_variable_info(); + CHECK(ivec3_x_info.id() == "zero"); + } +}