Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: code/branches/objecthierarchy/src/orxonox/core/Identifier.h @ 453

Last change on this file since 453 was 453, checked in by landauf, 17 years ago

added benschs Debug.h from orxonox_v1

include Debug.h or CoreIncludes.h and use it in the following way:
COUT(int) << bla;
PRINT(int)(bla);
PRINTF(int)(bla);

where 'bla' is the same as if you would use the normal std::cout or printf function
and 'int' is a value between 0 and 5:
0 = no debug output
1 = errors
2 = warnings
3 = info
4 = debug
5 = more debug

so to print a warning, use int = 2
for some unimportant debug information, use int = 4
and so on…

the level of the output is configured in the Debug.h file (later i'll add an entry to the config-file for the soft-level).

File size: 16.3 KB
RevLine 
[365]1/*!
2    @file Identifier.h
[452]3    @brief Definition of the Identifier, ClassIdentifier and SubclassIdentifier classes, implementation of the ClassIdentifier and SubclassIdentifier classes.
[365]4
5    The Identifier contains all needed informations about the class it belongs to:
6     - the name
7     - a list with all objects
8     - parents and childs
[447]9     - the factory (if available)
[365]10     - the networkID that can be synchronised with the server
[447]11     - all configurable variables (if available)
[365]12
13    Every object has a pointer to the Identifier of its class. This allows the use isA(...),
14    isDirectlyA(...), isChildOf(...) and isParentOf(...).
15
16    To create the class-hierarchy, the Identifier has some intern functions and variables.
17
18    Every Identifier is in fact a ClassIdentifier, but they are derived from Identifier.
19
20    SubclassIdentifier is a separated class, acting like an Identifier, but has a given class.
[447]21    You can only assign Identifiers of exactly the given class or of a derivative to a SubclassIdentifier.
[365]22*/
23
[197]24#ifndef _Identifier_H__
25#define _Identifier_H__
26
[219]27#include <iostream>
[434]28#include <map>
[219]29
[197]30#include "IdentifierList.h"
31#include "ObjectList.h"
[218]32#include "Factory.h"
[434]33#include "ConfigValueContainer.h"
[453]34#include "Debug.h"
[197]35
36namespace orxonox
37{
[365]38    class BaseObject; // Forward declaration
[219]39
[224]40    // ###############################
41    // ###       Identifier        ###
42    // ###############################
[365]43    //! The Identifier is used to identify the class of an object and to store informations about the class.
44    /**
45        The Identifier contains all needed informations about the class it belongs to:
46         - the name
47         - a list with all objects
48         - parents and childs
[447]49         - the factory (if available)
[365]50         - the networkID that can be synchronised with the server
[447]51         - all configurable variables (if available)
[365]52
53        Every object has a pointer to the Identifier of its class. This allows the use isA(...),
54        isDirectlyA(...), isChildOf(...) and isParentOf(...).
55
56        You can't directly create an Identifier, it's just the base-class for ClassIdentifier.
57    */
[197]58    class Identifier
59    {
60        template <class T>
[365]61        friend class ClassIdentifier; // Forward declaration
[197]62
63        template <class T>
[365]64        friend class SubclassIdentifier; // Forward declaration
[197]65
[244]66        template <class T>
[365]67        friend class ClassFactory; // Forward declaration
[244]68
[197]69        public:
[365]70            /** @brief Sets the Factory. @param facotry The factory to assign */
[244]71            inline void addFactory(BaseFactory* factory) { this->factory_ = factory; }
[365]72
[244]73            BaseObject* fabricate();
[218]74
[239]75            bool isA(const Identifier* identifier) const;
76            bool isDirectlyA(const Identifier* identifier) const;
77            bool isChildOf(const Identifier* identifier) const;
78            bool isParentOf(const Identifier* identifier) const;
[197]79
[365]80            /** @returns the name of the class the Identifier belongs to. */
[244]81            inline const std::string& getName() const { return this->name_; }
[365]82
83            /** @returns the parents of the class the Identifier belongs to. */
[244]84            inline const IdentifierList& getParents() const { return this->parents_; }
[365]85
86            /** @returns the children of the class the Identifier belongs to. */
[244]87            inline IdentifierList& getChildren() const { return *this->children_; }
[197]88
[447]89            /** @returns true, if a branch of the class-hierarchy is being created, causing all new objects to store their parents. */
[244]90            inline static bool isCreatingHierarchy() { return (hierarchyCreatingCounter_s > 0); }
[219]91
[447]92            /** @returns the network ID to identify a class through the network. */
[362]93            inline const unsigned int getNetworkID() const { return this->classID_; }
[365]94
[447]95            /** @brief Sets the network ID to a new value. @param id The new value */
[362]96            void setNetworkID(unsigned int id);
97
[447]98            /** @returns the ConfigValueContainer of a variable, given by the string of its name. @param varname The name of the variable */
[434]99            inline ConfigValueContainer* getConfigValueContainer(const std::string& varname)
100                { return this->configValues_[varname]; }
101
[447]102            /** @brief Sets the ConfigValueContainer of a variable, given by the string of its name. @param varname The name of the variablee @param container The container */
[434]103            inline void setConfigValueContainer(const std::string& varname, ConfigValueContainer* container)
104                { this->configValues_[varname] = container; }
105
[197]106        private:
107            Identifier();
[365]108            Identifier(const Identifier& identifier) {} // don't copy
[197]109            virtual ~Identifier();
[239]110            void initialize(const IdentifierList* parents);
[197]111
[365]112            /**
113                @brief Increases the hierarchyCreatingCounter_s variable, causing all new objects to store their parents.
114            */
[244]115            inline static void startCreatingHierarchy()
[231]116            {
117                hierarchyCreatingCounter_s++;
[453]118                COUT(4) << "*** Increased Hierarchy-Creating-Counter to " << hierarchyCreatingCounter_s << "\n";
[231]119            }
[197]120
[365]121            /**
122                @brief Decreases the hierarchyCreatingCounter_s variable, causing the objects to stop storing their parents.
123            */
[244]124            inline static void stopCreatingHierarchy()
[231]125            {
126                hierarchyCreatingCounter_s--;
[453]127                COUT(4) << "*** Decreased Hierarchy-Creating-Counter to " << hierarchyCreatingCounter_s << "\n";
[231]128            }
129
[434]130            IdentifierList parents_;                                    //!< The Parents of the class the Identifier belongs to
131            IdentifierList* children_;                                  //!< The Children of the class the Identifier belongs to
[219]132
[434]133            std::string name_;                                          //!< The name of the class the Identifier belongs to
[197]134
[447]135            BaseFactory* factory_;                                      //!< The Factory, able to create new objects of the given class (if available)
[434]136            bool bCreatedOneObject_;                                    //!< True if at least one object of the given type was created (used to determine the need of storing the parents)
137            static int hierarchyCreatingCounter_s;                      //!< Bigger than zero if at least one Identifier stores its parents (its an int instead of a bool to avoid conflicts with multithreading)
[447]138            static unsigned int classIDcounter_s;                       //!< The number of existing Identifiers
139            unsigned int classID_;                                      //!< The network ID to identify a class through the network
140            std::map<std::string, ConfigValueContainer*> configValues_; //!< A map to link the string of configurable variables with their ConfigValueContainer
[197]141    };
142
143
[224]144    // ###############################
145    // ###     ClassIdentifier     ###
146    // ###############################
[365]147    //! The ClassIdentifier is derived from Identifier and holds all class-specific functions and variables the Identifier cannot have.
148    /**
149        ClassIdentifier is a Singleton, which means that only one object of a given type T exists.
150        This makes it possible to store informations about a class, sharing them with all
151        objects of that class without defining static variables in every class.
152    */
[197]153    template <class T>
154    class ClassIdentifier : public Identifier
155    {
156        public:
[244]157            static ClassIdentifier<T>* registerClass(const IdentifierList* parents, const std::string& name, bool bRootClass);
[197]158            static ClassIdentifier<T>* getIdentifier();
[224]159            static void addObject(T* object);
[197]160
161        private:
162            ClassIdentifier();
[365]163            ClassIdentifier(const ClassIdentifier<T>& identifier) {} // don't copy
[197]164            ~ClassIdentifier();
165
[365]166            static ClassIdentifier<T>* pointer_s;       //!< A pointer to the singleton-object
167            ObjectList<T>* objects_;                    //!< The ObjectList, containing all objects of type T
[197]168    };
169
170    template <class T>
[365]171    ClassIdentifier<T>* ClassIdentifier<T>::pointer_s = NULL; // Set the static member variable pointer_s to zero
[197]172
[365]173    /**
[447]174        @brief Constructor: Creates the ObjectList.
[365]175    */
[197]176    template <class T>
177    ClassIdentifier<T>::ClassIdentifier()
178    {
[239]179        this->objects_ = new ObjectList<T>;
[197]180    }
181
[365]182    /**
[447]183        @brief Destructor: Deletes the ObjectList, sets the singleton-pointer to zero.
[365]184    */
[197]185    template <class T>
186    ClassIdentifier<T>::~ClassIdentifier()
187    {
[239]188        delete this->objects_;
[219]189        this->pointer_s = NULL;
[197]190    }
191
[365]192    /**
193        @brief Registers a class, which means that the name and the parents get stored.
194        @param parents An IdentifierList, containing the Identifiers of all parents of the class
195        @param name A string, containing exactly the name of the class
[447]196        @param bRootClass True if the class is either an Interface or the BaseObject itself
[365]197        @return The ClassIdentifier itself
198    */
[197]199    template <class T>
[244]200    ClassIdentifier<T>* ClassIdentifier<T>::registerClass(const IdentifierList* parents, const std::string& name, bool bRootClass)
[218]201    {
[453]202        COUT(4) << "*** Register Class in " << name << "-Singleton.\n";
[365]203
204        // It's a singleton, so maybe we have to create it first
[219]205        if (!pointer_s)
[197]206        {
[453]207            COUT(4) << "*** Register Class in " << name << "-Singleton -> Create Singleton.\n";
[244]208            pointer_s = new ClassIdentifier();
209        }
[218]210
[365]211        // Check if at least one object of the given type was created
[244]212        if (!pointer_s->bCreatedOneObject_)
213        {
[365]214            // If no: We have to store the informations and initialize the Identifier
215
[453]216            COUT(4) << "*** Register Class in " << name << "-Singleton -> Initialize Singleton.\n";
[244]217            pointer_s->name_ = name;
[365]218            Factory::add(name, pointer_s); // Add the Identifier to the Factory
[218]219
[244]220            if (bRootClass)
[365]221                pointer_s->initialize(NULL); // If a class is derived from two interfaces, the second interface might think it's derived from the first because of the order of constructor-calls. Thats why we set parents to zero in that case.
[197]222            else
[244]223                pointer_s->initialize(parents);
[197]224        }
225
[219]226        return pointer_s;
[197]227    }
228
[365]229    /**
[447]230        @returns the Identifier itself.
[365]231    */
[197]232    template <class T>
233    ClassIdentifier<T>* ClassIdentifier<T>::getIdentifier()
234    {
[219]235        if (!pointer_s)
[197]236        {
[453]237            COUT(4) << "*** Create Singleton.\n";
[244]238            pointer_s = new ClassIdentifier();
[197]239        }
240
[219]241        return pointer_s;
[197]242    }
243
[365]244    /**
245        @brief Adds an object of the given type to the ObjectList.
246        @param object The object to add
247    */
[224]248    template <class T>
249    void ClassIdentifier<T>::addObject(T* object)
250    {
[453]251        COUT(4) << "*** Added object to " << ClassIdentifier<T>::getIdentifier()->getName() << "-list.\n";
[365]252        object->getMetaList().add(ClassIdentifier<T>::getIdentifier()->objects_, ClassIdentifier<T>::getIdentifier()->objects_->add(object));
[224]253    }
254
255
256    // ###############################
[242]257    // ###   SubclassIdentifier    ###
[224]258    // ###############################
[365]259    //! The SubclassIdentifier acts almost like an Identifier, but has some prerequisites.
260    /**
[447]261        You can only assign an Identifier that belongs to a class T (or derived) to a SubclassIdentifier<T>.
[365]262        If you assign something else, the program aborts.
263        Because we know the minimal type, a dynamic_cast is done, which makes it easier to create a new object.
264    */
265    template <class T>
[242]266    class SubclassIdentifier
[197]267    {
268        public:
[365]269            /**
270                @brief Constructor: Automaticaly assigns the Identifier of the given class.
271            */
272            SubclassIdentifier()
273            {
274                this->identifier_ = ClassIdentifier<T>::getIdentifier();
275            }
[197]276
[365]277            /**
278                @brief Overloading of the = operator: assigns the identifier and checks its type.
279                @param identifier The Identifier to assign
280                @return The SubclassIdentifier itself
281            */
282            SubclassIdentifier<T>& operator=(Identifier* identifier)
[197]283            {
[365]284                if (!identifier->isA(ClassIdentifier<T>::getIdentifier()))
[197]285                {
[453]286                    COUT(1) << "Error: Class " << identifier->getName() << " is not a " << ClassIdentifier<T>::getIdentifier()->getName() << "!\n";
287                    COUT(1) << "Error: SubclassIdentifier<" << ClassIdentifier<T>::getIdentifier()->getName() << "> = Class(" << identifier->getName() << ") is forbidden.\n";
288                    COUT(1) << "Aborting...\n";
[197]289                    abort();
290                }
291                this->identifier_ = identifier;
292                return *this;
293            }
[218]294
[365]295            /**
296                @brief Overloading of the * operator: returns the assigned identifier.
297                @return The assigned identifier
298            */
[221]299            Identifier* operator*()
[218]300            {
301                return this->identifier_;
302            }
303
[365]304            /**
305                @brief Overloading of the -> operator: returns the assigned identifier.
306                @return The assigned identifier
307            */
[221]308            Identifier* operator->() const
[218]309            {
310                return this->identifier_;
311            }
312
[365]313            /**
[447]314                @brief Creates a new object of the type of the assigned Identifier and dynamic_casts it to the minimal type given by T.
[365]315                @return The new object
316            */
317            T* fabricate()
[218]318            {
[219]319                BaseObject* newObject = this->identifier_->fabricate();
[365]320
[447]321                // Check if the creation was successful
[218]322                if (newObject)
323                {
[365]324                    // Do a dynamic_cast, because an object of type T is much better than of type BaseObject
325                    return dynamic_cast<T*>(newObject);
[218]326                }
327                else
328                {
[365]329                    // Something went terribly wrong
[218]330                    if (this->identifier_)
331                    {
[453]332                        COUT(1) << "Error: Class " << this->identifier_->getName() << " is not a " << ClassIdentifier<T>::getIdentifier()->getName() << "!\n";
333                        COUT(1) << "Error: Couldn't fabricate a new Object.\n";
334                        COUT(1) << "Aborting...\n";
[218]335                    }
336                    else
337                    {
[453]338                        COUT(1) << "Error: Couldn't fabricate a new Object - Identifier is undefined.\n";
339                        COUT(1) << "Aborting...\n";
[218]340                    }
341
342                    abort();
343                }
344            }
345
[365]346            /** @returns the assigned identifier. */
[239]347            inline const Identifier* getIdentifier() const
[197]348                { return this->identifier_; }
[365]349
350            /** @returns true, if the assigned identifier is at least of the given type. @param identifier The identifier to compare with */
[239]351            inline bool isA(const Identifier* identifier) const
[197]352                { return this->identifier_->isA(identifier); }
[365]353
354            /** @returns true, if the assigned identifier is exactly of the given type. @param identifier The identifier to compare with */
[239]355            inline bool isDirectlyA(const Identifier* identifier) const
[197]356                { return this->identifier_->isDirectlyA(identifier); }
[365]357
358            /** @returns true, if the assigned identifier is a child of the given identifier. @param identifier The identifier to compare with */
[239]359            inline bool isChildOf(const Identifier* identifier) const
[197]360                { return this->identifier_->isChildOf(identifier); }
[365]361
362            /** @returns true, if the assigned identifier is a parent of the given identifier. @param identifier The identifier to compare with */
[239]363            inline bool isParentOf(const Identifier* identifier) const
[197]364                { return this->identifier_->isParentOf(identifier); }
365
366        private:
[365]367            Identifier* identifier_;        //!< The assigned identifier
[197]368    };
369}
370
371#endif
Note: See TracBrowser for help on using the repository browser.