Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

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

Last change on this file since 11071 was 11071, checked in by landauf, 8 years ago

merged branch cpp11_v3 back to trunk

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