Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

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

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

cleanup

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