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, 9 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.