Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: code/branches/FICN/src/orxonox/core/Identifier.h @ 679

Last change on this file since 679 was 677, checked in by landauf, 18 years ago

changed \n to std::endl

File size: 16.4 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        friend class Factory; // Forward declaration
67
68        public:
69            /** @brief Sets the Factory.
70             *  @param factory The factory to assign
71             */
72            inline void addFactory(BaseFactory* factory) { this->factory_ = factory; }
73
74            BaseObject* fabricate();
75
76            bool isA(const Identifier* identifier) const;
77            bool isDirectlyA(const Identifier* identifier) const;
78            bool isChildOf(const Identifier* identifier) const;
79            bool isParentOf(const Identifier* identifier) const;
80
81            /** @returns the name of the class the Identifier belongs to. */
82            inline const std::string& getName() const { return this->name_; }
83
84            /** @returns the parents of the class the Identifier belongs to. */
85            inline const IdentifierList& getParents() const { return this->parents_; }
86
87            /** @returns the children of the class the Identifier belongs to. */
88            inline IdentifierList& getChildren() const { return *this->children_; }
89
90            /** @returns true, if a branch of the class-hierarchy is being created, causing all new objects to store their parents. */
91            inline static bool isCreatingHierarchy() { return (hierarchyCreatingCounter_s > 0); }
92
93            /** @returns the network ID to identify a class through the network. */
94            inline const unsigned int getNetworkID() const { return this->classID_; }
95
96            /** @brief Sets the network ID to a new value. @param id The new value */
97            void setNetworkID(unsigned int id);
98
99            /** @returns the ConfigValueContainer of a variable, given by the string of its name. @param varname The name of the variable */
100            inline ConfigValueContainer* getConfigValueContainer(const std::string& varname)
101                { return this->configValues_[varname]; }
102
103            /** @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 */
104            inline void setConfigValueContainer(const std::string& varname, ConfigValueContainer* container)
105                { this->configValues_[varname] = container; }
106
107        private:
108            Identifier();
109            Identifier(const Identifier& identifier) {} // don't copy
110            virtual ~Identifier();
111            void initialize(const IdentifierList* parents);
112
113            /**
114                @brief Increases the hierarchyCreatingCounter_s variable, causing all new objects to store their parents.
115            */
116            inline static void startCreatingHierarchy()
117            {
118                hierarchyCreatingCounter_s++;
119                COUT(4) << "*** Increased Hierarchy-Creating-Counter to " << hierarchyCreatingCounter_s << std::endl;
120            }
121
122            /**
123                @brief Decreases the hierarchyCreatingCounter_s variable, causing the objects to stop storing their parents.
124            */
125            inline static void stopCreatingHierarchy()
126            {
127                hierarchyCreatingCounter_s--;
128                COUT(4) << "*** Decreased Hierarchy-Creating-Counter to " << hierarchyCreatingCounter_s << std::endl;
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 (if available)
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 existing Identifiers
140            unsigned int classID_;                                      //!< The network ID to identify a class through the network
141            std::map<std::string, ConfigValueContainer*> configValues_; //!< A map to link the string of configurable variables with their ConfigValueContainer
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: Creates the ObjectList.
176    */
177    template <class T>
178    ClassIdentifier<T>::ClassIdentifier()
179    {
180        this->objects_ = new ObjectList<T>;
181    }
182
183    /**
184        @brief Destructor: Deletes the ObjectList, sets 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 the 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        COUT(4) << "*** Register Class in " << name << "-Singleton." << std::endl;
204
205        // It's a singleton, so maybe we have to create it first
206        if (!pointer_s)
207        {
208            COUT(4) << "*** Register Class in " << name << "-Singleton -> Create Singleton." << std::endl;
209            pointer_s = new ClassIdentifier();
210        }
211
212        // Check if at least one object of the given type was created
213        if (!pointer_s->bCreatedOneObject_)
214        {
215            // If no: We have to store the informations and initialize the Identifier
216            COUT(4) << "*** Register Class in " << name << "-Singleton -> Initialize Singleton." << std::endl;
217            pointer_s->name_ = name;
218            if (bRootClass)
219                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.
220            else
221                pointer_s->initialize(parents);
222        }
223
224        return pointer_s;
225    }
226
227    /**
228        @returns the Identifier itself.
229    */
230    template <class T>
231    ClassIdentifier<T>* ClassIdentifier<T>::getIdentifier()
232    {
233        if (!pointer_s)
234        {
235            COUT(4) << "*** Create Singleton." << std::endl;
236            pointer_s = new ClassIdentifier();
237        }
238
239        return pointer_s;
240    }
241
242    /**
243        @brief Adds an object of the given type to the ObjectList.
244        @param object The object to add
245    */
246    template <class T>
247    void ClassIdentifier<T>::addObject(T* object)
248    {
249        COUT(4) << "*** Added object to " << ClassIdentifier<T>::getIdentifier()->getName() << "-list." << std::endl;
250        object->getMetaList().add(ClassIdentifier<T>::getIdentifier()->objects_, ClassIdentifier<T>::getIdentifier()->objects_->add(object));
251    }
252
253
254    // ###############################
255    // ###   SubclassIdentifier    ###
256    // ###############################
257    //! The SubclassIdentifier acts almost like an Identifier, but has some prerequisites.
258    /**
259        You can only assign an Identifier that belongs to a class T (or derived) to a SubclassIdentifier<T>.
260        If you assign something else, the program aborts.
261        Because we know the minimal type, a dynamic_cast is done, which makes it easier to create a new object.
262    */
263    template <class T>
264    class SubclassIdentifier
265    {
266        public:
267            /**
268                @brief Constructor: Automaticaly assigns the Identifier of the given class.
269            */
270            SubclassIdentifier()
271            {
272                this->identifier_ = ClassIdentifier<T>::getIdentifier();
273            }
274
275            /**
276                @brief Overloading of the = operator: assigns the identifier and checks its type.
277                @param identifier The Identifier to assign
278                @return The SubclassIdentifier itself
279            */
280            SubclassIdentifier<T>& operator=(Identifier* identifier)
281            {
282                if (!identifier->isA(ClassIdentifier<T>::getIdentifier()))
283                {
284                    COUT(1) << "Error: Class " << identifier->getName() << " is not a " << ClassIdentifier<T>::getIdentifier()->getName() << "!" << std::endl;
285                    COUT(1) << "Error: SubclassIdentifier<" << ClassIdentifier<T>::getIdentifier()->getName() << "> = Class(" << identifier->getName() << ") is forbidden." << std::endl;
286                    COUT(1) << "Aborting..." << std::endl;
287                    abort();
288                }
289                this->identifier_ = identifier;
290                return *this;
291            }
292
293            /**
294                @brief Overloading of the * operator: returns the assigned identifier.
295                @return The assigned identifier
296            */
297            Identifier* operator*()
298            {
299                return this->identifier_;
300            }
301
302            /**
303                @brief Overloading of the -> operator: returns the assigned identifier.
304                @return The assigned identifier
305            */
306            Identifier* operator->() const
307            {
308                return this->identifier_;
309            }
310
311            /**
312                @brief Creates a new object of the type of the assigned Identifier and dynamic_casts it to the minimal type given by T.
313                @return The new object
314            */
315            T* fabricate()
316            {
317                BaseObject* newObject = this->identifier_->fabricate();
318
319                // Check if the creation was successful
320                if (newObject)
321                {
322                    // Do a dynamic_cast, because an object of type T is much better than of type BaseObject
323                    return dynamic_cast<T*>(newObject);
324                }
325                else
326                {
327                    // Something went terribly wrong
328                    if (this->identifier_)
329                    {
330                        COUT(1) << "Error: Class " << this->identifier_->getName() << " is not a " << ClassIdentifier<T>::getIdentifier()->getName() << "!" << std::endl;
331                        COUT(1) << "Error: Couldn't fabricate a new Object." << std::endl;
332                        COUT(1) << "Aborting..." << std::endl;
333                    }
334                    else
335                    {
336                        COUT(1) << "Error: Couldn't fabricate a new Object - Identifier is undefined." << std::endl;
337                        COUT(1) << "Aborting..." << std::endl;
338                    }
339
340                    abort();
341                }
342            }
343
344            /** @returns the assigned identifier. */
345            inline const Identifier* getIdentifier() const
346                { return this->identifier_; }
347
348            /** @returns true, if the assigned identifier is at least of the given type. @param identifier The identifier to compare with */
349            inline bool isA(const Identifier* identifier) const
350                { return this->identifier_->isA(identifier); }
351
352            /** @returns true, if the assigned identifier is exactly of the given type. @param identifier The identifier to compare with */
353            inline bool isDirectlyA(const Identifier* identifier) const
354                { return this->identifier_->isDirectlyA(identifier); }
355
356            /** @returns true, if the assigned identifier is a child of the given identifier. @param identifier The identifier to compare with */
357            inline bool isChildOf(const Identifier* identifier) const
358                { return this->identifier_->isChildOf(identifier); }
359
360            /** @returns true, if the assigned identifier is a parent of the given identifier. @param identifier The identifier to compare with */
361            inline bool isParentOf(const Identifier* identifier) const
362                { return this->identifier_->isParentOf(identifier); }
363
364        private:
365            Identifier* identifier_;        //!< The assigned identifier
366    };
367}
368
369#endif /* _Identifier_H__ */
Note: See TracBrowser for help on using the repository browser.