Skip to content

Commit

Permalink
added support for forwarding a rttr::variant into a property or a method
Browse files Browse the repository at this point in the history
when the underlying datatype is itself a rttr::variant.

Therefore the internals of the argument class needed to be adjusted.
Now an additional variant ptr needs to be stored inside the argument class.

Closed #47
  • Loading branch information
acki-m committed Mar 20, 2017
1 parent 5120097 commit 739411e
Show file tree
Hide file tree
Showing 6 changed files with 111 additions and 14 deletions.
19 changes: 17 additions & 2 deletions src/rttr/argument.h
Original file line number Diff line number Diff line change
Expand Up @@ -55,17 +55,26 @@ class RTTR_API argument
!std::is_same<variant_array_view, T>::value, T>;

template<typename T>
using arg_value_t = detail::enable_if_t<!std::is_rvalue_reference<T>::value, T>;
using is_variant = std::is_same<detail::remove_cv_t<detail::remove_reference_t<T>>, variant>;

template<typename T>
using arg_rvalue_t = detail::enable_if_t<std::is_rvalue_reference<T>::value, detail::remove_reference_t<T> >;
using arg_value_t = detail::enable_if_t<!std::is_rvalue_reference<T>::value && !is_variant<T>::value, T>;

template<typename T>
using arg_rvalue_t = detail::enable_if_t<std::is_rvalue_reference<T>::value && !is_variant<T>::value, detail::remove_reference_t<T> >;

template<typename T>
using ptr_type = detail::enable_if_t<std::is_pointer<T>::value, bool>;

template<typename T>
using non_ptr_type = detail::enable_if_t<!std::is_pointer<T>::value, bool>;

template<typename T>
using is_variant_t = detail::enable_if_t<is_variant<T>::value && !std::is_rvalue_reference<T>::value, T>;

template<typename T>
using is_variant_ref_t = detail::enable_if_t<is_variant<T>::value && std::is_rvalue_reference<T>::value, detail::remove_reference_t<T>>;

public:

RTTR_INLINE argument() RTTR_NOEXCEPT;
Expand Down Expand Up @@ -98,10 +107,16 @@ class RTTR_API argument
RTTR_INLINE arg_value_t<T>& get_value() const RTTR_NOEXCEPT;
template<typename T>
RTTR_INLINE arg_rvalue_t<T> && get_value() const RTTR_NOEXCEPT;

template<typename T>
RTTR_INLINE is_variant_t<T>& get_value() const RTTR_NOEXCEPT;
template<typename T>
RTTR_INLINE is_variant_ref_t<T> && get_value() const RTTR_NOEXCEPT;
#endif

private:
const void* m_data;
const variant* m_variant;
const rttr::type m_type;
};

Expand Down
38 changes: 31 additions & 7 deletions src/rttr/detail/impl/argument_impl.h
Original file line number Diff line number Diff line change
Expand Up @@ -36,29 +36,30 @@ namespace rttr

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

RTTR_INLINE argument::argument() RTTR_NOEXCEPT : m_data(nullptr), m_type(detail::get_invalid_type()) {}
RTTR_INLINE argument::argument() RTTR_NOEXCEPT : m_data(nullptr), m_variant(nullptr), m_type(detail::get_invalid_type()) {}

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

RTTR_INLINE argument::argument(argument&& arg) RTTR_NOEXCEPT : m_data(arg.m_data), m_type(arg.m_type) {}
RTTR_INLINE argument::argument(argument&& arg) RTTR_NOEXCEPT : m_data(arg.m_data), m_variant(arg.m_variant), m_type(arg.m_type) {}

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

RTTR_INLINE argument::argument(const argument& other) RTTR_NOEXCEPT : m_data(other.m_data), m_type(other.m_type) {}
RTTR_INLINE argument::argument(const argument& other) RTTR_NOEXCEPT : m_data(other.m_data), m_variant(other.m_variant), m_type(other.m_type) {}

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

RTTR_INLINE argument::argument(variant& var) RTTR_NOEXCEPT : m_data(var.get_ptr()), m_type(var.get_type()) {}
RTTR_INLINE argument::argument(variant& var) RTTR_NOEXCEPT : m_data(var.get_ptr()), m_variant(&var), m_type(var.get_type()) {}

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

RTTR_INLINE argument::argument(const variant& var) RTTR_NOEXCEPT : m_data(var.get_ptr()), m_type(var.get_type()) {}
RTTR_INLINE argument::argument(const variant& var) RTTR_NOEXCEPT : m_data(var.get_ptr()), m_variant(&var), m_type(var.get_type()) {}

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

template<typename T, typename Tp>
argument::argument(const T& data) RTTR_NOEXCEPT
: m_data(reinterpret_cast<const void*>(std::addressof(data))),
m_variant(nullptr),
m_type(rttr::type::get<T>())
{
static_assert(!std::is_same<instance, T>::value, "Don't use the argument class for forwarding an instance!");
Expand All @@ -69,6 +70,7 @@ argument::argument(const T& data) RTTR_NOEXCEPT
template<typename T, typename Tp>
argument::argument(T& data) RTTR_NOEXCEPT
: m_data(reinterpret_cast<const void*>(std::addressof(data))),
m_variant(nullptr),
m_type(rttr::type::get<T>())
{
static_assert(!std::is_same<instance, T>::value, "Don't use the argument class for forwarding an instance!");
Expand All @@ -79,15 +81,18 @@ argument::argument(T& data) RTTR_NOEXCEPT
template<typename T>
RTTR_INLINE argument::ptr_type<T> argument::is_type() const RTTR_NOEXCEPT
{
return ((rttr::type::get<T>() == m_type) || m_type == type::get<std::nullptr_t>());
return ((rttr::type::get<T>() == m_type) ||
m_type == type::get<std::nullptr_t>() ||
(m_variant && type::get<variant*>() == type::get<T>()));
}

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

template<typename T>
RTTR_INLINE argument::non_ptr_type<T> argument::is_type() const RTTR_NOEXCEPT
{
return (rttr::type::get<T>() == m_type);
return (rttr::type::get<T>() == m_type ||
(m_variant && type::get<variant>() == type::get<T>()));
}

/////////////////////////////////////////////////////////////////////////////////////////
Expand Down Expand Up @@ -117,10 +122,29 @@ RTTR_INLINE argument::arg_rvalue_t<T>&& argument::get_value() const RTTR_NOEXCEP

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

template<typename T>
RTTR_INLINE argument::is_variant_t<T>& argument::get_value() const RTTR_NOEXCEPT
{
using raw_type = typename std::remove_reference<T>::type;
return (*reinterpret_cast<raw_type*>(const_cast<variant *>(m_variant)));
}

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

template<typename T>
RTTR_INLINE argument::is_variant_ref_t<T>&& argument::get_value() const RTTR_NOEXCEPT
{
using raw_type = typename std::remove_reference<T>::type;
return std::move(*reinterpret_cast<raw_type*>(const_cast<variant *>(m_data)));
}

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

RTTR_INLINE argument& argument::operator=(const argument& other) RTTR_NOEXCEPT
{
m_data = other.m_data;
const_cast<rttr::type&>(m_type) = other.m_type;
m_variant = other.m_variant;
return *this;
}

Expand Down
4 changes: 2 additions & 2 deletions src/rttr/parameter_info.h
Original file line number Diff line number Diff line change
Expand Up @@ -130,7 +130,7 @@ class RTTR_API parameter_info
*/
variant get_default_value() const;

/*!
/*!
* \brief Returns the name of this parameter.
* When no name was provided during registration via \ref parameter_names(),
* then an empty string is returned.
Expand All @@ -139,7 +139,7 @@ class RTTR_API parameter_info
*/
string_view get_name() const RTTR_NOEXCEPT;

/*!
/*!
* \brief Returns the zero-based position of the parameter in the formal parameter list.
*
* \return An integer representing the position this parameter occupies in the parameter list.
Expand Down
21 changes: 18 additions & 3 deletions src/unit_tests/method/test_method_reflection.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,7 @@ RTTR_REGISTRATION
)
.method("method_fun_ptr_arg", &method_test::method_fun_ptr_arg)
.method("method_with_ptr", &method_test::method_with_ptr)
.method("variant_func", &method_test::set_func_via_variant)
;

registration::class_<method_test_derived>("method_test_derived")
Expand Down Expand Up @@ -267,7 +268,7 @@ TEST_CASE("Test method", "[method]")
// check up_cast, cross cast and middle in the hierarchy cast through invoke
method_test_final final_obj;
type t_final = type::get(final_obj);
REQUIRE(t_final.get_methods().size() == 20); // +1 overloaded
REQUIRE(t_final.get_methods().size() == 21); // +1 overloaded
// test the up cast
t_final.get_method("method_3").invoke(final_obj, 1000);
REQUIRE(final_obj.method_3_called == true);
Expand Down Expand Up @@ -370,13 +371,13 @@ TEST_CASE("Test method signature", "[method]")
{
const auto meth_range = type::get<method_test_final>().get_methods();
std::vector<method> methods(meth_range.cbegin(), meth_range.cend());
REQUIRE(methods.size() == 20);
REQUIRE(methods.size() == 21);

REQUIRE(methods[0].get_signature() == "method_1( )");
REQUIRE(methods[3].get_signature() == std::string("method_4( ") + type::get<std::string>().get_name() + " & )");
REQUIRE(methods[4].get_signature() == "method_5( double* )");
REQUIRE(methods[5].get_signature() == "method_5( int, double )");
REQUIRE(methods[19].get_signature() == "method_13( )");
REQUIRE(methods[20].get_signature() == "method_13( )");
}

/////////////////////////////////////////////////////////////////////////////////////////
Expand Down Expand Up @@ -485,6 +486,20 @@ TEST_CASE("method - invoke with nullptr", "[method]")

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

TEST_CASE("method - invoke with variant as argument", "[method]")
{
type t_meth = type::get<method_test>();
method meth = t_meth.get_method("variant_func");
method_test obj;

auto ret = meth.invoke(obj, variant(23));

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

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

TEST_CASE("Test method meta data", "[method]")
{
method m8 = type::get<method_test_final>().get_method("method_8");
Expand Down
5 changes: 5 additions & 0 deletions src/unit_tests/method/test_method_reflection.h
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,11 @@ struct method_test

void method_fun_ptr_arg(void(*func_ptr)(int)) { method_func_ptr_arg_called = true; m_func_ptr = func_ptr; }

bool set_func_via_variant(const rttr::variant& var)
{
return (var == 23) ? true : false;
}

double dummy_data = 12;
std::string dummy_text = "Hello World";
int method_3_value = 0;
Expand Down
38 changes: 38 additions & 0 deletions src/unit_tests/property/property_member_object.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,8 @@ struct property_member_obj_test
const int _p2 = 12;
std::vector<int> _p3;
std::vector<int> _p4 = std::vector<int>(50, 12);
variant _p7 = std::string("hello");
const variant _p8 = 23;



Expand Down Expand Up @@ -94,6 +96,8 @@ RTTR_REGISTRATION
metadata("Description", "Some Text"),
policy::prop::as_reference_wrapper
)
.property("p7", &property_member_obj_test::_p7)
.property_readonly("p8", &property_member_obj_test::_p8)
;
}

Expand Down Expand Up @@ -308,3 +312,37 @@ TEST_CASE("property - class object - read only - as_reference_wrapper", "[proper
}

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

TEST_CASE("property - variant as property", "[property]")
{
SECTION("Writable")
{
property_member_obj_test obj;
type prop_type = type::get(obj);

property prop = prop_type.get_property("p7");
REQUIRE(prop.is_valid() == true);

variant var = prop.get_value(obj);
CHECK(obj._p7 == std::string("hello"));

var = 23;
prop.set_value(obj, var);

CHECK(obj._p7.to_int() == 23);
}

SECTION("Read Only")
{
property_member_obj_test obj;
type prop_type = type::get(obj);

property prop = prop_type.get_property("p8");
REQUIRE(prop.is_valid() == true);

variant var = prop.get_value(obj);
CHECK(obj._p8 == 23);
}
}

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

0 comments on commit 739411e

Please # to comment.