Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

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

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