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
Line 
1/*!
2    @file Identifier.h
3    @brief Definition of the Identifier, ClassIdentifier and SubclassIdentifier classes, implementation of the ClassIdentifier and SubclassIdentifier classes.
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
9     - the factory (if available)
10     - the networkID that can be synchronised with the server
11     - all configurable variables (if available)
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.
21    You can only assign Identifiers of exactly the given class or of a derivative to a SubclassIdentifier.
22*/
23
24#ifndef _Identifier_H__
25#define _Identifier_H__
26
27#include <iostream>
28#include <map>
29
30#include "IdentifierList.h"
31#include "ObjectList.h"
32#include "Factory.h"
33#include "ConfigValueContainer.h"
34#include "Debug.h"
35
36namespace orxonox
37{
38    class BaseObject; // Forward declaration
39
40    // ###############################
41    // ###       Identifier        ###
42    // ###############################
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
49         - the factory (if available)
50         - the networkID that can be synchronised with the server
51         - all configurable variables (if available)
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    */
58    class Identifier
59    {
60        template <class T>
61        friend class ClassIdentifier; // Forward declaration
62
63        template <class T>
64        friend class SubclassIdentifier; // Forward declaration
65
66        template <class T>
67        friend class ClassFactory; // Forward declaration
68
69        public:
70            /** @brief Sets the Factory. @param facotry The factory to assign */
71            inline void addFactory(BaseFactory* factory) { this->factory_ = factory; }
72
73            BaseObject* fabricate();
74
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;
79
80            /** @returns the name of the class the Identifier belongs to. */
81            inline const std::string& getName() const { return this->name_; }
82
83            /** @returns the parents of the class the Identifier belongs to. */
84            inline const IdentifierList& getParents() const { return this->parents_; }
85
86            /** @returns the children of the class the Identifier belongs to. */
87            inline IdentifierList& getChildren() const { return *this->children_; }
88
89            /** @returns true, if a branch of the class-hierarchy is being created, causing all new objects to store their parents. */
90            inline static bool isCreatingHierarchy() { return (hierarchyCreatingCounter_s > 0); }
91
92            /** @returns the network ID to identify a class through the network. */
93            inline const unsigned int getNetworkID() const { return this->classID_; }
94
95            /** @brief Sets the network ID to a new value. @param id The new value */
96            void setNetworkID(unsigned int id);
97
98            /** @returns the ConfigValueContainer of a variable, given by the string of its name. @param varname The name of the variable */
99            inline ConfigValueContainer* getConfigValueContainer(const std::string& varname)
100                { return this->configValues_[varname]; }
101
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 */
103            inline void setConfigValueContainer(const std::string& varname, ConfigValueContainer* container)
104                { this->configValues_[varname] = container; }
105
106        private:
107            Identifier();
108            Identifier(const Identifier& identifier) {} // don't copy
109            virtual ~Identifier();
110            void initialize(const IdentifierList* parents);
111
112            /**
113                @brief Increases the hierarchyCreatingCounter_s variable, causing all new objects to store their parents.
114            */
115            inline static void startCreatingHierarchy()
116            {
117                hierarchyCreatingCounter_s++;
118                COUT(4) << "*** Increased Hierarchy-Creating-Counter to " << hierarchyCreatingCounter_s << "\n";
119            }
120
121            /**
122                @brief Decreases the hierarchyCreatingCounter_s variable, causing the objects to stop storing their parents.
123            */
124            inline static void stopCreatingHierarchy()
125            {
126                hierarchyCreatingCounter_s--;
127                COUT(4) << "*** Decreased Hierarchy-Creating-Counter to " << hierarchyCreatingCounter_s << "\n";
128            }
129
130            IdentifierList parents_;                                    //!< The Parents of the class the Identifier belongs to
131            IdentifierList* children_;                                  //!< The Children of the class the Identifier belongs to
132
133            std::string name_;                                          //!< The name of the class the Identifier belongs to
134
135            BaseFactory* factory_;                                      //!< The Factory, able to create new objects of the given class (if available)
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)
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
141    };
142
143
144    // ###############################
145    // ###     ClassIdentifier     ###
146    // ###############################
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    */
153    template <class T>
154    class ClassIdentifier : public Identifier
155    {
156        public:
157            static ClassIdentifier<T>* registerClass(const IdentifierList* parents, const std::string& name, bool bRootClass);
158            static ClassIdentifier<T>* getIdentifier();
159            static void addObject(T* object);
160
161        private:
162            ClassIdentifier();
163            ClassIdentifier(const ClassIdentifier<T>& identifier) {} // don't copy
164            ~ClassIdentifier();
165
166            static ClassIdentifier<T>* pointer_s;       //!< A pointer to the singleton-object
167            ObjectList<T>* objects_;                    //!< The ObjectList, containing all objects of type T
168    };
169
170    template <class T>
171    ClassIdentifier<T>* ClassIdentifier<T>::pointer_s = NULL; // Set the static member variable pointer_s to zero
172
173    /**
174        @brief Constructor: Creates the ObjectList.
175    */
176    template <class T>
177    ClassIdentifier<T>::ClassIdentifier()
178    {
179        this->objects_ = new ObjectList<T>;
180    }
181
182    /**
183        @brief Destructor: Deletes the ObjectList, sets the singleton-pointer to zero.
184    */
185    template <class T>
186    ClassIdentifier<T>::~ClassIdentifier()
187    {
188        delete this->objects_;
189        this->pointer_s = NULL;
190    }
191
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
196        @param bRootClass True if the class is either an Interface or the BaseObject itself
197        @return The ClassIdentifier itself
198    */
199    template <class T>
200    ClassIdentifier<T>* ClassIdentifier<T>::registerClass(const IdentifierList* parents, const std::string& name, bool bRootClass)
201    {
202        COUT(4) << "*** Register Class in " << name << "-Singleton.\n";
203
204        // It's a singleton, so maybe we have to create it first
205        if (!pointer_s)
206        {
207            COUT(4) << "*** Register Class in " << name << "-Singleton -> Create Singleton.\n";
208            pointer_s = new ClassIdentifier();
209        }
210
211        // Check if at least one object of the given type was created
212        if (!pointer_s->bCreatedOneObject_)
213        {
214            // If no: We have to store the informations and initialize the Identifier
215
216            COUT(4) << "*** Register Class in " << name << "-Singleton -> Initialize Singleton.\n";
217            pointer_s->name_ = name;
218            Factory::add(name, pointer_s); // Add the Identifier to the Factory
219
220            if (bRootClass)
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.
222            else
223                pointer_s->initialize(parents);
224        }
225
226        return pointer_s;
227    }
228
229    /**
230        @returns the Identifier itself.
231    */
232    template <class T>
233    ClassIdentifier<T>* ClassIdentifier<T>::getIdentifier()
234    {
235        if (!pointer_s)
236        {
237            COUT(4) << "*** Create Singleton.\n";
238            pointer_s = new ClassIdentifier();
239        }
240
241        return pointer_s;
242    }
243
244    /**
245        @brief Adds an object of the given type to the ObjectList.
246        @param object The object to add
247    */
248    template <class T>
249    void ClassIdentifier<T>::addObject(T* object)
250    {
251        COUT(4) << "*** Added object to " << ClassIdentifier<T>::getIdentifier()->getName() << "-list.\n";
252        object->getMetaList().add(ClassIdentifier<T>::getIdentifier()->objects_, ClassIdentifier<T>::getIdentifier()->objects_->add(object));
253    }
254
255
256    // ###############################
257    // ###   SubclassIdentifier    ###
258    // ###############################
259    //! The SubclassIdentifier acts almost like an Identifier, but has some prerequisites.
260    /**
261        You can only assign an Identifier that belongs to a class T (or derived) to a SubclassIdentifier<T>.
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>
266    class SubclassIdentifier
267    {
268        public:
269            /**
270                @brief Constructor: Automaticaly assigns the Identifier of the given class.
271            */
272            SubclassIdentifier()
273            {
274                this->identifier_ = ClassIdentifier<T>::getIdentifier();
275            }
276
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)
283            {
284                if (!identifier->isA(ClassIdentifier<T>::getIdentifier()))
285                {
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";
289                    abort();
290                }
291                this->identifier_ = identifier;
292                return *this;
293            }
294
295            /**
296                @brief Overloading of the * operator: returns the assigned identifier.
297                @return The assigned identifier
298            */
299            Identifier* operator*()
300            {
301                return this->identifier_;
302            }
303
304            /**
305                @brief Overloading of the -> operator: returns the assigned identifier.
306                @return The assigned identifier
307            */
308            Identifier* operator->() const
309            {
310                return this->identifier_;
311            }
312
313            /**
314                @brief Creates a new object of the type of the assigned Identifier and dynamic_casts it to the minimal type given by T.
315                @return The new object
316            */
317            T* fabricate()
318            {
319                BaseObject* newObject = this->identifier_->fabricate();
320
321                // Check if the creation was successful
322                if (newObject)
323                {
324                    // Do a dynamic_cast, because an object of type T is much better than of type BaseObject
325                    return dynamic_cast<T*>(newObject);
326                }
327                else
328                {
329                    // Something went terribly wrong
330                    if (this->identifier_)
331                    {
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";
335                    }
336                    else
337                    {
338                        COUT(1) << "Error: Couldn't fabricate a new Object - Identifier is undefined.\n";
339                        COUT(1) << "Aborting...\n";
340                    }
341
342                    abort();
343                }
344            }
345
346            /** @returns the assigned identifier. */
347            inline const Identifier* getIdentifier() const
348                { return this->identifier_; }
349
350            /** @returns true, if the assigned identifier is at least of the given type. @param identifier The identifier to compare with */
351            inline bool isA(const Identifier* identifier) const
352                { return this->identifier_->isA(identifier); }
353
354            /** @returns true, if the assigned identifier is exactly of the given type. @param identifier The identifier to compare with */
355            inline bool isDirectlyA(const Identifier* identifier) const
356                { return this->identifier_->isDirectlyA(identifier); }
357
358            /** @returns true, if the assigned identifier is a child of the given identifier. @param identifier The identifier to compare with */
359            inline bool isChildOf(const Identifier* identifier) const
360                { return this->identifier_->isChildOf(identifier); }
361
362            /** @returns true, if the assigned identifier is a parent of the given identifier. @param identifier The identifier to compare with */
363            inline bool isParentOf(const Identifier* identifier) const
364                { return this->identifier_->isParentOf(identifier); }
365
366        private:
367            Identifier* identifier_;        //!< The assigned identifier
368    };
369}
370
371#endif
Note: See TracBrowser for help on using the repository browser.