Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

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

Last change on this file since 434 was 434, checked in by landauf, 16 years ago

added a config-file-parser and a makro ( SetConfigValue(variable, defaultvalue) ) to get user-modified values from the config-file (or to write the defaultvalue into it if the variable isn't yet in the file).

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