From 7d1b3c5df2eab1d42179332d467d5756aefed587 Mon Sep 17 00:00:00 2001 From: Andreas Stöckel Date: Wed, 14 Jan 2015 02:44:09 +0100 Subject: Implemented attaching Methods and Property information to Types (this will later allow script engines to access these methods). --- src/core/common/Property.cpp | 22 ++-- src/core/common/Property.hpp | 28 ++--- src/core/common/Rtti.cpp | 70 ++++++++++++- src/core/common/Rtti.hpp | 196 +++++++++++++++++++++++------------ src/core/common/TypedRttiBuilder.cpp | 24 +++++ src/core/common/TypedRttiBuilder.hpp | 171 ++++++++++++++++++++++++++++++ 6 files changed, 420 insertions(+), 91 deletions(-) create mode 100644 src/core/common/TypedRttiBuilder.cpp create mode 100644 src/core/common/TypedRttiBuilder.hpp (limited to 'src') 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 getter, - std::unique_ptr setter) - : type(type), getter(std::move(getter)), setter(std::move(setter)) + std::shared_ptr getter, + std::shared_ptr setter) + : type(std::make_shared(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; /** * 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 type; /** * Object used to read the value of the property. */ - std::unique_ptr getter; + std::shared_ptr 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 setter; + std::shared_ptr 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 getter, - std::unique_ptr setter); + std::shared_ptr getter, + std::shared_ptr 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 &getter, const Setter &setter = Setter{}) : PropertyDescriptor( PropertyType{}, - std::unique_ptr{new Getter{getter}}, - std::unique_ptr{new Setter{setter}}) + std::make_shared>(getter), + std::make_shared>(setter)) { } @@ -458,8 +458,8 @@ public: const Setter &setter = Setter{}) : PropertyDescriptor( PropertyType{type}, - std::unique_ptr{new Getter{getter}}, - std::unique_ptr{new Setter{setter}}) + std::make_shared>(getter), + std::make_shared>(setter)) { } @@ -481,8 +481,8 @@ public: const Getter &getter, const Setter &setter = Setter{}) : PropertyDescriptor( PropertyType{type, innerType}, - std::unique_ptr{new Getter{getter}}, - std::unique_ptr{new Setter{setter}}) + std::make_shared>(getter), + std::make_shared>(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 . */ +#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) +{ + 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 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 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 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 #include #include #include @@ -73,6 +74,25 @@ namespace ousia { class RttiType; +class Function; +class PropertyDescriptor; + +/** + * Type describing a set of RttiType pointers. + */ +using RttiTypeSet = std::unordered_set; + +/** + * Type describing a map containing methods and their name. + */ +using RttiMethodMap = + std::unordered_map>; + +/** + * Type describing a map containing properties and their name. + */ +using RttiPropertyMap = + std::unordered_map>; /** * Helper class used to globally store and access the runtime type information. @@ -112,11 +132,6 @@ public: */ class RttiBuilder { public: - /** - * Type describing a set of RttiType pointers. - */ - using RttiTypeSet = std::unordered_set; - /** * Contains the human readable name of the type for which the type * information is being built. @@ -133,6 +148,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". @@ -176,20 +201,6 @@ public: 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 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); + + /** + * 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 property); }; /** @@ -269,37 +291,31 @@ private: /** * Set containing references to all parent types, including their parents. */ - mutable std::unordered_set 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 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 parents = - std::unordered_set{}, - std::unordered_set compositeTypes = - std::unordered_set{}) + 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 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 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 &parents = - std::unordered_set{}, - std::unordered_set compositeTypes = - std::unordered_set{}) - : 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 . +*/ + +#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 . +*/ + +/** + * @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 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 &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 &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 &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 &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 &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 &method(const std::string name, const Method &method) + { + RttiBuilder::genericMethod(name, std::make_shared>(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 &method(const std::string name, + const typename Method::Callback &method) + { + RttiBuilder::genericMethod(name, std::make_shared>(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 &property(const std::string name, + const Property &property) + { + RttiBuilder::genericProperty(name, + std::make_shared>(property)); + return *this; + } +}; +} + +#endif /* _OUSIA_TYPED_RTTI_BUILDER_HPP_ */ + -- cgit v1.2.3