Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: code/branches/objecthierarchy2/src/core/Identifier.cc @ 2576

Last change on this file since 2576 was 2344, checked in by rgrieder, 16 years ago

Completed destruction of static elements like XMLPort, Identifier, etc.
Of initially about 250 memory leaks (not in the actual meaning but the memory was never freed anyway) only 1 remains in TinyCpp.

  • Core class is now a normal Singleton that gets created and destroyed in main.
  • The same goes for Language, LuaBind, SignalHandler and PlayerManager.
  • Added a new std::set to the CommandExecutor so that the external ConsoleCommands can get destroyed too.
  • Code for destroying CommandLineArguments
  • Added destruction code for ConstructionCallbacks in Identifier
  • Moved internal identifier map (the one with the typeid(.) names) in a static function in Identifier. This was necessary in order to destroy ALL Identifiers with the static destruction function. Before it was possible to create an Identifier with having a class instance (that would call RegisterObject) for instance by simply accessing it via getIdentifier.
  • Removed a big memory leak in Button (forgot to destroy the ConfigValueContainers)
  • Added destruction code for InputBufferListenerTuples in InputBuffer destructor.
  • Added destruction code for load and save executors in both XMLPortParam and XMLPortObject
  • Added destruction code for ConsoleCommands in GSRoot, GSGraphics and GSLevel (temporary solution anyway)
  • Deleting the CEGUILua script module seems to work properly now, one memory leak less (GUIManager.cc)
  • Added global destruction calls in Main.cc
  • Property svn:eol-style set to native
File size: 21.6 KB
Line 
1/*
2 *   ORXONOX - the hottest 3D action shooter ever to exist
3 *                    > www.orxonox.net <
4 *
5 *
6 *   License notice:
7 *
8 *   This program is free software; you can redistribute it and/or
9 *   modify it under the terms of the GNU General Public License
10 *   as published by the Free Software Foundation; either version 2
11 *   of the License, or (at your option) any later version.
12 *
13 *   This program is distributed in the hope that it will be useful,
14 *   but WITHOUT ANY WARRANTY; without even the implied warranty of
15 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16 *   GNU General Public License for more details.
17 *
18 *   You should have received a copy of the GNU General Public License
19 *   along with this program; if not, write to the Free Software
20 *   Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
21 *
22 *   Author:
23 *      Fabian 'x3n' Landau
24 *   Co-authors:
25 *      ...
26 *
27 */
28
29/**
30    @file
31    @brief Implementation of the Identifier class.
32*/
33
34#include "Identifier.h"
35
36#include <ostream>
37
38#include "Factory.h"
39#include "ConfigValueContainer.h"
40#include "ConsoleCommand.h"
41#include "CommandExecutor.h"
42#include "XMLPort.h"
43
44namespace orxonox
45{
46    // ###############################
47    // ###       Identifier        ###
48    // ###############################
49    int Identifier::hierarchyCreatingCounter_s = 0; // Set the static member variable hierarchyCreatingCounter_s to zero (this static member variable is ok: it's used in main(), not before)
50
51    /**
52        @brief Constructor: No factory, no object created, new ObjectList and a unique networkID.
53    */
54    Identifier::Identifier()
55    {
56        this->objects_ = new ObjectListBase(this);
57
58        this->bCreatedOneObject_ = false;
59        this->bSetName_ = false;
60        this->factory_ = 0;
61        this->bLoadable_ = true;
62
63        this->bHasConfigValues_ = false;
64        this->bHasConsoleCommands_ = false;
65        this->bHasConstructionCallback_ = false;
66
67        this->children_ = new std::set<const Identifier*>();
68        this->directChildren_ = new std::set<const Identifier*>();
69
70        // Use a static variable because the classID gets created before main() and that's why we should avoid static member variables
71        static unsigned int classIDcounter_s = 0;
72        this->classID_ = classIDcounter_s++;
73    }
74
75    /**
76        @brief Destructor: Deletes the list containing the children.
77    */
78    Identifier::~Identifier()
79    {
80        delete this->children_;
81        delete this->directChildren_;
82        delete this->objects_;
83
84        if (this->factory_)
85            delete this->factory_;
86
87        for (std::map<std::string, ConsoleCommand*>::iterator it = this->consoleCommands_.begin(); it != this->consoleCommands_.end(); ++it)
88            delete (it->second);
89        for (std::map<std::string, ConfigValueContainer*>::iterator it = this->configValues_.begin(); it != this->configValues_.end(); ++it)
90            delete (it->second);
91        for (std::map<std::string, XMLPortParamContainer*>::iterator it = this->xmlportParamContainers_.begin(); it != this->xmlportParamContainers_.end(); ++it)
92            delete (it->second);
93        for (std::map<std::string, XMLPortObjectContainer*>::iterator it = this->xmlportObjectContainers_.begin(); it != this->xmlportObjectContainers_.end(); ++it)
94            delete (it->second);
95        for (std::vector<Functor*>::iterator it = this->constructionCallbacks_.begin(); it != this->constructionCallbacks_.end(); ++it)
96            delete *it;
97    }
98
99    /**
100        @brief Returns the identifier map with the names as received by typeid(). This is only used internally.
101    */
102    std::map<std::string, Identifier*>& Identifier::getTypeIDIdentifierMap()
103    {
104        static std::map<std::string, Identifier*> identifiers;    //!< The map to store all Identifiers.
105        return identifiers;
106    }
107
108    /**
109        @brief Returns an identifier by name and adds it if not available
110        @param name The name of the identifier as typeid().name() suggests
111        @param proposal A pointer to a newly created identifier for the case of non existance in the map
112        @return The identifier (unique instance)
113    */
114    Identifier* Identifier::getIdentifierSingleton(const std::string& name, Identifier* proposal)
115    {
116        std::map<std::string, Identifier*>::const_iterator it = getTypeIDIdentifierMap().find(name);
117
118        if (it != getTypeIDIdentifierMap().end())
119        {
120            // There is already an entry: return it and delete the proposal
121            delete proposal;
122            return (*it).second;
123        }
124        else
125        {
126            // There is no entry: put the proposal into the map and return it
127            getTypeIDIdentifierMap()[name] = proposal;
128            return proposal;
129        }
130    }
131
132    /**
133        @brief Registers a class, which means that the name and the parents get stored.
134        @param parents A list, containing the Identifiers of all parents of the class
135        @param bRootClass True if the class is either an Interface or the BaseObject itself
136    */
137    void Identifier::initializeClassHierarchy(std::set<const Identifier*>* parents, bool bRootClass)
138    {
139        // Check if at least one object of the given type was created
140        if (!this->bCreatedOneObject_ && Identifier::isCreatingHierarchy())
141        {
142            // If no: We have to store the informations and initialize the Identifier
143            COUT(4) << "*** ClassIdentifier: Register Class in " << this->getName() << "-Singleton -> Initialize Singleton." << std::endl;
144            if (bRootClass)
145                this->initialize(0); // 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.
146            else
147                this->initialize(parents);
148        }
149    }
150
151    /**
152        @brief Initializes the Identifier with a list containing all parents of the class the Identifier belongs to.
153        @param parents A list containing all parents
154    */
155    void Identifier::initialize(std::set<const Identifier*>* parents)
156    {
157        COUT(4) << "*** Identifier: Initialize " << this->name_ << "-Singleton." << std::endl;
158        this->bCreatedOneObject_ = true;
159
160        if (parents)
161        {
162            this->parents_ = (*parents);
163            this->directParents_ = (*parents);
164
165            // Iterate through all parents
166            for (std::set<const Identifier*>::iterator it = parents->begin(); it != parents->end(); ++it)
167            {
168                // Tell the parent we're one of it's children
169                (*it)->getChildrenIntern().insert((*it)->getChildrenIntern().end(), this);
170
171                // Erase all parents of our parent from our direct-parent-list
172                for (std::set<const Identifier*>::const_iterator it1 = (*it)->getParents().begin(); it1 != (*it)->getParents().end(); ++it1)
173                {
174                    // Search for the parent's parent in our direct-parent-list
175                    for (std::set<const Identifier*>::iterator it2 = this->directParents_.begin(); it2 != this->directParents_.end(); ++it2)
176                    {
177                        if ((*it1) == (*it2))
178                        {
179                            // We've found a non-direct parent in our list: Erase it
180                            this->directParents_.erase(it2);
181                            break;
182                        }
183                    }
184                }
185            }
186
187            // Now iterate through all direct parents
188            for (std::set<const Identifier*>::iterator it = this->directParents_.begin(); it != this->directParents_.end(); ++it)
189            {
190                // Tell the parent we're one of it's direct children
191                (*it)->getDirectChildrenIntern().insert((*it)->getDirectChildrenIntern().end(), this);
192
193                // Create the super-function dependencies
194                (*it)->createSuperFunctionCaller();
195            }
196        }
197    }
198
199    /**
200        @brief Destroys all Identifiers. Called when exiting the program.
201    */
202    void Identifier::destroyAllIdentifiers()
203    {
204        for (std::map<std::string, Identifier*>::iterator it = Identifier::getTypeIDIdentifierMap().begin(); it != Identifier::getTypeIDIdentifierMap().end(); ++it)
205            delete (it->second);
206    }
207
208    /**
209        @brief Sets the name of the class.
210        @param name The name
211    */
212    void Identifier::setName(const std::string& name)
213    {
214        if (!this->bSetName_)
215        {
216            this->name_ = name;
217            this->bSetName_ = true;
218            Identifier::getIdentifierMapIntern()[name] = this;
219            Identifier::getLowercaseIdentifierMapIntern()[getLowercase(name)] = this;
220        }
221    }
222
223    /**
224        @brief Creates an object of the type the Identifier belongs to.
225        @return The new object
226    */
227    BaseObject* Identifier::fabricate(BaseObject* creator)
228    {
229        if (this->factory_)
230        {
231            return this->factory_->fabricate(creator); // We have to return a BaseObject, because we don't know the exact type.
232        }
233        else
234        {
235            COUT(1) << "An error occurred in Identifier.cc:" << std::endl;
236            COUT(1) << "Error: Cannot fabricate an object of type '" << this->name_ << "'. Class has no factory." << std::endl;
237            COUT(1) << "Aborting..." << std::endl;
238            abort();
239            return NULL;
240        }
241    }
242
243    /**
244        @brief Sets the network ID to a new value and changes the entry in the Factory.
245        @param id The new network ID
246    */
247    void Identifier::setNetworkID(unsigned int id)
248    {
249        Factory::changeNetworkID(this, this->classID_, id);
250        this->classID_ = id;
251    }
252
253    /**
254        @brief Returns true, if the Identifier is at least of the given type.
255        @param identifier The identifier to compare with
256    */
257    bool Identifier::isA(const Identifier* identifier) const
258    {
259        return (identifier == this || (this->parents_.find(identifier) != this->parents_.end()));
260    }
261
262    /**
263        @brief Returns true, if the Identifier is exactly of the given type.
264        @param identifier The identifier to compare with
265    */
266    bool Identifier::isExactlyA(const Identifier* identifier) const
267    {
268        return (identifier == this);
269    }
270
271    /**
272        @brief Returns true, if the assigned identifier is a child of the given identifier.
273        @param identifier The identifier to compare with
274    */
275    bool Identifier::isChildOf(const Identifier* identifier) const
276    {
277        return (this->parents_.find(identifier) != this->parents_.end());
278    }
279
280    /**
281        @brief Returns true, if the assigned identifier is a direct child of the given identifier.
282        @param identifier The identifier to compare with
283    */
284    bool Identifier::isDirectChildOf(const Identifier* identifier) const
285    {
286        return (this->directParents_.find(identifier) != this->directParents_.end());
287    }
288
289    /**
290        @brief Returns true, if the assigned identifier is a parent of the given identifier.
291        @param identifier The identifier to compare with
292    */
293    bool Identifier::isParentOf(const Identifier* identifier) const
294    {
295        return (this->children_->find(identifier) != this->children_->end());
296    }
297
298    /**
299        @brief Returns true, if the assigned identifier is a direct parent of the given identifier.
300        @param identifier The identifier to compare with
301    */
302    bool Identifier::isDirectParentOf(const Identifier* identifier) const
303    {
304        return (this->directChildren_->find(identifier) != this->directChildren_->end());
305    }
306
307    /**
308        @brief Returns the map that stores all Identifiers.
309        @return The map
310    */
311    std::map<std::string, Identifier*>& Identifier::getIdentifierMapIntern()
312    {
313        static std::map<std::string, Identifier*> identifierMap;
314        return identifierMap;
315    }
316
317    /**
318        @brief Returns the map that stores all Identifiers.
319        @return The map
320    */
321    std::map<std::string, Identifier*>& Identifier::getLowercaseIdentifierMapIntern()
322    {
323        static std::map<std::string, Identifier*> lowercaseIdentifierMap;
324        return lowercaseIdentifierMap;
325    }
326
327    /**
328        @brief Adds the ConfigValueContainer of a variable, given by the string of its name.
329        @param varname The name of the variablee
330        @param container The container
331    */
332    void Identifier::addConfigValueContainer(const std::string& varname, ConfigValueContainer* container)
333    {
334        std::map<std::string, ConfigValueContainer*>::const_iterator it = this->configValues_.find(varname);
335        if (it != this->configValues_.end())
336        {
337            COUT(2) << "Warning: Overwriting config-value with name " << varname << " in class " << this->getName() << "." << std::endl;
338            delete (it->second);
339        }
340
341        this->bHasConfigValues_ = true;
342        this->configValues_[varname] = container;
343        this->configValues_LC_[getLowercase(varname)] = container;
344    }
345
346    /**
347        @brief Returns the ConfigValueContainer of a variable, given by the string of its name.
348        @param varname The name of the variable
349        @return The ConfigValueContainer
350    */
351    ConfigValueContainer* Identifier::getConfigValueContainer(const std::string& varname)
352    {
353        std::map<std::string, ConfigValueContainer*>::const_iterator it = configValues_.find(varname);
354        if (it != configValues_.end())
355            return ((*it).second);
356        else
357            return 0;
358    }
359
360    /**
361        @brief Returns the ConfigValueContainer of a variable, given by the string of its name in lowercase.
362        @param varname The name of the variable in lowercase
363        @return The ConfigValueContainer
364    */
365    ConfigValueContainer* Identifier::getLowercaseConfigValueContainer(const std::string& varname)
366    {
367        std::map<std::string, ConfigValueContainer*>::const_iterator it = configValues_LC_.find(varname);
368        if (it != configValues_LC_.end())
369            return ((*it).second);
370        else
371            return 0;
372    }
373
374    /**
375        @brief Adds a new console command of this class.
376        @param executor The executor of the command
377        @param bCreateShortcut If this is true a shortcut gets created so you don't have to add the classname to access this command
378        @return The executor of the command
379    */
380    ConsoleCommand& Identifier::addConsoleCommand(ConsoleCommand* command, bool bCreateShortcut)
381    {
382        std::map<std::string, ConsoleCommand*>::const_iterator it = this->consoleCommands_.find(command->getName());
383        if (it != this->consoleCommands_.end())
384        {
385            COUT(2) << "Warning: Overwriting console-command with name " << command->getName() << " in class " << this->getName() << "." << std::endl;
386            delete (it->second);
387        }
388
389        this->bHasConsoleCommands_ = true;
390        this->consoleCommands_[command->getName()] = command;
391        this->consoleCommands_LC_[getLowercase(command->getName())] = command;
392
393        if (bCreateShortcut)
394            CommandExecutor::addConsoleCommandShortcut(command);
395
396        return (*command);
397    }
398
399    /**
400        @brief Returns the executor of a console command with given name.
401        @brief name The name of the requested console command
402        @return The executor of the requested console command
403    */
404    ConsoleCommand* Identifier::getConsoleCommand(const std::string& name) const
405    {
406        std::map<std::string, ConsoleCommand*>::const_iterator it = this->consoleCommands_.find(name);
407        if (it != this->consoleCommands_.end())
408            return (*it).second;
409        else
410            return 0;
411    }
412
413    /**
414        @brief Returns the executor of a console command with given name in lowercase.
415        @brief name The name of the requested console command in lowercae
416        @return The executor of the requested console command
417    */
418    ConsoleCommand* Identifier::getLowercaseConsoleCommand(const std::string& name) const
419    {
420        std::map<std::string, ConsoleCommand*>::const_iterator it = this->consoleCommands_LC_.find(name);
421        if (it != this->consoleCommands_LC_.end())
422            return (*it).second;
423        else
424            return 0;
425    }
426
427    /**
428        @brief Returns a XMLPortParamContainer that loads a parameter of this class.
429        @param paramname The name of the parameter
430        @return The container
431    */
432    XMLPortParamContainer* Identifier::getXMLPortParamContainer(const std::string& paramname)
433    {
434        std::map<std::string, XMLPortParamContainer*>::const_iterator it = this->xmlportParamContainers_.find(paramname);
435        if (it != this->xmlportParamContainers_.end())
436            return ((*it).second);
437        else
438            return 0;
439    }
440
441    /**
442        @brief Adds a new XMLPortParamContainer that loads a parameter of this class.
443        @param paramname The name of the parameter
444        @param container The container
445    */
446    void Identifier::addXMLPortParamContainer(const std::string& paramname, XMLPortParamContainer* container)
447    {
448        std::map<std::string, XMLPortParamContainer*>::const_iterator it = this->xmlportParamContainers_.find(paramname);
449        if (it != this->xmlportParamContainers_.end())
450        {
451            COUT(2) << "Warning: Overwriting XMLPortParamContainer in class " << this->getName() << "." << std::endl;
452            delete (it->second);
453        }
454
455        this->xmlportParamContainers_[paramname] = container;
456    }
457
458    /**
459        @brief Returns a XMLPortObjectContainer that attaches an object to this class.
460        @param sectionname The name of the section that contains the attachable objects
461        @return The container
462    */
463    XMLPortObjectContainer* Identifier::getXMLPortObjectContainer(const std::string& sectionname)
464    {
465        std::map<std::string, XMLPortObjectContainer*>::const_iterator it = this->xmlportObjectContainers_.find(sectionname);
466        if (it != this->xmlportObjectContainers_.end())
467            return ((*it).second);
468        else
469            return 0;
470    }
471
472    /**
473        @brief Adds a new XMLPortObjectContainer that attaches an object to this class.
474        @param sectionname The name of the section that contains the attachable objects
475        @param container The container
476    */
477    void Identifier::addXMLPortObjectContainer(const std::string& sectionname, XMLPortObjectContainer* container)
478    {
479        std::map<std::string, XMLPortObjectContainer*>::const_iterator it = this->xmlportObjectContainers_.find(sectionname);
480        if (it != this->xmlportObjectContainers_.end())
481        {
482            COUT(2) << "Warning: Overwriting XMLPortObjectContainer in class " << this->getName() << "." << std::endl;
483            delete (it->second);
484        }
485
486        this->xmlportObjectContainers_[sectionname] = container;
487    }
488
489    /**
490        @brief Returns a XMLPortEventContainer that attaches an event to this class.
491        @param sectionname The name of the section that contains the event
492        @return The container
493    */
494    XMLPortObjectContainer* Identifier::getXMLPortEventContainer(const std::string& eventname)
495    {
496        std::map<std::string, XMLPortObjectContainer*>::const_iterator it = this->xmlportEventContainers_.find(eventname);
497        if (it != this->xmlportEventContainers_.end())
498            return ((*it).second);
499        else
500            return 0;
501    }
502
503    /**
504        @brief Adds a new XMLPortEventContainer that attaches an event to this class.
505        @param sectionname The name of the section that contains the event
506        @param container The container
507    */
508    void Identifier::addXMLPortEventContainer(const std::string& eventname, XMLPortObjectContainer* container)
509    {
510        std::map<std::string, XMLPortObjectContainer*>::const_iterator it = this->xmlportEventContainers_.find(eventname);
511        if (it != this->xmlportEventContainers_.end())
512        {
513            COUT(2) << "Warning: Overwriting XMLPortEventContainer in class " << this->getName() << "." << std::endl;
514            delete (it->second);
515        }
516
517        this->xmlportEventContainers_[eventname] = container;
518    }
519
520    /**
521        @brief Adds a construction callback functor that gets called every time an object is created.
522        @param functor Functor pointer to any function with no argument.
523    */
524    void Identifier::addConstructionCallback(Functor* functor)
525    {
526        for (unsigned int i = 0; i < this->constructionCallbacks_.size(); ++i)
527        {
528            if (this->constructionCallbacks_[i] == functor)
529                return;
530        }
531        this->constructionCallbacks_.push_back(functor);
532        this->bHasConstructionCallback_ = true;
533    }
534
535    /**
536        @brief Removes a construction callback functor that gets called every time an object is created.
537        @param functor Functor pointer to any function with no argument.
538    */
539    void Identifier::removeConstructionCallback(Functor* functor)
540    {
541        for (unsigned int i = 0; i < this->constructionCallbacks_.size(); ++i)
542        {
543            if (this->constructionCallbacks_[i] == functor)
544            {
545                this->constructionCallbacks_.erase(this->constructionCallbacks_.begin() + i);
546            }
547        }
548        if (constructionCallbacks_.empty())
549            this->bHasConstructionCallback_ = false;
550    }
551
552    /**
553        @brief Lists the names of all Identifiers in a std::set<const Identifier*>.
554        @param out The outstream
555        @param list The list (or set) of Identifiers
556        @return The outstream
557    */
558    std::ostream& operator<<(std::ostream& out, const std::set<const Identifier*>& list)
559    {
560        for (std::set<const Identifier*>::const_iterator it = list.begin(); it != list.end(); ++it)
561            out << (*it)->getName() << " ";
562
563        return out;
564    }
565}
Note: See TracBrowser for help on using the repository browser.