Browse Source

Data struct members now support getter functions. Make Struct members use separate variable definitions.

Co-authored-by: Omegapl <[email protected]>
Michael Ragazzon 4 years ago
parent
commit
28f369530a
3 changed files with 235 additions and 79 deletions
  1. 69 26
      Include/RmlUi/Core/DataTypeRegister.h
  2. 16 0
      Include/RmlUi/Core/DataTypes.h
  3. 150 53
      Include/RmlUi/Core/DataVariable.h

+ 69 - 26
Include/RmlUi/Core/DataTypeRegister.h

@@ -53,11 +53,24 @@ template<typename Object>
 class StructHandle {
 public:
 	StructHandle(DataTypeRegister* type_register, StructDefinition* struct_definition) : type_register(type_register), struct_definition(struct_definition) {}
-	
+
+	// Register a member object. Any data type can be used.
 	template <typename MemberType>
 	StructHandle<Object>& RegisterMember(const String& name, MemberType Object::* member_ptr);
 
-	StructHandle<Object>& RegisterMemberFunc(const String& name, MemberGetFunc<Object> get_func, MemberSetFunc<Object> set_func = nullptr);
+	// Register a member using a getter function. Must return value by reference or by raw pointer. Any data type can be used.
+    template<typename ReturnType>
+    StructHandle<Object>& RegisterMember(const String& name, ReturnType(Object::* member_get_func_ptr)());
+
+	// Register a member using a getter function and optionally a setter function. Only scalar data types can be used.
+	// Can get and set by value or by reference.
+	/// @example
+	///     RegisterMemberScalar("color", &Invader::GetColor, &Invader::SetColor);
+	///       where functions can be declared as 
+	///     MyColorType Invader::GetColor();
+	///     void Invader::SetColor(MyColorType color);
+	template<typename ReturnType = std::nullptr_t, typename AssignType = std::nullptr_t>
+	StructHandle<Object>& RegisterMemberScalar(const String& name, ReturnType(Object::* member_get_func_ptr)(), void(Object::* member_set_func_ptr)(AssignType) = nullptr);
 
 	explicit operator bool() const {
 		return type_register && struct_definition;
@@ -99,7 +112,7 @@ public:
 		bool inserted = type_register.emplace(id, std::move(struct_definition)).second;
 		if (!inserted)
 		{
-			RMLUI_LOG_TYPE_ERROR(T, "Type already declared");
+			RMLUI_LOG_TYPE_ERROR(T, "Struct type already declared");
 			return StructHandle<T>(nullptr, nullptr);
 		}
 		
@@ -147,21 +160,6 @@ public:
 		return true;
 	}
 
-	template<typename T>
-	VariableDefinition* RegisterMemberFunc(MemberGetFunc<T> get_func, MemberSetFunc<T> set_func)
-	{
-		FamilyId id = Family<MemberGetFunc<T>>::Id();
-
-		auto result = type_register.emplace(id, nullptr);
-		auto& it = result.first;
-		bool inserted = result.second;
-
-		if (inserted)
-			it->second = MakeUnique<MemberFuncDefinition<T>>(get_func, set_func);
-
-		return it->second.get();
-	}
-
 	template<typename T>
 	VariableDefinition* GetDefinition()
 	{
@@ -213,10 +211,10 @@ private:
 	VariableDefinition* GetDefinitionDetail()
 	{
 		static_assert(PointerTraits<T>::is_pointer::value, "Not a valid pointer type.");
-		static_assert(!PointerTraits<PointerTraits<T>::element_type>::is_pointer::value, "Recursive pointer type (pointer to pointer) detected.");
+		static_assert(!PointerTraits<typename PointerTraits<T>::element_type>::is_pointer::value, "Recursive pointer type (pointer to pointer) detected.");
 
 		// Get the underlying definition.
-		VariableDefinition* underlying_definition = GetDefinitionDetail<typename std::remove_cv<PointerTraits<T>::element_type>::type>();
+		VariableDefinition* underlying_definition = GetDefinitionDetail<typename std::remove_cv<typename PointerTraits<T>::element_type>::type>();
 		if (!underlying_definition)
 		{
 			RMLUI_LOG_TYPE_ERROR(T, "Underlying type of pointer not registered.");
@@ -244,15 +242,60 @@ private:
 
 template<typename Object>
 template<typename MemberType>
-inline StructHandle<Object>& StructHandle<Object>::RegisterMember(const String& name, MemberType Object::* member_ptr) {
-	VariableDefinition* member_type = type_register->GetDefinition<MemberType>();
-	struct_definition->AddMember(name, MakeUnique<StructMemberObject<Object, MemberType>>(member_type, member_ptr));
+inline StructHandle<Object>& StructHandle<Object>::RegisterMember(const String& name, MemberType Object::* member_ptr)
+{
+	if (VariableDefinition* member_definition = type_register->GetDefinition<MemberType>())
+	{
+		struct_definition->AddMember(
+			name,
+			MakeUnique<MemberObjectPointerDefinition<Object, MemberType>>(member_definition, 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));
+template<typename ReturnType>
+inline StructHandle<Object>& StructHandle<Object>::RegisterMember(const String& name, ReturnType(Object::*member_get_func_ptr)())
+{
+	using BasicReturnType = typename std::remove_pointer<typename std::remove_reference<ReturnType>::type>::type;
+	static_assert(!std::is_same<ReturnType, BasicReturnType>::value, "Struct member getter function must return value by reference or raw pointer.");
+
+	VariableDefinition* underlying_definition = type_register->GetDefinition<BasicReturnType>();
+	struct_definition->AddMember(
+		name,
+		MakeUnique<MemberFunctionPointerDefinition<Object, ReturnType, BasicReturnType>>(underlying_definition, member_get_func_ptr)
+	);
+	return *this;
+}
+
+template<typename Object>
+template<typename ReturnType, typename AssignType>
+inline StructHandle<Object>& StructHandle<Object>::RegisterMemberScalar(const String& name, ReturnType(Object::* member_get_func_ptr)(), void(Object::* member_set_func_ptr)(AssignType))
+{
+	using BasicReturnType = typename std::remove_cv<typename std::remove_reference<ReturnType>::type>::type;
+	using BasicAssignType = typename std::remove_cv<typename std::remove_reference<AssignType>::type>::type;
+	using UnderlyingType = typename std::conditional<std::is_null_pointer<BasicReturnType>::value, BasicAssignType, BasicReturnType>::type;
+
+	static_assert(std::is_null_pointer<ReturnType>::value || std::is_null_pointer<AssignType>::value || std::is_same<BasicReturnType, BasicAssignType>::value, "Provided getter and setter functions must get and set the same type.");
+	static_assert(std::is_copy_assignable<UnderlyingType>::value, "Struct member getter and setter functions must return/assign a type that is copy assignable.");
+	static_assert(std::is_default_constructible<UnderlyingType>::value, "Struct member getter and setter functions must return/assign a type that is default constructible.");
+
+	VariableDefinition* underlying_definition = type_register->GetDefinition<UnderlyingType>();
+	if (!underlying_definition)
+		return *this;
+
+	DataVariableType type = underlying_definition->Type();
+	if (!(type == DataVariableType::Scalar || type == DataVariableType::Function))
+	{
+		RMLUI_LOG_TYPE_ERROR(UnderlyingType, "A getter/setter member function must return and assign a scalar data variable type.");
+		return *this;
+	}
+
+	struct_definition->AddMember(
+		name,
+		MakeUnique<MemberScalarFunctionPointerDefinition<Object, ReturnType, AssignType, UnderlyingType>>(underlying_definition, member_get_func_ptr, member_set_func_ptr)
+	);
 	return *this;
 }
 

+ 16 - 0
Include/RmlUi/Core/DataTypes.h

@@ -31,6 +31,7 @@
 
 #include "Header.h"
 #include "Types.h"
+#include <type_traits>
 
 namespace Rml {
 
@@ -51,6 +52,9 @@ template<typename T> using MemberSetFunc = void(T::*)(const Variant&);
 template<typename T> using DataTypeGetFunc = void(*)(const T*, Variant&);
 template<typename T> using DataTypeSetFunc = void(*)(T*, const Variant&);
 
+template<typename Object, typename ReturnType> using MemberGetterFunc = ReturnType(Object::*)();
+template<typename Object, typename AssignType> using MemberSetterFunc = void(Object::*)(AssignType);
+
 using DirtyVariables = SmallUnorderedSet<String>;
 
 struct DataAddressEntry {
@@ -65,21 +69,33 @@ template<class T>
 struct PointerTraits {
 	using is_pointer = std::false_type;
 	using element_type = T;
+	static void* Dereference(void* ptr) {
+		return ptr;
+	}
 };
 template<class T>
 struct PointerTraits<T*> {
 	using is_pointer = std::true_type;
 	using element_type = T;
+	static void* Dereference(void* ptr) {
+		return (void*)*static_cast<T**>(ptr);
+	}
 };
 template<class T>
 struct PointerTraits<UniquePtr<T>> {
 	using is_pointer = std::true_type;
 	using element_type = T;
+	static void* Dereference(void* ptr) {
+		return (void*)static_cast<UniquePtr<T>*>(ptr)->get();
+	}
 };
 template<class T>
 struct PointerTraits<SharedPtr<T>> {
 	using is_pointer = std::true_type;
 	using element_type = T;
+	static void* Dereference(void* ptr) {
+		return (void*)static_cast<SharedPtr<T>*>(ptr)->get();
+	}
 };
 
 

+ 150 - 53
Include/RmlUi/Core/DataVariable.h

@@ -195,6 +195,7 @@ private:
 	VariableDefinition* underlying_definition;
 };
 
+
 template<typename T>
 class PointerDefinition final : public VariableDefinition {
 public:
@@ -232,48 +233,13 @@ private:
 
 	static void* DereferencePointer(void* ptr)
 	{
-		return (void*)(&(*(*static_cast<T*>(ptr))));
+		return PointerTraits<T>::Dereference(ptr);
 	}
 
 	VariableDefinition* underlying_definition;
 };
 
 
-class StructMember {
-public:
-	StructMember(VariableDefinition* definition) : definition(definition) {}
-	virtual ~StructMember() = default;
-
-	VariableDefinition* GetDefinition() const { return definition; }
-
-	virtual void* GetPointer(void* base_ptr) = 0;
-
-private:
-	VariableDefinition* definition;
-};
-
-template <typename Object, typename MemberType>
-class StructMemberObject final : public StructMember {
-public:
-	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);
-	}
-
-private:
-	MemberType Object::* member_ptr;
-};
-
-class StructMemberFunc final : public StructMember {
-public:
-	StructMemberFunc(VariableDefinition* definition) : StructMember(definition) {}
-	void* GetPointer(void* base_ptr) override {
-		return base_ptr;
-	}
-};
-
-
 class StructDefinition final : public VariableDefinition {
 public:
 	StructDefinition() : VariableDefinition(DataVariableType::Struct)
@@ -295,13 +261,12 @@ public:
 			return DataVariable();
 		}
 
-		void* next_ptr = it->second->GetPointer(ptr);
-		VariableDefinition* next_definition = it->second->GetDefinition();
+		VariableDefinition* next_definition = it->second.get();
 
-		return DataVariable(next_definition, next_ptr);
+		return DataVariable(next_definition, ptr);
 	}
 
-	void AddMember(const String& name, UniquePtr<StructMember> member)
+	void AddMember(const String& name, UniquePtr<VariableDefinition> member)
 	{
 		RMLUI_ASSERT(member);
 		bool inserted = members.emplace(name, std::move(member)).second;
@@ -310,33 +275,165 @@ public:
 	}
 
 private:
-	SmallUnorderedMap<String, UniquePtr<StructMember>> members;
+	SmallUnorderedMap<String, UniquePtr<VariableDefinition>> members;
 };
 
 
-template<typename T>
-class MemberFuncDefinition final : public VariableDefinition {
+template <typename Object, typename MemberType>
+class MemberAccessor {
+protected:
+	MemberAccessor(MemberType Object::* member_ptr) : member_ptr(member_ptr) {}
+
+	void* ResolvePointer(void* base_ptr) const {
+		return &(static_cast<Object*>(base_ptr)->*member_ptr);
+	}
+
+private:
+	MemberType Object::* member_ptr;
+};
+
+template <typename Object, typename MemberType>
+class MemberObjectPointerDefinition final : public VariableDefinition, public MemberAccessor<Object, MemberType> {
 public:
-	MemberFuncDefinition(MemberGetFunc<T> get, MemberSetFunc<T> set) : VariableDefinition(DataVariableType::MemberFunction), get(get), set(set) {}
+	MemberObjectPointerDefinition(VariableDefinition* underlying_definition, MemberType Object::* member_ptr)
+		: VariableDefinition(underlying_definition->Type()), MemberAccessor<Object, MemberType>(member_ptr), underlying_definition(underlying_definition) {}
 
 	bool Get(void* ptr, Variant& variant) override
 	{
-		if (!get)
-			return false;
-		(static_cast<T*>(ptr)->*get)(variant);
-		return true;
+		return underlying_definition->Get(ResolvePointer(ptr), variant);
 	}
 	bool Set(void* ptr, const Variant& variant) override
 	{
-		if (!set)
+		return underlying_definition->Set(ResolvePointer(ptr), variant);
+	}
+	int Size(void* ptr) override
+	{
+		return underlying_definition->Size(ResolvePointer(ptr));
+	}
+	DataVariable Child(void* ptr, const DataAddressEntry& address) override
+	{
+		return underlying_definition->Child(ResolvePointer(ptr), address);
+	}
+
+private:
+	using MemberAccessor<Object, MemberType>::ResolvePointer;
+
+	VariableDefinition* underlying_definition;
+};
+
+
+template <typename Object, typename ReturnType, typename BasicReturnType>
+class MemberFunctionPointerDefinition final : public VariableDefinition {
+public:
+	using MemberFunc = ReturnType(Object::*)();
+
+	MemberFunctionPointerDefinition(VariableDefinition* underlying_definition, MemberFunc member_ptr)
+		: VariableDefinition(underlying_definition->Type()), underlying_definition(underlying_definition), member_ptr(member_ptr) 
+	{
+		// static assert return type is reference or pointer
+	}
+
+	bool Get(void* ptr, Variant& variant) override
+	{
+		return underlying_definition->Get(GetPointer(ptr), variant);
+	}
+	bool Set(void* ptr, const Variant& variant) override
+	{
+		return underlying_definition->Set(GetPointer(ptr), variant);
+	}
+	int Size(void* ptr) override
+	{
+		return underlying_definition->Size(GetPointer(ptr));
+	}
+	DataVariable Child(void* ptr, const DataAddressEntry& address) override
+	{
+		return underlying_definition->Child(GetPointer(ptr), address);
+	}
+
+private:
+	void* GetPointer(void* base_ptr) {
+		return (void*)Extract((static_cast<Object*>(base_ptr)->*member_ptr)());
+	}
+
+	// Pointer return types
+	BasicReturnType* Extract(BasicReturnType* value) {
+		return value;
+	}
+	// Reference return types
+	BasicReturnType* Extract(BasicReturnType& value) {
+		return &value;
+	}
+
+	VariableDefinition* underlying_definition;
+	MemberFunc member_ptr;
+};
+
+
+
+template <typename Object, typename ReturnType, typename AssignType, typename UnderlyingType>
+class MemberScalarFunctionPointerDefinition final : public VariableDefinition {
+public:
+	using MemberFunc = ReturnType(Object::*)();
+
+	MemberScalarFunctionPointerDefinition(VariableDefinition* underlying_definition, MemberGetterFunc<Object, ReturnType> get_func, MemberSetterFunc<Object, AssignType> set_func)
+		: VariableDefinition(underlying_definition->Type()), underlying_definition(underlying_definition), get_func(get_func), set_func(set_func)
+	{}
+
+	bool Get(void* ptr, Variant& variant) override
+	{
+		return GetDetail(ptr, variant);
+	}
+	bool Set(void* ptr, const Variant& variant) override
+	{
+		return SetDetail(ptr, variant);
+	}
+
+private:
+
+	template<typename R = ReturnType, typename std::enable_if<std::is_null_pointer<R>::value, int>::type = 0>
+	bool GetDetail(void* /*ptr*/, Variant& /*variant*/)
+	{
+		return false;
+	}
+
+	template<typename R = ReturnType, typename std::enable_if<!std::is_null_pointer<R>::value, int>::type = 0>
+	bool GetDetail(void* ptr, Variant& variant)
+	{
+		if (!get_func)
 			return false;
-		(static_cast<T*>(ptr)->*set)(variant);
+
+		// TODO: Does this work for pointers?
+		auto&& value = (static_cast<Object*>(ptr)->*get_func)();
+		bool result = underlying_definition->Get((void*)&value, variant);
+		return result;
+	}
+
+	template<typename A = AssignType, typename std::enable_if<std::is_null_pointer<A>::value, int>::type = 0>
+	bool SetDetail(void* /*ptr*/, const Variant& /*variant*/)
+	{
+		return false;
+	}
+
+	template<typename A = AssignType, typename std::enable_if<!std::is_null_pointer<A>::value, int>::type = 0>
+	bool SetDetail(void* ptr, const Variant& variant)
+	{
+		if (!set_func)
+			return false;
+
+		UnderlyingType result;
+		if (!underlying_definition->Set((void*)&result, variant))
+			return false;
+
+		(static_cast<Object*>(ptr)->*set_func)(result);
+
 		return true;
 	}
-private:
-	MemberGetFunc<T> get;
-	MemberSetFunc<T> set;
+
+	VariableDefinition* underlying_definition;
+	MemberGetterFunc<Object, ReturnType> get_func;
+	MemberSetterFunc<Object, AssignType> set_func;
 };
 
+
 } // namespace Rml
 #endif