Skip to content

Commit

Permalink
add possiblitiy to register a function of a base class
Browse files Browse the repository at this point in the history
during register of a derived class.
Internally the base class will be extracted from the
member function pointer an added to the base class list of the derived class.

Example and use case:
---------------------

struct base
{
    void some_method() {}
};

struct derived : base
{
};

registration::class_<derived>("derived")
        .method("some_method", &derived::some_method);

dereived d;
type::get(d).get_method("some_method").invoke(d); // now this is possible
  • Loading branch information
acki-m committed Mar 31, 2017
1 parent 8dbbf79 commit 28dbc85
Show file tree
Hide file tree
Showing 6 changed files with 230 additions and 2 deletions.
2 changes: 2 additions & 0 deletions src/rttr/detail/registration/bind_impl.h
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@
#include "rttr/detail/misc/utility.h"
#include "rttr/detail/type/type_register.h"
#include "rttr/detail/default_arguments/default_arguments.h"
#include "rttr/detail/registration/register_base_class_from_accessor.h"
#include "rttr/policy.h"
#include "rttr/type.h"

Expand Down Expand Up @@ -699,6 +700,7 @@ class registration::bind<detail::meth, Class_Type, F, acc_level> : public regist
bind(const std::shared_ptr<detail::registration_executer>& reg_exec, string_view name, F f)
: registration_derived_t<Class_Type>(reg_exec), m_reg_exec(reg_exec), m_name(name), m_func(f)
{
detail::register_accessor_class_type_when_needed<Class_Type, F>();
m_reg_exec->add_registration_func(this);
}

Expand Down
115 changes: 115 additions & 0 deletions src/rttr/detail/registration/register_base_class_from_accessor.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
/************************************************************************************
* *
* Copyright (c) 2014, 2015 - 2017 Axel Menzel <info@rttr.org> *
* *
* This file is part of RTTR (Run Time Type Reflection) *
* License: MIT License *
* *
* Permission is hereby granted, free of charge, to any person obtaining *
* a copy of this software and associated documentation files (the "Software"), *
* to deal in the Software without restriction, including without limitation *
* the rights to use, copy, modify, merge, publish, distribute, sublicense, *
* and/or sell copies of the Software, and to permit persons to whom the *
* Software is furnished to do so, subject to the following conditions: *
* *
* The above copyright notice and this permission notice shall be included in *
* all copies or substantial portions of the Software. *
* *
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR *
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, *
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE *
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER *
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, *
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE *
* SOFTWARE. *
* *
*************************************************************************************/

#ifndef RTTR_REGISTER_BASE_CLASS_FROM_ACCESSOR_H_
#define RTTR_REGISTER_BASE_CLASS_FROM_ACCESSOR_H_

#include "rttr/detail/base/core_prerequisites.h"

#include "rttr/detail/type/base_classes.h"
#include "rttr/detail/type/type_register.h"

#include <type_traits>

namespace rttr
{
namespace detail
{

template<typename ClassType, typename FuncClassType>
enable_if_t<contains<FuncClassType, typename ClassType::base_class_list>::value, void>
register_member_func_class_type_when_needed_3()
{
}

template<typename ClassType, typename FuncClassType>
enable_if_t<!contains<FuncClassType, typename ClassType::base_class_list>::value, void>
register_member_func_class_type_when_needed_3()
{
base_class_info baseClassInfo = { type::get<FuncClassType>(), &rttr_cast_impl<ClassType, FuncClassType> };
type_register::register_base_class(type::get<ClassType>(), baseClassInfo);
}

template<typename ClassType, typename FuncClassType>
enable_if_t<has_base_class_list<ClassType>::value, void>
register_member_func_class_type_when_needed_2()
{
register_member_func_class_type_when_needed_3<ClassType, FuncClassType>();
}

template<typename ClassType, typename FuncClassType>
enable_if_t<!has_base_class_list<ClassType>::value, void>
register_member_func_class_type_when_needed_2()
{
base_class_info baseClassInfo = { type::get<FuncClassType>(), &rttr_cast_impl<ClassType, FuncClassType> };
type_register::register_base_class(type::get<ClassType>(), baseClassInfo);

}

template<typename ClassType, typename FuncClassType>
enable_if_t<std::is_base_of<FuncClassType, ClassType>::value, void>
register_member_func_class_type_when_needed_1()
{
register_member_func_class_type_when_needed_2<ClassType, FuncClassType>();
}

template<typename ClassType, typename FuncClassType>
enable_if_t<!std::is_base_of<FuncClassType, ClassType>::value, void>
register_member_func_class_type_when_needed_1()
{
}

template<typename ClassType, typename FuncClassType>
enable_if_t<!std::is_same<ClassType, FuncClassType>::value, void>
register_member_func_class_type_when_needed()
{
register_member_func_class_type_when_needed_1<ClassType, FuncClassType>();
}

template<typename ClassType, typename FuncClassType>
enable_if_t<std::is_same<ClassType, FuncClassType>::value, void>
register_member_func_class_type_when_needed()
{
}

template<typename ClassType, typename F>
enable_if_t<std::is_member_function_pointer<F>::value, void>
register_accessor_class_type_when_needed()
{
register_member_func_class_type_when_needed<ClassType, typename function_traits<F>::class_type>();
}

template<typename ClassType, typename F>
enable_if_t<!std::is_member_function_pointer<F>::value, void>
register_accessor_class_type_when_needed()
{
}

} // end namespace detail
} // end namespace rttr

#endif // RTTR_REGISTER_BASE_CLASS_FROM_ACCESSOR_H_
49 changes: 48 additions & 1 deletion src/rttr/detail/type/type_register.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -137,6 +137,54 @@ void type_register::less_than_comparator(const type& t, type_comparator_base* co

/////////////////////////////////////////////////////////////////////////////////////////

void type_register::register_base_class(const type& derived_type, const base_class_info& base_info)
{
auto& class_data = derived_type.m_type_data->get_class_data();
auto itr = std::find_if(class_data.m_base_types.begin(), class_data.m_base_types.end(),
[base_info](const type& t)
{
return (t == base_info.m_base_type);
});

if (itr != class_data.m_base_types.end()) // already registerd as base class => quit
return;

std::vector<std::pair<type, rttr_cast_func>> tmp_sort_vec;
using sorted_pair = decltype(tmp_sort_vec)::value_type;
if (class_data.m_base_types.size() != class_data.m_conversion_list.size())
return; // error!!!

int index = 0;
for (const auto& item : class_data.m_base_types)
{
tmp_sort_vec.emplace_back(item, class_data.m_conversion_list[index]);
++index;
}

tmp_sort_vec.emplace_back(base_info.m_base_type, base_info.m_rttr_cast_func);
std::sort(tmp_sort_vec.begin(), tmp_sort_vec.end(),
[](const sorted_pair& left, const sorted_pair& right)
{ return left.first.get_id() < right.first.get_id(); });

class_data.m_base_types.clear();
class_data.m_conversion_list.clear();

std::transform(tmp_sort_vec.begin(),
tmp_sort_vec.end(),
std::back_inserter(class_data.m_base_types),
[](const sorted_pair& item)-> type { return item.first; });

std::transform(tmp_sort_vec.begin(),
tmp_sort_vec.end(),
std::back_inserter(class_data.m_conversion_list),
[](const sorted_pair& item)-> rttr_cast_func { return item.second; });

auto r_type = base_info.m_base_type.get_raw_type();
r_type.m_type_data->get_class_data().m_derived_types.push_back(type(derived_type.m_type_data));
}

/////////////////////////////////////////////////////////////////////////////////////////

type type_register::type_reg(type_data& info) RTTR_NOEXCEPT
{
return type_register_private::register_type(info);
Expand Down Expand Up @@ -301,7 +349,6 @@ type type_register_private::register_type(type_data& info) RTTR_NOEXCEPT
// register the base types
info.get_base_types();

//std::lock_guard<std::mutex> lock(*g_register_type_mutex);
using namespace detail;
uint16_t id = 0;
const bool isAlreadyRegistered = register_name(id, info);
Expand Down
2 changes: 2 additions & 0 deletions src/rttr/detail/type/type_register.h
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,8 @@ class RTTR_API type_register

static void less_than_comparator(const type& t, type_comparator_base* comparator);

static void register_base_class(const type& derived_type, const base_class_info& base_info);

/*!
* \brief Register the type info for the given name
*
Expand Down
1 change: 1 addition & 0 deletions src/rttr/rttr.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,7 @@ set(HEADER_FILES access_levels.h
detail/property/property_wrapper_object.h
detail/registration/bind_types.h
detail/registration/bind_impl.h
detail/registration/register_base_class_from_accessor.h
detail/registration/registration_impl.h
detail/registration/registration_executer.h
detail/type/accessor_type.h
Expand Down
63 changes: 62 additions & 1 deletion src/unit_tests/method/test_method_reflection.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,29 @@ std::string& get_global_string()
return text;
}

struct base_not_registered
{
bool some_method()
{
return true;
}

void other_method(int i)
{
}
};

struct derive_registered : base_not_registered
{

};


struct derive_registered_with_base_class_list : base_not_registered
{
RTTR_ENABLE() // but forgot the base class to insert in the macro
};


/////////////////////////////////////////////////////////////////////////////////////////

Expand Down Expand Up @@ -134,11 +157,22 @@ RTTR_REGISTRATION
(
policy::meth::discard_return
);

// the class 'derive_registered' has a base class 'base_not_registered'
// which is not registered explictely via rttr, however the base-derived relationship
// will be established by rttr internaly
registration::class_<derive_registered>("derive_registered")
.method("some_method", &derive_registered::some_method)
.method("other_method", &derive_registered::other_method)
;

registration::class_<derive_registered_with_base_class_list>("derive_registered_with_base_class_list")
.method("some_method", &derive_registered_with_base_class_list::some_method)
;
}

/////////////////////////////////////////////////////////////////////////////////////////


TEST_CASE("Test method", "[method]")
{
type t_meth = type::get<method_test>();
Expand Down Expand Up @@ -500,6 +534,33 @@ TEST_CASE("method - invoke with variant as argument", "[method]")

/////////////////////////////////////////////////////////////////////////////////////////

TEST_CASE("method - invoke base method, which is not registerd", "[method]")
{
type t_meth = type::get<derive_registered>();
method meth = t_meth.get_method("some_method");
derive_registered obj;

auto ret = meth.invoke(obj);

CHECK(ret.is_valid() == true);
CHECK(ret.to_bool() == true);

auto base_type = type::get<base_not_registered>();

CHECK(t_meth.is_derived_from(base_type) == true);

auto derived_type = type::get<derive_registered_with_base_class_list>();
CHECK(derived_type.is_derived_from(base_type) == true);

auto range = base_type.get_derived_classes();

REQUIRE(range.size() == 2);
CHECK(*range.begin() == t_meth);
CHECK(*(++range.begin()) == derived_type);
}

/////////////////////////////////////////////////////////////////////////////////////////

TEST_CASE("Test method meta data", "[method]")
{
method m8 = type::get<method_test_final>().get_method("method_8");
Expand Down

0 comments on commit 28dbc85

Please sign in to comment.