Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: code/branches/core7/src/libraries/core/class/IdentifierManager.cc @ 10460

Last change on this file since 10460 was 10403, checked in by landauf, 9 years ago

added function to destroy the class hierarchy (i.e. reset all information about parents and children in Identifiers).
tests now use a fixture to create and destroy class hierarchy. this makes them independent of the order of execution (and also fixes the three *_NoFixture tests)

  • Property svn:eol-style set to native
File size: 10.9 KB
RevLine 
[790]1/*
2 *   ORXONOX - the hottest 3D action shooter ever to exist
[1505]3 *                    > www.orxonox.net <
[790]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
[871]29/**
[2171]30    @file
[790]31    @brief Implementation of the Identifier class.
32*/
33
[9564]34#include "IdentifierManager.h"
[1505]35
36#include <ostream>
37
[3280]38#include "util/StringUtils.h"
[10364]39#include "core/Core.h"
[9563]40#include "core/config/ConfigValueContainer.h"
41#include "core/XMLPort.h"
42#include "core/object/ClassFactory.h"
[790]43
44namespace orxonox
45{
[9667]46    /* static */ IdentifierManager& IdentifierManager::getInstance()
47    {
48        static IdentifierManager instance;
49        return instance;
50    }
[790]51
[9667]52    IdentifierManager::IdentifierManager()
[2662]53    {
[9667]54        this->hierarchyCreatingCounter_s = 0;
55        this->classIDCounter_s = 0;
[10370]56        this->recordTraceForIdentifier_ = NULL;
[2662]57    }
58
59    /**
[9667]60     * Registers the identifier in all maps of the IdentifierManager.
61     */
[10395]62    void IdentifierManager::addIdentifier(Identifier* identifier)
[9667]63    {
[10399]64        orxout(verbose, context::identifier) << "Adding identifier for " << identifier->getName() << " / " << identifier->getTypeInfo().name() << endl;
[10395]65
[10399]66        this->identifiers_.insert(identifier);
[10395]67        this->identifierByString_[identifier->getName()] = identifier;
68        this->identifierByLowercaseString_[getLowercase(identifier->getName())] = identifier;
69        this->identifierByNetworkId_[identifier->getNetworkID()] = identifier;
[9667]70    }
71
72    /**
[5929]73        @brief Creates the class-hierarchy by creating and destroying one object of each type.
74    */
[9564]75    void IdentifierManager::createClassHierarchy()
[5929]76    {
[8858]77        orxout(internal_status) << "Create class-hierarchy" << endl;
[9667]78        this->startCreatingHierarchy();
79
80        std::set<Identifier*> initializedIdentifiers;
81
82        // ensure root context exists before starting to create objects. if the root context is dynamically created while creating the class hierarchy, we
83        // would mistakenly assume the class of the currently created object inherits from Context
84        Context::getRootContext();
85
86        // iterate over all identifiers, create one instance of each class and initialize the identifiers
[5929]87        {
[9667]88            Context temporaryContext(NULL);
[10399]89            for (std::set<Identifier*>::const_iterator it = this->identifiers_.begin(); it != this->identifiers_.end(); ++it)
[5929]90            {
[10399]91                Identifier* identifier = (*it);
92
93                orxout(verbose, context::identifier) << "Initialize ClassIdentifier<" << identifier->getName() << ">-Singleton." << endl;
[9667]94                // To initialize the identifier, we create a new object and delete it afterwards.
[10399]95                if (identifier->hasFactory())
[9667]96                {
[10366]97                    this->identifierTraceOfNewObject_.clear();
[10399]98                    this->recordTraceForIdentifier_ = identifier;
[10370]99
[10399]100                    Identifiable* temp = identifier->fabricate(&temporaryContext);
[10370]101
102                    this->recordTraceForIdentifier_ = NULL;
103
[10399]104                    if (temp->getIdentifier() != identifier)
105                        orxout(internal_error) << "Newly created object of type " << identifier->getName() << " has unexpected identifier. Did you forget to use RegisterObject(classname)?" << endl;
[10363]106
[10399]107                    identifier->initializeParents(this->identifierTraceOfNewObject_[temp]);
[10363]108
[9667]109                    delete temp;
110                }
111
[10399]112                initializedIdentifiers.insert(identifier);
[5929]113            }
[9667]114
115            size_t numberOfObjects = temporaryContext.getObjectList<Listable>()->size();
116            if (numberOfObjects > 0)
117                orxout(internal_warning) << "There are still " << numberOfObjects << " listables left after creating the class hierarchy" << endl;
[5929]118        }
[9667]119
120        // finish the initialization of all identifiers
[10399]121        for (std::set<Identifier*>::const_iterator it = this->identifiers_.begin(); it != this->identifiers_.end(); ++it)
[9667]122        {
[10399]123            Identifier* identifier = (*it);
124
125            if (initializedIdentifiers.find(identifier) != initializedIdentifiers.end())
126                identifier->finishInitialization();
[9667]127            else
[10399]128                orxout(internal_error) << "Identifier was registered late and is not initialized: " << identifier->getName() << " / " << identifier->getTypeInfo().name() << endl;
[9667]129        }
130
[10364]131        // only check class hierarchy in dev mode because it's an expensive operation and it requires a developer to fix detected problems anyway.
[10365]132        if (!Core::exists() || Core::getInstance().inDevMode())
[10364]133            this->verifyClassHierarchy();
[10361]134
[9667]135        this->stopCreatingHierarchy();
[8858]136        orxout(internal_status) << "Finished class-hierarchy creation" << endl;
[5929]137    }
138
139    /**
[10361]140     * Verifies if the class hierarchy is consistent with the RTTI.
141     */
142    void IdentifierManager::verifyClassHierarchy()
143    {
144        Context temporaryContext(NULL);
[10399]145        for (std::set<Identifier*>::const_iterator it1 = this->identifiers_.begin(); it1 != this->identifiers_.end(); ++it1)
[10361]146        {
[10399]147            if (!(*it1)->hasFactory())
[10361]148                continue;
149
[10399]150            Identifiable* temp = (*it1)->fabricate(&temporaryContext);
[10361]151
[10399]152            for (std::set<Identifier*>::const_iterator it2 = this->identifiers_.begin(); it2 != this->identifiers_.end(); ++it2)
[10361]153            {
[10399]154                bool isA_AccordingToRtti = (*it2)->canDynamicCastObjectToIdentifierClass(temp);
155                bool isA_AccordingToClassHierarchy = temp->isA((*it2));
[10361]156
157                if (isA_AccordingToRtti != isA_AccordingToClassHierarchy)
158                {
[10399]159                    orxout(internal_error) << "Class hierarchy does not match RTTI: Class hierarchy claims that " << (*it1)->getName() <<
160                        (isA_AccordingToClassHierarchy ? " is a " : " is not a ") << (*it2)->getName() << " but RTTI says the opposite." << endl;
[10361]161                }
162            }
163
164            delete temp;
165        }
[10365]166        orxout(internal_info) << "Class hierarchy matches RTTI" << endl;
[10361]167
168        size_t numberOfObjects = temporaryContext.getObjectList<Listable>()->size();
169        if (numberOfObjects > 0)
170            orxout(internal_warning) << "There are still " << numberOfObjects << " listables left after creating the class hierarchy" << endl;
171    }
172
173    /**
[10403]174     * @brief Resets all Identifiers.
175     */
176    void IdentifierManager::destroyClassHierarchy()
[1747]177    {
[10403]178        orxout(internal_status) << "Destroy class-hierarchy" << endl;
179        for (std::set<Identifier*>::const_iterator it = this->identifiers_.begin(); it != this->identifiers_.end(); ++it)
180            (*it)->reset();
[1505]181    }
182
183    /**
[9667]184     * @brief Notifies the IdentifierManager about a newly created object while creating the class hierarchy.
185     */
186    void IdentifierManager::createdObject(Identifiable* identifiable)
[1505]187    {
[9667]188        if (this->isCreatingHierarchy())
[10370]189        {
190            if (this->recordTraceForIdentifier_)
191            {
[10372]192                std::list<const Identifier*>& traceForObject = this->identifierTraceOfNewObject_[identifiable];
193                if (std::find(traceForObject.begin(), traceForObject.end(), identifiable->getIdentifier()) != traceForObject.end())
[10370]194                {
195                    orxout(internal_warning) << this->recordTraceForIdentifier_->getName() << " inherits two times from " <<
196                        identifiable->getIdentifier()->getName() << ". Did you forget to use virtual inheritance?" << endl;
197                }
[10372]198                traceForObject.push_back(identifiable->getIdentifier());
[10370]199            }
200        }
[9667]201        else
202            orxout(internal_warning) << "createdObject() called outside of class hierarchy creation" << endl;
[1505]203    }
204
205    /**
[5929]206        @brief Returns the Identifier with a given name.
207        @param name The name of the wanted Identifier
208        @return The Identifier
209    */
[9564]210    Identifier* IdentifierManager::getIdentifierByString(const std::string& name)
[5929]211    {
[9667]212        std::map<std::string, Identifier*>::const_iterator it = this->identifierByString_.find(name);
213        if (it != this->identifierByString_.end())
[5929]214            return it->second;
215        else
216            return 0;
217    }
218
219    /**
220        @brief Returns the Identifier with a given name in lowercase.
221        @param name The name of the wanted Identifier
222        @return The Identifier
223    */
[9564]224    Identifier* IdentifierManager::getIdentifierByLowercaseString(const std::string& name)
[5929]225    {
[9667]226        std::map<std::string, Identifier*>::const_iterator it = this->identifierByLowercaseString_.find(name);
227        if (it != this->identifierByLowercaseString_.end())
[5929]228            return it->second;
229        else
230            return 0;
231    }
232
233    /**
234        @brief Returns the Identifier with a given network ID.
235        @param id The network ID of the wanted Identifier
236        @return The Identifier
237    */
[9564]238    Identifier* IdentifierManager::getIdentifierByID(const uint32_t id)
[5929]239    {
[9667]240        std::map<uint32_t, Identifier*>::const_iterator it = this->identifierByNetworkId_.find(id);
241        if (it != this->identifierByNetworkId_.end())
[5929]242            return it->second;
243        else
244            return 0;
245    }
246
247    /**
[10395]248        @brief Returns the Identifier with a given typeid-name.
249        @param name The typeid-name of the wanted Identifier
250        @return The Identifier
251    */
[10399]252    Identifier* IdentifierManager::getIdentifierByTypeInfo(const std::type_info& typeInfo)
[10395]253    {
[10399]254        // TODO: use std::type_index and a map to find identifiers by type_info (only with c++11)
255        for (std::set<Identifier*>::iterator it = this->identifiers_.begin(); it != this->identifiers_.end(); ++it)
256            if ((*it)->getTypeInfo() == typeInfo)
257                return (*it);
258        return 0;
[10395]259    }
260
261    /**
[5929]262        @brief Cleans the NetworkID map (needed on clients for correct initialization)
263    */
[9564]264    void IdentifierManager::clearNetworkIDs()
[5929]265    {
[9667]266        this->identifierByNetworkId_.clear();
[5929]267    }
[10403]268
269    /**
270        @brief Destroys all Identifiers. Called when exiting the program.
271    */
272    void IdentifierManager::destroyAllIdentifiers()
273    {
274        for (std::set<Identifier*>::iterator it = this->identifiers_.begin(); it != this->identifiers_.end(); ++it)
275            delete (*it);
276
277        this->identifiers_.clear();
278        this->identifierByString_.clear();
279        this->identifierByLowercaseString_.clear();
280        this->identifierByNetworkId_.clear();
281    }
[790]282}
Note: See TracBrowser for help on using the repository browser.