Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

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

Last change on this file since 10375 was 10372, checked in by landauf, 10 years ago

use lists instead of sets to store parent identifiers. this allows to store the exact order of initialization of parent classes.

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