Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: code/branches/cpp11_v2/src/libraries/core/class/IdentifierManager.cc @ 10920

Last change on this file since 10920 was 10916, checked in by landauf, 10 years ago

use actual types instead of 'auto'. only exception is for complicated template types, e.g. when iterating over a map

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