Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

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

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

more checks.

  • Property svn:eol-style set to native
File size: 11.0 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                else
136                    it->second->initializeDirectParentsOfAbstractClass();
137
138                initializedIdentifiers.insert(it->second);
139            }
140
141            size_t numberOfObjects = temporaryContext.getObjectList<Listable>()->size();
142            if (numberOfObjects > 0)
143                orxout(internal_warning) << "There are still " << numberOfObjects << " listables left after creating the class hierarchy" << endl;
144        }
145
146        // finish the initialization of all identifiers
147        for (std::map<std::string, Identifier*>::const_iterator it = this->identifierByTypeidName_.begin(); it != this->identifierByTypeidName_.end(); ++it)
148        {
149            if (initializedIdentifiers.find(it->second) != initializedIdentifiers.end())
150                it->second->finishInitialization();
151            else
152                orxout(internal_error) << "Identifier was registered late and is not initialized: " << it->second->getName() << " / " << it->second->getTypeidName() << endl;
153        }
154
155        // only check class hierarchy in dev mode because it's an expensive operation and it requires a developer to fix detected problems anyway.
156        if (!Core::exists() || Core::getInstance().inDevMode())
157            this->verifyClassHierarchy();
158
159        this->stopCreatingHierarchy();
160        orxout(internal_status) << "Finished class-hierarchy creation" << endl;
161    }
162
163    /**
164     * Verifies if the class hierarchy is consistent with the RTTI.
165     */
166    void IdentifierManager::verifyClassHierarchy()
167    {
168        Context temporaryContext(NULL);
169        for (std::map<std::string, Identifier*>::const_iterator it1 = this->identifierByTypeidName_.begin(); it1 != this->identifierByTypeidName_.end(); ++it1)
170        {
171            if (!it1->second->hasFactory())
172                continue;
173
174            Identifiable* temp = it1->second->fabricate(&temporaryContext);
175
176            for (std::map<std::string, Identifier*>::const_iterator it2 = this->identifierByTypeidName_.begin(); it2 != this->identifierByTypeidName_.end(); ++it2)
177            {
178                bool isA_AccordingToRtti = it2->second->canDynamicCastObjectToIdentifierClass(temp);
179                bool isA_AccordingToClassHierarchy = temp->isA(it2->second);
180
181                if (isA_AccordingToRtti != isA_AccordingToClassHierarchy)
182                {
183                    orxout(internal_error) << "Class hierarchy does not match RTTI: Class hierarchy claims that " << it1->second->getName() <<
184                        (isA_AccordingToClassHierarchy ? " is a " : " is not a ") << it2->second->getName() << " but RTTI says the opposite." << endl;
185                }
186            }
187
188            delete temp;
189        }
190        orxout(internal_info) << "Class hierarchy matches RTTI" << endl;
191
192        size_t numberOfObjects = temporaryContext.getObjectList<Listable>()->size();
193        if (numberOfObjects > 0)
194            orxout(internal_warning) << "There are still " << numberOfObjects << " listables left after creating the class hierarchy" << endl;
195    }
196
197    /**
198        @brief Destroys all Identifiers. Called when exiting the program.
199    */
200    void IdentifierManager::destroyAllIdentifiers()
201    {
202        for (std::map<std::string, Identifier*>::iterator it = this->identifierByTypeidName_.begin(); it != this->identifierByTypeidName_.end(); ++it)
203            delete (it->second);
204
205        this->identifierByTypeidName_.clear();
206        this->identifierByString_.clear();
207        this->identifierByLowercaseString_.clear();
208        this->identifierByNetworkId_.clear();
209    }
210
211    /**
212     * @brief Notifies the IdentifierManager about a newly created object while creating the class hierarchy.
213     */
214    void IdentifierManager::createdObject(Identifiable* identifiable)
215    {
216        if (this->isCreatingHierarchy())
217        {
218            if (this->recordTraceForIdentifier_)
219            {
220                if (this->identifierTraceOfNewObject_[identifiable].insert(identifiable->getIdentifier()).second == false)
221                {
222                    orxout(internal_warning) << this->recordTraceForIdentifier_->getName() << " inherits two times from " <<
223                        identifiable->getIdentifier()->getName() << ". Did you forget to use virtual inheritance?" << endl;
224                }
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.