Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: code/trunk/src/libraries/core/class/IdentifierManager.cc @ 10624

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

merged branch core7 back to trunk

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