Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added support of (smart) pointers as members and added support for "T& getter()" getters #166

Merged
merged 7 commits into from
Jan 19, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 17 additions & 0 deletions Include/RmlUi/Core/DataModelHandle.h
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,23 @@ class RMLUICORE_API DataModelConstructor {
return type_register->RegisterArray<Container>();
}

// Register a pointer type.
// @note The type applies to every data model associated with the current Context.
// @note If 'PointerType' represents a non-scalar type, that type must already have been registered with the appropriate 'Register...()' functions.
template<typename PointerType>
bool RegisterPointer() {
return type_register->RegisterPointer<PointerType>();
}

// Register an array type.
// @note The type applies to every data model associated with the current Context.
// @note If 'PointerType::element_type' represents a non-scalar type, that type must already have been registered with the appropriate 'Register...()' functions.
// @note PointerType requires the following functions to be implemented: PointerType::element_type* get(). This is satisfied by several "pointer containers" such as std::shared_ptr.
template<typename PointerType>
bool RegisterComplexPointer() {
return type_register->RegisterComplexPointer<PointerType>();
}

// Register a transform function.
// A transform function modifies a variant with optional arguments. It can be called in data expressions using the pipe '|' operator.
// @note The transform function applies to every data model associated with the current Context.
Expand Down
82 changes: 72 additions & 10 deletions Include/RmlUi/Core/DataTypeRegister.h
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,9 @@ class StructHandle {
template <typename MemberType>
StructHandle<Object>& RegisterMember(const String& name, MemberType Object::* member_ptr);

template<typename GetterType>
inline StructHandle<Object>& RegisterMemberGetter(const String& name, GetterType member_ptr);

StructHandle<Object>& RegisterMemberFunc(const String& name, MemberGetFunc<Object> get_func, MemberSetFunc<Object> set_func = nullptr);

explicit operator bool() const {
Expand Down Expand Up @@ -102,6 +105,43 @@ class RMLUICORE_API DataTypeRegister : NonCopyMoveable {
return StructHandle<T>(this, struct_variable_raw);
}

template<typename PointerType, typename InnerType, typename Definition>
bool RegisterPointer()
{
VariableDefinition* value_variable = GetOrAddScalar<InnerType>();
RMLUI_ASSERTMSG(value_variable, "Underlying type of the pointer has not been registered.");
if (!value_variable)
return false;

FamilyId container_id = Family<PointerType>::Id();

auto ptr_variable = MakeUnique<Definition>(value_variable);

bool inserted = type_register.emplace(container_id, std::move(ptr_variable)).second;
if (!inserted)
{
RMLUI_ERRORMSG("Pointer type already declared.");
return false;
}

return true;
}

template<typename PointerType>
bool RegisterPointer()
{
using ValueType = typename std::remove_pointer<PointerType>::type;
static_assert(std::is_pointer<PointerType>::value, "Provided type is not a pointer!");
return RegisterPointer<PointerType, ValueType, PointerDefinition<PointerType>>();
}

template<typename PointerType>
bool RegisterComplexPointer()
{
using ValueType = typename PointerType::element_type;
return RegisterPointer<PointerType, ValueType, ComplexPointerDefinition<PointerType>>();
}

template<typename Container>
bool RegisterArray()
{
Expand Down Expand Up @@ -140,8 +180,8 @@ class RMLUICORE_API DataTypeRegister : NonCopyMoveable {
return it->second.get();
}

template<typename T, typename std::enable_if<is_valid_data_scalar<T>::value, int>::type = 0>
VariableDefinition* GetOrAddScalar()
template<typename T, typename Definition, typename std::enable_if<is_valid_data_scalar<T>::value, int>::type = 0>
VariableDefinition* GetOrAddScalarGeneric()
{
FamilyId id = Family<T>::Id();

Expand All @@ -150,17 +190,29 @@ class RMLUICORE_API DataTypeRegister : NonCopyMoveable {
UniquePtr<VariableDefinition>& definition = result.first->second;

if (inserted)
definition = MakeUnique<ScalarDefinition<T>>();
definition = MakeUnique<Definition>();

return definition.get();
}

template<typename T, typename std::enable_if<!is_valid_data_scalar<T>::value, int>::type = 0>
VariableDefinition* GetOrAddScalar()
template<typename T, typename Definition, typename std::enable_if<!is_valid_data_scalar<T>::value, int>::type = 0>
VariableDefinition* GetOrAddScalarGeneric()
{
return Get<T>();
}


template<typename T>
VariableDefinition* GetOrAddScalar()
{
return GetOrAddScalarGeneric<T, ScalarDefinition<T>>();
}

template<typename T>
VariableDefinition* GetOrAddScalarGetter()
{
return GetOrAddScalarGeneric<T, ScalarGetterDefinition<T>>();
}

template<typename T>
VariableDefinition* Get()
{
Expand All @@ -187,18 +239,28 @@ class RMLUICORE_API DataTypeRegister : NonCopyMoveable {
};

template<typename Object>
template<typename MemberType>
template <typename MemberType>
inline StructHandle<Object>& StructHandle<Object>::RegisterMember(const String& name, MemberType Object::* member_ptr) {
VariableDefinition* member_type = type_register->GetOrAddScalar<MemberType>();
struct_definition->AddMember(name, MakeUnique<StructMemberObject<Object, MemberType>>(member_type, member_ptr));
return *this;
VariableDefinition* member_type = type_register->GetOrAddScalar<MemberType>();
struct_definition->AddMember(name, MakeUnique<StructMemberObject<Object, MemberType>>(member_type, member_ptr));
return *this;
}

template<typename Object>
inline StructHandle<Object>& StructHandle<Object>::RegisterMemberFunc(const String& name, MemberGetFunc<Object> get_func, MemberSetFunc<Object> set_func) {
VariableDefinition* definition = type_register->RegisterMemberFunc<Object>(get_func, set_func);
struct_definition->AddMember(name, MakeUnique<StructMemberFunc>(definition));
return *this;
}

template<typename Object>
template<typename GetterType>
inline StructHandle<Object>& StructHandle<Object>::RegisterMemberGetter(const String& name, GetterType member_ptr) {
using ReturnType = typename std::result_of<GetterType(Object)>::type;
VariableDefinition* member_type = type_register->GetOrAddScalarGetter<ReturnType>();
struct_definition->AddMember(name, MakeUnique<StructMemberObjectGetter<Object, GetterType>>(member_type, member_ptr));
return *this;
}

} // namespace Rml
#endif
154 changes: 152 additions & 2 deletions Include/RmlUi/Core/DataVariable.h
Original file line number Diff line number Diff line change
Expand Up @@ -47,13 +47,46 @@ enum class DataVariableType { Scalar, Array, Struct, Function, MemberFunction };
* Together they can be used to get and set variables between the user side and data model side.
*/

template <typename Object, typename GetterType, typename ReturnType>
struct Extractor {
static void* ExtractPointer(void* base_ptr, GetterType member_ptr)
{
auto tmp = static_cast<Object*>(base_ptr);
auto &res = (tmp->*member_ptr)();
auto v = (const void*)&(res);
return const_cast<void*>(v);
}
static void* ConvertPointer(Object& base_obj)
{
auto v = (const void*)&(base_obj);
return const_cast<void*>(v);
}
};

template <typename Object, typename GetterType, typename ReturnType>
struct Extractor<Object, GetterType, ReturnType*> {
static void* ExtractPointer(void* base_ptr, GetterType member_ptr)
{
auto tmp = static_cast<Object*>(base_ptr);
auto res = (tmp->*member_ptr)();
auto ptr = (const void*)(res);
return const_cast<void*>(ptr);
}
static void* ConvertPointer(Object& base_obj)
{
auto v = (const void*)(base_obj);
return const_cast<void*>(v);
}
};

class RMLUICORE_API DataVariable {
public:
DataVariable() {}
DataVariable(VariableDefinition* definition, void* ptr) : definition(definition), ptr(ptr) {}

explicit operator bool() const { return definition; }

void Access(DataVariable& out);
bool Get(Variant& variant);
bool Set(const Variant& variant);
int Size();
Expand All @@ -77,6 +110,7 @@ class RMLUICORE_API VariableDefinition {
virtual ~VariableDefinition() = default;
DataVariableType Type() const { return type; }

virtual void Access(void* ptr, VariableDefinition*& output_def, void*& output_ptr);
virtual bool Get(void* ptr, Variant& variant);
virtual bool Set(void* ptr, const Variant& variant);

Expand Down Expand Up @@ -110,6 +144,91 @@ class ScalarDefinition final : public VariableDefinition {
}
};

template<typename T>
class PointerDefinition final : public VariableDefinition {
public:
PointerDefinition(VariableDefinition* underlying_definition) : VariableDefinition(DataVariableType::Scalar), underlying_definition(underlying_definition){}

void Access(void* ptr, VariableDefinition*& output_def, void*& output_ptr) override
{
output_def = underlying_definition;
output_ptr = ptr;
}
bool Get(void* ptr, Variant& variant) override
{
return underlying_definition->Get(ptr, variant);
}

bool Set(void* ptr, const Variant& variant) override
{
return underlying_definition->Set(ptr, variant);
}

DataVariable Child(void* ptr, const DataAddressEntry& address) override
{
return underlying_definition->Child(ptr, address);
}

protected:
VariableDefinition* underlying_definition;
};

template<typename T>
class ComplexPointerDefinition final : public VariableDefinition {
public:
ComplexPointerDefinition(VariableDefinition* underlying_definition) : VariableDefinition(DataVariableType::Scalar), underlying_definition(underlying_definition){}
using elty = typename T::element_type;
void Access(void* ptr, VariableDefinition*& output_def, void*& output_ptr) override
{
output_def = underlying_definition;
output_ptr = getPtr(ptr);
}
bool Get(void* ptr, Variant& variant) override
{
ptr = getPtr(ptr);
return underlying_definition->Get(ptr, variant);
}

bool Set(void* ptr, const Variant& variant) override
{
ptr = getPtr(ptr);
return underlying_definition->Set(ptr, variant);
}

DataVariable Child(void* ptr, const DataAddressEntry& address) override
{
ptr = getPtr(ptr);
return underlying_definition->Child(ptr, address);
}

private:
void* getPtr(void* ptr)
{
T* shptr = static_cast<T*>(ptr);
elty* tmp = shptr->get();
return (void*) tmp;
}
protected:
VariableDefinition* underlying_definition;
};

template<typename T>
class ScalarGetterDefinition final : public VariableDefinition {
public:
ScalarGetterDefinition() : VariableDefinition(DataVariableType::Scalar) {}

bool Get(void* ptr, Variant& variant) override
{
variant = *static_cast<T*>(ptr);
return true;
}
bool Set(void* RMLUI_UNUSED_PARAMETER(ptr), const Variant& RMLUI_UNUSED_PARAMETER(variant)) override
{
Log::Message(Log::LT_WARNING, "Only getter exposed for this variable.");
return false;
}
};


class FuncDefinition final : public VariableDefinition {
public:
Expand Down Expand Up @@ -145,6 +264,7 @@ class ArrayDefinition final : public VariableDefinition {
return int(static_cast<Container*>(ptr)->size());
}

using value_type = typename Container::value_type;
protected:
DataVariable Child(void* void_ptr, const DataAddressEntry& address) override
{
Expand All @@ -164,7 +284,7 @@ class ArrayDefinition final : public VariableDefinition {
auto it = ptr->begin();
std::advance(it, index);

void* next_ptr = &(*it);
void* next_ptr = Extractor<value_type, void*, value_type>::ConvertPointer(*it);
return DataVariable(underlying_definition, next_ptr);
}

Expand Down Expand Up @@ -192,13 +312,43 @@ class StructMemberObject final : public StructMember {
StructMemberObject(VariableDefinition* definition, MemberType Object::* member_ptr) : StructMember(definition), member_ptr(member_ptr) {}

void* GetPointer(void* base_ptr) override {
return &(static_cast<Object*>(base_ptr)->*member_ptr);
auto tmp = static_cast<Object*>(base_ptr);
auto& res = tmp->*member_ptr;
return &(res);
}

private:
MemberType Object::* member_ptr;
};

template <typename Object, typename MemberType>
class StructMemberObject<Object, MemberType*> final : public StructMember {
public:
StructMemberObject(VariableDefinition* definition, MemberType* Object::* member_ptr) : StructMember(definition), member_ptr(member_ptr) {}

void* GetPointer(void* base_ptr) override {
auto tmp = static_cast<Object*>(base_ptr);
auto res = tmp->*member_ptr;
return (void*) res;
}

private:
MemberType* Object::* member_ptr;
};

template <typename Object, typename GetterType>
class StructMemberObjectGetter final : public StructMember {
public:
StructMemberObjectGetter(VariableDefinition* definition, GetterType member_ptr) : StructMember(definition), member_ptr(member_ptr) {}

void* GetPointer(void* base_ptr) override {
return Extractor<Object, GetterType, typename std::result_of<GetterType(Object)>::type>::ExtractPointer(base_ptr, member_ptr);
}

private:
GetterType member_ptr;
};

class StructMemberFunc final : public StructMember {
public:
StructMemberFunc(VariableDefinition* definition) : StructMember(definition) {}
Expand Down
15 changes: 14 additions & 1 deletion Include/RmlUi/Core/Traits.h
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,20 @@ class Family : FamilyBase {
return GetId< typename std::remove_cv< typename std::remove_reference< T >::type >::type >();
}
};


template< class T > struct remove_smart_pointer {typedef T type;};
template< class T > struct remove_smart_pointer<SharedPtr<T>> {typedef T type;};
template< class T > struct remove_smart_pointer<SharedPtr<const T>> {typedef T type;};
template< class T > struct remove_smart_pointer<SharedPtr<T>&> {typedef T type;};
template< class T > struct remove_smart_pointer<SharedPtr<const T>&> {typedef T type;};

template<typename MemberType>
struct remove_raw_smart_pointer
{
using _type1 = typename std::remove_const<MemberType>::type;
using _type2 = typename Rml::remove_smart_pointer<_type1>::type;
using type = typename std::remove_pointer<_type2>::type;
};
} // namespace Rml


Expand Down
1 change: 1 addition & 0 deletions Source/Core/DataModel.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -292,6 +292,7 @@ DataVariable DataModel::GetVariable(const DataAddress& address) const
for (int i = 1; i < (int)address.size() && variable; i++)
{
variable = variable.Child(address[i]);
variable.Access(variable);
if (!variable)
return DataVariable();
}
Expand Down
Loading