Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

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

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