summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--CMakeLists.txt1
-rw-r--r--src/core/common/Property.cpp22
-rw-r--r--src/core/common/Property.hpp28
-rw-r--r--src/core/common/Rtti.cpp70
-rw-r--r--src/core/common/Rtti.hpp196
-rw-r--r--src/core/common/TypedRttiBuilder.cpp24
-rw-r--r--src/core/common/TypedRttiBuilder.hpp171
-rw-r--r--test/core/common/PropertyTest.cpp10
-rw-r--r--test/core/common/RttiTest.cpp164
-rw-r--r--test/core/managed/ManagedTest.cpp9
10 files changed, 584 insertions, 111 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 90539bc..95934ec 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -120,6 +120,7 @@ ADD_LIBRARY(ousia_core
src/core/common/Property
src/core/common/Rtti
src/core/common/Terminal
+ src/core/common/TypedRttiBuilder
src/core/common/Utils
src/core/common/Variant
src/core/common/VariantConverter
diff --git a/src/core/common/Property.cpp b/src/core/common/Property.cpp
index ea40182..8248058 100644
--- a/src/core/common/Property.cpp
+++ b/src/core/common/Property.cpp
@@ -41,8 +41,10 @@ void GetterFunction::validateArguments(Variant::arrayType &args) const
void GetterFunction::validateResult(Variant &res) const
{
ExceptionLogger logger;
- VariantConverter::convert(res, propertyType->type, propertyType->innerType,
- logger);
+ if (propertyType != nullptr) {
+ VariantConverter::convert(res, propertyType->type,
+ propertyType->innerType, logger);
+ }
}
Variant GetterFunction::get(void *obj)
@@ -66,8 +68,10 @@ void SetterFunction::validateArguments(Variant::arrayType &args) const
// Convert the one argument to the requested type, throw an exception if
// this fails.
ExceptionLogger logger;
- VariantConverter::convert(args[0], propertyType->type,
- propertyType->innerType, logger);
+ if (propertyType != nullptr) {
+ VariantConverter::convert(args[0], propertyType->type,
+ propertyType->innerType, logger);
+ }
}
void SetterFunction::set(const Variant &value, void *obj)
@@ -78,9 +82,9 @@ void SetterFunction::set(const Variant &value, void *obj)
/* Class PropertyDescriptor */
PropertyDescriptor::PropertyDescriptor(const PropertyType &type,
- std::unique_ptr<GetterFunction> getter,
- std::unique_ptr<SetterFunction> setter)
- : type(type), getter(std::move(getter)), setter(std::move(setter))
+ std::shared_ptr<GetterFunction> getter,
+ std::shared_ptr<SetterFunction> setter)
+ : type(std::make_shared<PropertyType>(type)), getter(getter), setter(setter)
{
if (!this->getter->isValid()) {
throw PropertyException(
@@ -89,8 +93,8 @@ PropertyDescriptor::PropertyDescriptor(const PropertyType &type,
}
// Assign the property type reference to the getter and setter
- this->getter->propertyType = &this->type;
- this->setter->propertyType = &this->type;
+ this->getter->propertyType = this->type;
+ this->setter->propertyType = this->type;
}
}
diff --git a/src/core/common/Property.hpp b/src/core/common/Property.hpp
index 5957e40..72dff71 100644
--- a/src/core/common/Property.hpp
+++ b/src/core/common/Property.hpp
@@ -129,13 +129,13 @@ protected:
* @param valid specifies whether a callback function was given or not.
*/
PropertyFunction(bool valid)
- : valid(valid), propertyType(&PropertyType::None){};
+ : valid(valid), propertyType(nullptr){};
public:
/**
* Returns the type associated with the property function.
*/
- PropertyType const *propertyType;
+ std::shared_ptr<PropertyType> propertyType;
/**
* Returns true if a callback function was given, false otherwise.
@@ -354,18 +354,18 @@ private:
* Description of the type of the property, consisting of an inner and an
* outer type.
*/
- const PropertyType type;
+ std::shared_ptr<PropertyType> type;
/**
* Object used to read the value of the property.
*/
- std::unique_ptr<GetterFunction> getter;
+ std::shared_ptr<GetterFunction> getter;
/**
* Object used to write values of the property. The setter may be invalid
* in which case the property is read only.
*/
- std::unique_ptr<SetterFunction> setter;
+ std::shared_ptr<SetterFunction> setter;
protected:
/**
@@ -379,8 +379,8 @@ protected:
* setter function may be invalid, in which case the property is readonly.
*/
PropertyDescriptor(const PropertyType &type,
- std::unique_ptr<GetterFunction> getter,
- std::unique_ptr<SetterFunction> setter);
+ std::shared_ptr<GetterFunction> getter,
+ std::shared_ptr<SetterFunction> setter);
public:
/**
@@ -396,7 +396,7 @@ public:
*
* @return the PropertyType instance describing the type of this property.
*/
- const PropertyType &getType() const { return type; }
+ const PropertyType &getType() const { return *type; }
/**
* Returns the value of the property for the given object.
@@ -438,8 +438,8 @@ public:
Property(const Getter<T> &getter, const Setter<T> &setter = Setter<T>{})
: PropertyDescriptor(
PropertyType{},
- std::unique_ptr<GetterFunction>{new Getter<T>{getter}},
- std::unique_ptr<SetterFunction>{new Setter<T>{setter}})
+ std::make_shared<Getter<T>>(getter),
+ std::make_shared<Setter<T>>(setter))
{
}
@@ -458,8 +458,8 @@ public:
const Setter<T> &setter = Setter<T>{})
: PropertyDescriptor(
PropertyType{type},
- std::unique_ptr<GetterFunction>{new Getter<T>{getter}},
- std::unique_ptr<SetterFunction>{new Setter<T>{setter}})
+ std::make_shared<Getter<T>>(getter),
+ std::make_shared<Setter<T>>(setter))
{
}
@@ -481,8 +481,8 @@ public:
const Getter<T> &getter, const Setter<T> &setter = Setter<T>{})
: PropertyDescriptor(
PropertyType{type, innerType},
- std::unique_ptr<GetterFunction>{new Getter<T>{getter}},
- std::unique_ptr<SetterFunction>{new Setter<T>{setter}})
+ std::make_shared<Getter<T>>(getter),
+ std::make_shared<Setter<T>>(setter))
{
}
diff --git a/src/core/common/Rtti.cpp b/src/core/common/Rtti.cpp
index a8343ef..239f2b4 100644
--- a/src/core/common/Rtti.cpp
+++ b/src/core/common/Rtti.cpp
@@ -16,6 +16,7 @@
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
+#include "Exceptions.hpp"
#include "Rtti.hpp"
namespace ousia {
@@ -44,6 +45,30 @@ const RttiType &RttiStore::lookup(const std::type_info &native)
}
}
+/* Class RttiBuilder */
+
+RttiBuilder &RttiBuilder::genericMethod(const std::string name,
+ std::shared_ptr<Function> function)
+{
+ if (!methods.emplace(name, function).second) {
+ throw OusiaException(std::string("Method with name \"") + name +
+ std::string("\" for type \"") + currentName +
+ std::string("\" already registered!"));
+ }
+ return *this;
+}
+
+RttiBuilder &RttiBuilder::genericProperty(
+ const std::string name, std::shared_ptr<PropertyDescriptor> property)
+{
+ if (!properties.emplace(name, property).second) {
+ throw OusiaException(std::string("Property with name \"") + name +
+ std::string("\" for type \"") + currentName +
+ std::string("\" already registered!"));
+ }
+ return *this;
+}
+
/* Class RttiType */
void RttiType::initialize() const
@@ -53,6 +78,15 @@ void RttiType::initialize() const
if (!initialized) {
initialized = true;
+ // Register the parent properties and methods
+ {
+ for (const RttiType *parent: parents) {
+ parent->initialize();
+ methods.insert(parent->methods.begin(), parent->methods.end());
+ properties.insert(parent->properties.begin(), parent->properties.end());
+ }
+ }
+
// Insert the parent types of the parent types and the composite types
// of the parents
{
@@ -64,7 +98,7 @@ void RttiType::initialize() const
for (const RttiType *parent : parents) {
parent->initialize();
compositeTypes.insert(parent->compositeTypes.begin(),
- parent->compositeTypes.end());
+ parent->compositeTypes.end());
}
parents.insert(this);
}
@@ -77,9 +111,9 @@ void RttiType::initialize() const
for (const RttiType *compositeType : origCompositeTypes) {
compositeType->initialize();
compositeTypes.insert(compositeType->compositeTypes.begin(),
- compositeType->compositeTypes.end());
+ compositeType->compositeTypes.end());
compositeTypes.insert(compositeType->parents.begin(),
- compositeType->parents.end());
+ compositeType->parents.end());
}
}
}
@@ -97,6 +131,36 @@ bool RttiType::composedOf(const RttiType &other) const
return compositeTypes.count(&other) > 0;
}
+const RttiMethodMap &RttiType::getMethods() const {
+ initialize();
+ return methods;
+}
+
+const RttiPropertyMap &RttiType::getProperties() const {
+ initialize();
+ return properties;
+}
+
+std::shared_ptr<Function> RttiType::getMethod(const std::string &name) const
+{
+ initialize();
+ auto it = methods.find(name);
+ if (it == methods.end()) {
+ return nullptr;
+ }
+ return it->second;
+}
+
+std::shared_ptr<PropertyDescriptor> RttiType::getProperty(const std::string &name) const
+{
+ initialize();
+ auto it = properties.find(name);
+ if (it == properties.end()) {
+ return nullptr;
+ }
+ return it->second;
+}
+
/* Constant initialization */
namespace RttiTypes {
diff --git a/src/core/common/Rtti.hpp b/src/core/common/Rtti.hpp
index 39a61d3..6449c75 100644
--- a/src/core/common/Rtti.hpp
+++ b/src/core/common/Rtti.hpp
@@ -64,6 +64,7 @@
#ifndef _OUSIA_RTTI_HPP_
#define _OUSIA_RTTI_HPP_
+#include <memory>
#include <typeinfo>
#include <typeindex>
#include <unordered_map>
@@ -73,6 +74,25 @@
namespace ousia {
class RttiType;
+class Function;
+class PropertyDescriptor;
+
+/**
+ * Type describing a set of RttiType pointers.
+ */
+using RttiTypeSet = std::unordered_set<const RttiType *>;
+
+/**
+ * Type describing a map containing methods and their name.
+ */
+using RttiMethodMap =
+ std::unordered_map<std::string, std::shared_ptr<Function>>;
+
+/**
+ * Type describing a map containing properties and their name.
+ */
+using RttiPropertyMap =
+ std::unordered_map<std::string, std::shared_ptr<PropertyDescriptor>>;
/**
* Helper class used to globally store and access the runtime type information.
@@ -113,11 +133,6 @@ public:
class RttiBuilder {
public:
/**
- * Type describing a set of RttiType pointers.
- */
- using RttiTypeSet = std::unordered_set<const RttiType *>;
-
- /**
* Contains the human readable name of the type for which the type
* information is being built.
*/
@@ -134,6 +149,16 @@ public:
RttiTypeSet compositeTypes;
/**
+ * Map containing all methods.
+ */
+ RttiMethodMap methods;
+
+ /**
+ * Map containing all properties.
+ */
+ RttiPropertyMap properties;
+
+ /**
* Default constructor, initializes the name of the type described by the
* RttiTypeSet with "unknown".
*/
@@ -177,20 +202,6 @@ public:
}
/**
- * Adds the given type descriptor as "parent" of the type information that
- * is being built by this RttiBuilder instance.
- *
- * @param p is the pointer to the type descriptor that should be added.
- * @return a reference to the current RttiBuilder reference to allow method
- * chaining.
- */
- RttiBuilder &parent(const RttiType &p)
- {
- parentTypes.insert(&p);
- return *this;
- }
-
- /**
* Adds the given type descriptors as "parent" of the type information that
* is being built by this RttiBuilder instance.
*
@@ -221,33 +232,44 @@ public:
/**
* Marks the current type being built by this RttiBuilder instance as being
- * a composition of the given other type.
+ * a composition of the given other types.
*
* @param p is the pointer to the type descriptor that should be added as
* composition type.
* @return a reference to the current RttiBuilder reference to allow method
* chaining.
*/
- RttiBuilder &composedOf(const RttiType &p)
+ RttiBuilder &composedOf(const RttiTypeSet &p)
{
- compositeTypes.insert(&p);
+ compositeTypes.insert(p.begin(), p.end());
return *this;
}
/**
- * Marks the current type being built by this RttiBuilder instance as being
- * a composition of the given other types.
+ * Registers a generic (no particular C++ type given) method for this RTTI
+ * type descriptor.
*
- * @param p is the pointer to the type descriptor that should be added as
- * composition type.
+ * @param name is the name of the method. Names must be unique for one
+ * RttiType instance. If the name is not unique, an exception is thrown.
+ * @param function is the function that should be registered.
* @return a reference to the current RttiBuilder reference to allow method
* chaining.
*/
- RttiBuilder &composedOf(const RttiTypeSet &p)
- {
- compositeTypes.insert(p.begin(), p.end());
- return *this;
- }
+ RttiBuilder &genericMethod(const std::string name,
+ std::shared_ptr<Function> function);
+
+ /**
+ * Registers a generic (no particular C++ type given) property descriptor
+ * for this RTTI type descriptor.
+ *
+ * @param name is the name of the property. Names must be unique for one
+ * RttiType instance. If the property is not unique, an exception is thrown.
+ * @param property is the property that should be registered.
+ * @return a reference to the current RttiBuilder reference to allow method
+ * chaining.
+ */
+ RttiBuilder &genericProperty(const std::string name,
+ std::shared_ptr<PropertyDescriptor> property);
};
/**
@@ -269,37 +291,31 @@ private:
/**
* Set containing references to all parent types, including their parents.
*/
- mutable std::unordered_set<const RttiType *> parents;
+ mutable RttiTypeSet parents;
/**
* Set containing references to all types this type is a composition of,
* including all composite types of the original composite types.
*/
- mutable std::unordered_set<const RttiType *> compositeTypes;
+ mutable RttiTypeSet compositeTypes;
/**
- * Adds the parent types of the original parents and the composite types of
- * the original composite types to the internal sets for faster lookup.
+ * Map used for storing all registered methods.
*/
- void initialize() const;
+ mutable RttiMethodMap methods;
-public:
/**
- * Human readable name associated with the type.
+ * Map used for storing all registered properties.
*/
- const std::string name;
+ mutable RttiPropertyMap properties;
/**
- * Default constructor. Creates a Rtti instance with name "unknown"
- * and no parents.
- */
- RttiType() : name("unknown") {}
-
- /**
- * Constructor for an empty RttiType with the given name.
+ * Adds the parent types of the original parents and the composite types of
+ * the original composite types to the internal sets for faster lookup.
*/
- RttiType(std::string name) : name(std::move(name)) {}
+ void initialize() const;
+protected:
/**
* Creates a new RttiType instance and registers it in the global type
* table. Use the Rtti and the RttiBuilder class for more convenient
@@ -313,13 +329,15 @@ public:
* are composited (consist of).
*/
RttiType(std::string name, const std::type_info &native,
- std::unordered_set<const RttiType *> parents =
- std::unordered_set<const RttiType *>{},
- std::unordered_set<const RttiType *> compositeTypes =
- std::unordered_set<const RttiType *>{})
+ RttiTypeSet parents = RttiTypeSet{},
+ RttiTypeSet compositeTypes = RttiTypeSet{},
+ RttiMethodMap methods = RttiMethodMap{},
+ RttiPropertyMap properties = RttiPropertyMap{})
: initialized(false),
parents(std::move(parents)),
compositeTypes(compositeTypes),
+ methods(std::move(methods)),
+ properties(std::move(properties)),
name(std::move(name))
{
RttiStore::store(native, this);
@@ -334,13 +352,32 @@ public:
*/
RttiType(const std::type_info &native, const RttiBuilder &builder)
: initialized(false),
- parents(builder.parentTypes),
- compositeTypes(builder.compositeTypes),
- name(builder.currentName)
+ parents(std::move(builder.parentTypes)),
+ compositeTypes(std::move(builder.compositeTypes)),
+ methods(std::move(builder.methods)),
+ properties(std::move(builder.properties)),
+ name(std::move(builder.currentName))
{
RttiStore::store(native, this);
}
+public:
+ /**
+ * Human readable name associated with the type.
+ */
+ const std::string name;
+
+ /**
+ * Default constructor. Creates a Rtti instance with name "unknown"
+ * and no parents.
+ */
+ RttiType() : name("unknown") {}
+
+ /**
+ * Constructor for an empty RttiType with the given name.
+ */
+ RttiType(std::string name) : name(std::move(name)) {}
+
/**
* Returns true if this Rtti instance is the given type or has the
* given type as one of its parents.
@@ -359,6 +396,45 @@ public:
* type is directly or indirectly composed of it.
*/
bool composedOf(const RttiType &other) const;
+
+ /**
+ * Returns all methods that are registered for this type (and the parent
+ * types, where methods with the same name as those in the parent type
+ * shadow the parent name methods).
+ *
+ * @return a mapping between method name and shared pointers of the
+ * registered function.
+ */
+ const RttiMethodMap& getMethods() const;
+
+ /**
+ * Returns all properties that are registered for this type (and the parent
+ * types, where properties with the same name as those in the parent type
+ * shadow the parent name properties).
+ *
+ * @return a mapping between property name and the shared pointers of the
+ * registered properties.
+ */
+ const RttiPropertyMap& getProperties() const;
+
+ /**
+ * Searches for a method with the given name. Returns a shared pointer to
+ * that method if found or nullptr otherwise.
+ *
+ * @param name is the name of the method that should be looked up.
+ * @return a shared pointer pointing at the method with the given name
+ */
+ std::shared_ptr<Function> getMethod(const std::string &name) const;
+
+ /**
+ * Searches for a property with the given name. Returns a shared pointer to
+ * that property if found or nullptr otherwise.
+ *
+ * @param name is the name of the property that should be looked up.
+ * @return a shared pointer pointing at the property with the given name
+ */
+ std::shared_ptr<PropertyDescriptor> getProperty(const std::string &name) const;
+
};
/**
@@ -376,18 +452,8 @@ public:
* Creates a new Rtti instance and registers it in the global type table.
*
* @param name is the name of the type.
- * @param parents is a list of parent types.
- * @param compositeTypes is a list of types of which instances of this type
- * are composited (consist of).
*/
- Rtti(std::string name, const std::unordered_set<const RttiType *> &parents =
- std::unordered_set<const RttiType *>{},
- std::unordered_set<const RttiType *> compositeTypes =
- std::unordered_set<const RttiType *>{})
- : RttiType(name, typeid(T), std::move(parents),
- std::move(compositeTypes))
- {
- }
+ Rtti(std::string name) : RttiType(name, typeid(T)) {}
/**
* Creates a new Rtti instance from the data stored in the given builder
diff --git a/src/core/common/TypedRttiBuilder.cpp b/src/core/common/TypedRttiBuilder.cpp
new file mode 100644
index 0000000..ea836e0
--- /dev/null
+++ b/src/core/common/TypedRttiBuilder.cpp
@@ -0,0 +1,24 @@
+/*
+ Ousía
+ Copyright (C) 2014, 2015 Benjamin Paaßen, Andreas Stöckel
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "TypedRttiBuilder.hpp"
+
+namespace ousia {
+
+}
+
diff --git a/src/core/common/TypedRttiBuilder.hpp b/src/core/common/TypedRttiBuilder.hpp
new file mode 100644
index 0000000..e390b38
--- /dev/null
+++ b/src/core/common/TypedRttiBuilder.hpp
@@ -0,0 +1,171 @@
+/*
+ Ousía
+ Copyright (C) 2014, 2015 Benjamin Paaßen, Andreas Stöckel
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+/**
+ * @file TypedRttiBuilder.hpp
+ *
+ * Defines a more convenient version of the RttiBuilder.
+ *
+ * @author Andreas Stöckel (astoecke@techfak.uni-bielefeld.de)
+ */
+
+#ifndef _OUSIA_TYPED_RTTI_BUILDER_HPP_
+#define _OUSIA_TYPED_RTTI_BUILDER_HPP_
+
+#include "Argument.hpp"
+#include "Rtti.hpp"
+#include "Function.hpp"
+#include "Property.hpp"
+
+namespace ousia {
+
+/**
+ * The TypedRttiBuilder class is a more convenient version of the RttiBuilder
+ * class which allows simple definition of new methods and properties.
+ *
+ * @tparam T is the C++ class for which the type is being built.
+ */
+template <class T>
+class TypedRttiBuilder : public RttiBuilder {
+public:
+ using RttiBuilder::RttiBuilder;
+
+ /**
+ * Sets the human readable name of the type information being built to the
+ * given string.
+ *
+ * @param s is the name to which the name should be set.
+ * @return a reference to the current TypedRttiBuilder reference to allow
+ * method chaining.
+ */
+ TypedRttiBuilder<T> &name(const std::string &s)
+ {
+ RttiBuilder::name(s);
+ return *this;
+ }
+
+ /**
+ * Adds the given type descriptor as "parent" of the type information that
+ * is being built by this RttiBuilder instance.
+ *
+ * @param p is the pointer to the type descriptor that should be added.
+ * @return a reference to the current TypedRttiBuilder reference to allow
+ * method chaining.
+ */
+ TypedRttiBuilder<T> &parent(const RttiType *p)
+ {
+ RttiBuilder::parent(p);
+ return *this;
+ }
+
+ /**
+ * Adds the given type descriptors as "parent" of the type information that
+ * is being built by this RttiBuilder instance.
+ *
+ * @param p is a
+ * @return a reference to the current TypedRttiBuilder reference to allow
+ * method chaining.
+ */
+ TypedRttiBuilder<T> &parent(const RttiTypeSet &p)
+ {
+ RttiBuilder::parent(p);
+ return *this;
+ }
+
+ /**
+ * Marks the current type being built by this RttiBuilder instance as being
+ * a composition of the given other type.
+ *
+ * @param p is the pointer to the type descriptor that should be added as
+ * composition type.
+ * @return a reference to the current TypedRttiBuilder reference to allow
+ * method chaining.
+ */
+ TypedRttiBuilder<T> &composedOf(const RttiType *p)
+ {
+ RttiBuilder::composedOf(p);
+ return *this;
+ }
+
+ /**
+ * Marks the current type being built by this RttiBuilder instance as being
+ * a composition of the given other types.
+ *
+ * @param p is the pointer to the type descriptor that should be added as
+ * composition type.
+ * @return a reference to the current TypedRttiBuilder reference to allow
+ * method chaining.
+ */
+ TypedRttiBuilder<T> &composedOf(const RttiTypeSet &p)
+ {
+ RttiBuilder::composedOf(p);
+ return *this;
+ }
+
+ /**
+ * Registers a method for this RTTI type descriptor.
+ *
+ * @param name is the name of the method. Names must be unique for one
+ * RttiType instance. If the name is not unique, an exception is thrown.
+ * @param method is the function that should be registered.
+ * @return a reference to the current TypedRttiBuilder reference to allow
+ * method chaining.
+ */
+ TypedRttiBuilder<T> &method(const std::string name, const Method<T> &method)
+ {
+ RttiBuilder::genericMethod(name, std::make_shared<Method<T>>(method));
+ return *this;
+ }
+
+ /**
+ * Registers a method for this RTTI type descriptor.
+ *
+ * @param name is the name of the method. Names must be unique for one
+ * RttiType instance. If the name is not unique, an exception is thrown.
+ * @param method is the function that should be registered.
+ * @return a reference to the current TypedRttiBuilder reference to allow
+ * method chaining.
+ */
+ TypedRttiBuilder<T> &method(const std::string name,
+ const typename Method<T>::Callback &method)
+ {
+ RttiBuilder::genericMethod(name, std::make_shared<Method<T>>(method));
+ return *this;
+ }
+
+ /**
+ * Registers a property for this RTTI type descriptor.
+ *
+ * @param name is the name of the property. Names must be unique for one
+ * RttiType instance. If the property is not unique, an exception is thrown.
+ * @param property is the property that should be registered.
+ * @return a reference to the current TypedRttiBuilder reference to allow
+ * method chaining.
+ */
+ TypedRttiBuilder<T> &property(const std::string name,
+ const Property<T> &property)
+ {
+ RttiBuilder::genericProperty(name,
+ std::make_shared<Property<T>>(property));
+ return *this;
+ }
+};
+}
+
+#endif /* _OUSIA_TYPED_RTTI_BUILDER_HPP_ */
+
diff --git a/test/core/common/PropertyTest.cpp b/test/core/common/PropertyTest.cpp
index c28feeb..0f3d74e 100644
--- a/test/core/common/PropertyTest.cpp
+++ b/test/core/common/PropertyTest.cpp
@@ -61,7 +61,8 @@ TEST(Getter, construction)
TEST(Getter, validation)
{
- const PropertyType type{RttiTypes::Int};
+ std::shared_ptr<PropertyType> type =
+ std::make_shared<PropertyType>(RttiTypes::Int);
TestObject obj{123};
{
@@ -73,7 +74,7 @@ TEST(Getter, validation)
{
// Int type set, returning strings is an exception
Getter<TestObject> getter{getString};
- getter.propertyType = &type;
+ getter.propertyType = type;
ASSERT_THROW(getter.get(&obj), LoggableException);
}
@@ -109,7 +110,8 @@ TEST(Setter, construction)
TEST(Setter, validation)
{
- const PropertyType type{RttiTypes::Int};
+ std::shared_ptr<PropertyType> type =
+ std::make_shared<PropertyType>(RttiTypes::Int);
TestObject obj{123};
Setter<TestObject> setter{TestObject::setA};
@@ -128,7 +130,7 @@ TEST(Setter, validation)
setter.set("foo", &obj);
ASSERT_EQ(42, obj.a);
- setter.propertyType = &type;
+ setter.propertyType = type;
ASSERT_THROW(setter.set("foo", &obj), LoggableException);
setter.set(123, &obj);
diff --git a/test/core/common/RttiTest.cpp b/test/core/common/RttiTest.cpp
index 36bf48f..5d02553 100644
--- a/test/core/common/RttiTest.cpp
+++ b/test/core/common/RttiTest.cpp
@@ -22,7 +22,10 @@
#include <gtest/gtest.h>
+#include <core/common/Function.hpp>
#include <core/common/Rtti.hpp>
+#include <core/common/TypedRttiBuilder.hpp>
+#include <core/common/Variant.hpp>
namespace ousia {
namespace {
@@ -45,18 +48,15 @@ class RttiTestClass7 {
extern const Rtti<RttiTestClass6> Type6;
extern const Rtti<RttiTestClass7> Type7;
-const Rtti<RttiTestClass1> Type1("Type1");
-const Rtti<RttiTestClass2> Type2("Type2");
-const Rtti<RttiTestClass3> Type3("Type3", {&Type1});
-const Rtti<RttiTestClass4> Type4("Type4", {&Type3, &Type2});
-const Rtti<RttiTestClass5> Type5("Type5",
- std::unordered_set<const RttiType *>{},
- {&Type6, &Type7});
-const Rtti<RttiTestClass6> Type6("Type6",
- std::unordered_set<const RttiType *>{},
- {&Type1});
-const Rtti<RttiTestClass7> Type7("Type7", {&Type6},
- std::unordered_set<const RttiType *>{});
+const Rtti<RttiTestClass1> Type1 = RttiBuilder{"Type1"};
+const Rtti<RttiTestClass2> Type2 = RttiBuilder{"Type2"};
+const Rtti<RttiTestClass3> Type3 = RttiBuilder{"Type3"}.parent(&Type1);
+const Rtti<RttiTestClass4> Type4 =
+ RttiBuilder{"Type4"}.parent({&Type3, &Type2});
+const Rtti<RttiTestClass5> Type5 =
+ RttiBuilder{"Type5"}.composedOf({&Type6, &Type7});
+const Rtti<RttiTestClass6> Type6 = RttiBuilder{"Type6"}.composedOf(&Type1);
+const Rtti<RttiTestClass7> Type7 = RttiBuilder{"Type7"}.parent(&Type6);
TEST(Rtti, isa)
{
@@ -118,6 +118,146 @@ TEST(Rtti, composedOf)
ASSERT_FALSE(Type7.composedOf(Type6));
ASSERT_FALSE(Type7.composedOf(Type7));
}
+
+class RttiMethodTestClass1 {
+};
+class RttiMethodTestClass2 {
+};
+
+static const Rtti<RttiMethodTestClass1> MType1 =
+ RttiBuilder{"MType1"}
+ .genericMethod(
+ "a", std::make_shared<Method<RttiMethodTestClass1>>([](
+ Variant::arrayType &args,
+ RttiMethodTestClass1 *thisPtr) { return Variant{"a"}; }))
+ .genericMethod(
+ "b", std::make_shared<Method<RttiMethodTestClass1>>([](
+ Variant::arrayType &args,
+ RttiMethodTestClass1 *thisPtr) { return Variant{"b"}; }))
+ .genericMethod(
+ "c", std::make_shared<Method<RttiMethodTestClass1>>([](
+ Variant::arrayType &args,
+ RttiMethodTestClass1 *thisPtr) { return Variant{"c"}; }));
+
+static const Rtti<RttiMethodTestClass2> MType2 =
+ TypedRttiBuilder<RttiMethodTestClass2>{"MType2"}
+ .parent(&MType1)
+ .method("c",
+ [](Variant::arrayType &args,
+ RttiMethodTestClass2 *thisPtr) { return Variant{"c2"}; })
+ .method("d", [](Variant::arrayType &args,
+ RttiMethodTestClass2 *thisPtr) { return Variant{"d"}; })
+ .method("e",
+ {{Argument::Int("a"), Argument::Int("b")},
+ [](Variant::arrayType &args, RttiMethodTestClass2 *thisPtr) {
+ return Variant{args[0].asInt() * args[1].asInt()};
+ }});
+
+TEST(Rtti, methods)
+{
+ auto methods = MType1.getMethods();
+ ASSERT_TRUE(methods.count("a") > 0);
+ ASSERT_TRUE(methods.count("b") > 0);
+ ASSERT_TRUE(methods.count("c") > 0);
+
+ ASSERT_FALSE(MType1.getMethod("a") == nullptr);
+ ASSERT_FALSE(MType1.getMethod("b") == nullptr);
+ ASSERT_FALSE(MType1.getMethod("c") == nullptr);
+ ASSERT_TRUE(MType1.getMethod("d") == nullptr);
+
+ ASSERT_EQ("a", MType1.getMethod("a")->call().asString());
+ ASSERT_EQ("b", MType1.getMethod("b")->call().asString());
+ ASSERT_EQ("c", MType1.getMethod("c")->call().asString());
+
+ methods = MType2.getMethods();
+ ASSERT_TRUE(methods.count("a") > 0);
+ ASSERT_TRUE(methods.count("b") > 0);
+ ASSERT_TRUE(methods.count("c") > 0);
+ ASSERT_TRUE(methods.count("d") > 0);
+
+ ASSERT_FALSE(MType2.getMethod("a") == nullptr);
+ ASSERT_FALSE(MType2.getMethod("b") == nullptr);
+ ASSERT_FALSE(MType2.getMethod("c") == nullptr);
+ ASSERT_FALSE(MType2.getMethod("d") == nullptr);
+
+ ASSERT_EQ("a", MType2.getMethod("a")->call().asString());
+ ASSERT_EQ("b", MType2.getMethod("b")->call().asString());
+ ASSERT_EQ("c2", MType2.getMethod("c")->call().asString());
+ ASSERT_EQ("d", MType2.getMethod("d")->call().asString());
+ ASSERT_EQ(42,
+ MType2.getMethod("e")->call(Variant::arrayType{6, 7}).asInt());
+ ASSERT_THROW(MType2.getMethod("e")->call(Variant::arrayType{6, "7"}),
+ LoggableException);
+}
+
+class RttiPropertyTestClass1 {
+public:
+ int a;
+
+ RttiPropertyTestClass1() : a(0) {}
+
+ static Variant getA(const RttiPropertyTestClass1 *obj) { return obj->a; }
+
+ static void setA(const Variant &value, RttiPropertyTestClass1 *obj)
+ {
+ obj->a = value.asInt();
+ }
+};
+
+class RttiPropertyTestClass2 : public RttiPropertyTestClass1 {
+public:
+ int b;
+
+ RttiPropertyTestClass2() : b(0) {}
+
+ static Variant getB(const RttiPropertyTestClass2 *obj) { return obj->b; }
+
+ static void setB(const Variant &value, RttiPropertyTestClass2 *obj)
+ {
+ obj->b = value.asInt();
+ }
+};
+
+static const Rtti<RttiPropertyTestClass1> PType1 =
+ TypedRttiBuilder<RttiPropertyTestClass1>{"PType1"}.property(
+ "a", {RttiTypes::Int, RttiPropertyTestClass1::getA,
+ RttiPropertyTestClass1::setA});
+
+static const Rtti<RttiMethodTestClass2> PType2 =
+ TypedRttiBuilder<RttiPropertyTestClass2>{"PType2"}.parent(&PType1).property(
+ "b", {RttiTypes::Int, RttiPropertyTestClass2::getB,
+ RttiPropertyTestClass2::setB});
+
+TEST(Rtti, properties)
+{
+ RttiPropertyTestClass2 obj;
+
+ auto properties = PType1.getProperties();
+ ASSERT_TRUE(properties.count("a") > 0);
+ ASSERT_FALSE(properties.count("b") > 0);
+
+ ASSERT_FALSE(PType1.getProperty("a") == nullptr);
+ ASSERT_TRUE(PType1.getProperty("b") == nullptr);
+
+ ASSERT_EQ(0, PType1.getProperty("a")->get(&obj).asInt());
+ PType1.getProperty("a")->set(4, &obj);
+ ASSERT_EQ(4, PType1.getProperty("a")->get(&obj).asInt());
+
+ properties = PType2.getProperties();
+ ASSERT_TRUE(properties.count("a") > 0);
+ ASSERT_TRUE(properties.count("b") > 0);
+
+ ASSERT_FALSE(PType2.getProperty("a") == nullptr);
+ ASSERT_FALSE(PType2.getProperty("b") == nullptr);
+
+ ASSERT_EQ(4, PType2.getProperty("a")->get(&obj).asInt());
+ PType2.getProperty("a")->set(8, &obj);
+ ASSERT_EQ(8, PType2.getProperty("a")->get(&obj).asInt());
+
+ ASSERT_EQ(0, PType2.getProperty("b")->get(&obj).asInt());
+ PType2.getProperty("b")->set(5, &obj);
+ ASSERT_EQ(5, PType2.getProperty("b")->get(&obj).asInt());
+}
}
}
diff --git a/test/core/managed/ManagedTest.cpp b/test/core/managed/ManagedTest.cpp
index a943f5d..0391738 100644
--- a/test/core/managed/ManagedTest.cpp
+++ b/test/core/managed/ManagedTest.cpp
@@ -76,10 +76,11 @@ class TypeTestManaged5 : public Managed {
using Managed::Managed;
};
-static const Rtti<TypeTestManaged1> Type1("Type1");
-static const Rtti<TypeTestManaged2> Type2("Type2");
-static const Rtti<TypeTestManaged3> Type3("Type3", {&Type1});
-static const Rtti<TypeTestManaged4> Type4("Type4", {&Type3, &Type2});
+static const Rtti<TypeTestManaged1> Type1 = RttiBuilder{"Type1"};
+static const Rtti<TypeTestManaged2> Type2 = RttiBuilder{"Type2"};
+static const Rtti<TypeTestManaged3> Type3 = RttiBuilder{"Type3"}.parent(&Type1);
+static const Rtti<TypeTestManaged4> Type4 =
+ RttiBuilder{"Type4"}.parent({&Type3, &Type2});
TEST(Managed, type)
{