Index: source/simulation2/helpers/FlatMap.h =================================================================== --- /dev/null +++ source/simulation2/helpers/FlatMap.h @@ -0,0 +1,378 @@ +/* Copyright (C) 2020 Wildfire Games. + * This file is part of 0 A.D. + * + * 0 A.D. is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * 0 A.D. is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with 0 A.D. If not, see . + */ + +#ifndef INCLUDED_FLATMAP +#define INCLUDED_FLATMAP + +#include "lib/allocators/arena.h" + +#include +#include +#include + +/** + * Guarantees: + * - data is never moved + * - allocations are O(1), if reallocations are needed, they are constant-time. + * - deallocations are O(1) + * Other characteristics: + * - memory may be reused (if allocating m_Alignment bytes) + * - memory is only deallocated at destruction + * - only objects of size up to BLOCK_SIZE may be allocated + */ +template +class StablePool : public Allocators::DynamicArena +{ +public: + using typename Allocators::DynamicArena::storage_type; + using Allocators::DynamicArena::DynamicArena; + using Allocators::DynamicArena::m_Alignment; + using Allocators::DynamicArena::m_Data; + using Allocators::DynamicArena::m_NewestBlock; + using Allocators::DynamicArena::AllocateNewBlock; + + void* allocate(size_t n) + { + if (n == m_Alignment && !m_FreeSlots.empty()) + { + storage_type* ptr = m_FreeSlots.back(); + m_FreeSlots.pop_back(); + return ptr; + } + return Allocators::DynamicArena::allocate(n); + } + + void deallocate(void* p, size_t n) + { + for (int i = 0; i < n; i += m_Alignment) + m_FreeSlots.push_back((storage_type*)p + i); + // ENSURE(i == n); + } + + void clear() + { + Allocators::DynamicArena::clear(); + m_FreeSlots.clear(); + } +protected: + std::vector m_FreeSlots; +}; + +/** + * SparseFlatMap is a faster replacement for std::map and std::unordered_map. + * Requirements of T: T can be used as an array index. + * Requirements of V: movable + * Other requirements: + * - the iteration order must be deterministic to ensure network synchronicity and replays. + * + * The basic principle is to have a sparse vector of + * and a dense "data" vector of . + * + * Inserting is slightly slower than a vector because of the pointer book-keeping and the key storage. + * Erasing just sets the key to nullptr and swap-and-erases the data, to keep it dense. + * It's thus also slightly slower than a vector. + * Iteration happens over the dense data deque, so it's as fast as iterating a deque (really fast). + * Random Access means two dereferences, so in theory it's about as fast as a deque, which is is still really fast. + */ + +class TestFlatMap; + +template +class SparseFlatMapCore : protected StablePool, protected DispatchPolicy +{ + using StablePool::m_Data; + using StablePool::m_Alignment; + using StablePool::m_NewestBlock; + + using StablePool::allocate; + using StablePool::deallocate; +private: + friend class TestFlatMap; + static_assert(std::is_pointer_v, "V must be a pointer"); + +public: + + using key_type = T; + using mapped_type = std::remove_pointer_t; + using value_type = std::pair; + +protected: + // Use std::vector - assume the gain from direct access offsets the occasional cost of re-allocating. + using dispatch_container = typename DispatchPolicy::container; + + size_t m_Size = 0; +public: + + size_t get_storage_size(size_t size, size_t align) + { + return ROUND_UP(size + sizeof(key_type), std::max(align, alignof(key_type))); + } + + SparseFlatMapCore(size_t size, size_t align) : StablePool(get_storage_size(size, align)) + { + }; + + ~SparseFlatMapCore() + { + clear(); + }; + + //NONCOPYABLE(SparseFlatMapCore) + //NONMOVABLE(SparseFlatMapCore); + + template + class _pseudo_iterator + { + friend class SparseFlatMapCore; + friend class TestFlatMap; + + using ret_type = std::conditional_t, std::pair>; + + std::pair data; + + _pseudo_iterator(K k, M v) : data(k, v) {}; + public: + _pseudo_iterator(const _pseudo_iterator&) = default; + _pseudo_iterator(_pseudo_iterator&&) = default; + + ret_type* operator->() { return &data; } + ret_type& operator*() { return data; } + + bool operator==(const _pseudo_iterator& it) const { return data.second == it.data.second; }; + bool operator!=(const _pseudo_iterator& it) const { return data.second != it.data.second; }; + bool operator==(const _pseudo_iterator& it) const { return data.second == it.data.second; }; + bool operator!=(const _pseudo_iterator& it) const { return data.second != it.data.second; }; + }; + + template + class _iterator : public _pseudo_iterator + { + friend class SparseFlatMapCore; + friend class TestFlatMap; + using iter = typename std::deque::Block>::const_iterator; + iter it; + + uint32_t m_Alignment; + M end; + + using _pseudo_iterator::data; + + public: + //using _pseudo_iterator::operator==; + //using _pseudo_iterator::operator!=; + + _iterator(uint32_t al, K k, M v, iter i, M e) + : _pseudo_iterator(k, v), it(i), m_Alignment(al), end(e) {}; + + _iterator& operator++() + { + do + { + uint8_t* val = (uint8_t*)data.second; + if (val - std::addressof(it->block[0]) >= BLOCK_SIZE - m_Alignment*2) + data.second = (M)std::addressof((++it)->block[0]); + else + data.second = (M)(val + m_Alignment); + + data.first = *(key_type*)((uint8_t*)data.second + m_Alignment - sizeof(key_type)); + } while (data.first==0 && data.second != end); + return *this; + } + }; + + using iterator = _iterator; + using const_iterator = _iterator; + + using pseudo_iterator = _pseudo_iterator; + using const_pseudo_iterator = _pseudo_iterator; + + pseudo_iterator _it(const key_type& key) + { + size_t index = DispatchPolicy::Index(key); + dispatch_container& dispatch = DispatchPolicy::Dispatch(key); + return { key, dispatch[index] }; + } + + const_pseudo_iterator _cit(const key_type& key) const + { + size_t index = DispatchPolicy::Index(key); + const dispatch_container& dispatch = DispatchPolicy::Dispatch(key); + return { key, dispatch[index] }; + } + + iterator begin() + { + key_type* ptr = (key_type*)((uint8_t*)&m_Data[0].block[0] + m_Alignment - sizeof(key_type)); + if (*ptr == INVALID_KEY) + return ++iterator(m_Alignment, *ptr, (mapped_type*)&m_Data[0].block[0], m_Data.begin(), end()->second); + return iterator(m_Alignment, *ptr, (mapped_type*)&m_Data[0].block[0], m_Data.begin(), end()->second); + } + + const_iterator begin() const + { + key_type* ptr = (key_type*)((uint8_t*)&m_Data[0].block[0] + m_Alignment - sizeof(key_type)); + if (*ptr == INVALID_KEY) + return ++const_iterator(m_Alignment, *ptr, (mapped_type*)&m_Data[0].block[0], m_Data.begin(), end()->second); + return const_iterator(m_Alignment, *ptr, (mapped_type*)&m_Data[0].block[0], m_Data.begin(), end()->second); + } + + pseudo_iterator end() + { + return { INVALID_KEY, (mapped_type*)(&m_NewestBlock->block[0] + m_NewestBlock->size) }; + } + + const_pseudo_iterator end() const + { + return { INVALID_KEY, (mapped_type*)(&m_NewestBlock->block[0] + m_NewestBlock->size) }; + } + + bool empty() const { return m_Size == 0; } + size_t size() const { return m_Size; } + + template + std::pair try_emplace(mapped_type*(*constructor)(void*, Args...), const key_type& key, const Args&... args) + { + size_t index = DispatchPolicy::Index(key); + dispatch_container& dispatch = DispatchPolicy::Dispatch(key); + + if (index >= dispatch.size()) + dispatch.resize(index + 1, { nullptr }); + else if (dispatch[index] != nullptr) + return { end(), false }; + + void* slot = allocate(m_Alignment); + std::invoke(constructor, slot, args...); + // Store the key past the end. + *(key_type*)((uint8_t*)slot + m_Alignment - sizeof(key_type)) = key; + dispatch[index] = (mapped_type*)slot; + + ++m_Size; + + pseudo_iterator t = _it(key); + + return std::tuple(t, true); + } + + size_t erase(const pseudo_iterator& it) + { + return erase(it->first); + } + + size_t erase(const key_type& key) + { + size_t index = DispatchPolicy::Index(key); + dispatch_container& dispatch = DispatchPolicy::Dispatch(key); + + if (index >= dispatch.size() || dispatch[index] == nullptr) + return 0; + + --m_Size; + + dispatch[index]->~mapped_type(); + *(key_type*)((uint8_t*)dispatch[index] + m_Alignment - sizeof(key_type)) = INVALID_KEY; + deallocate(dispatch[index], m_Alignment); + dispatch[index] = nullptr; + + return 1; + } + + void clear() + { + for (std::pair& elem : *this) + elem.second->~mapped_type(); + StablePool::clear(); + DispatchPolicy::clear(); + } + + mapped_type& at(const key_type& key) + { + ENSURE(find(key) != end()); + return *find(key)->second; + } + + const mapped_type& at(const key_type& key) const + { + ENSURE(find(key) != end()); + return *find(key)->second; + } + + + pseudo_iterator find(const key_type& key) + { + size_t index = DispatchPolicy::Index(key); + dispatch_container& dispatch = DispatchPolicy::Dispatch(key); + if (index < dispatch.size() && dispatch[index] != nullptr) + return _it(key); + return end(); + } + + const_pseudo_iterator find(const key_type& key) const + { + size_t index = DispatchPolicy::Index(key); + const dispatch_container& dispatch = DispatchPolicy::Dispatch(key); + if (index < dispatch.size() && dispatch[index] != nullptr) + return _cit(key); + return end(); + } +}; + +template +class SingleDispatchPolicy +{ +protected: + using container = std::vector*>; + container m_Dispatch; + + SingleDispatchPolicy() { + m_Dispatch.reserve(4096); + } + + size_t Index(T key) const { return key; } + + container& Dispatch(T) { return m_Dispatch; } + const container& Dispatch(T) const { return m_Dispatch; } + + void clear() { m_Dispatch.clear(); } +}; + +template +class DoubleDispatchPolicy +{ +protected: + using container = std::vector*>; + container m_Dispatch1; + container m_Dispatch2; + + DoubleDispatchPolicy() { + m_Dispatch1.reserve(4096); + m_Dispatch2.reserve(4096); + } + + size_t Index(T key) const { return key >= SECOND_RANGE_START ? key - SECOND_RANGE_START : key; } + + container& Dispatch(T key) { return key >= SECOND_RANGE_START ? m_Dispatch2 : m_Dispatch1; } + const container& Dispatch(T key) const { return key >= SECOND_RANGE_START ? m_Dispatch2 : m_Dispatch1; } + + void clear() { m_Dispatch1.clear(); m_Dispatch2.clear(); } +}; + +template +using SparseFlatMap = SparseFlatMapCore, T, V, INVALID_KEY, BLOCK_SIZE>; +template +using DualSparseFlatMap = SparseFlatMapCore, T, V, INVALID_KEY, BLOCK_SIZE>; + +#endif // INCLUDED_FLATMAP Index: source/simulation2/helpers/FlatMap.cpp =================================================================== --- /dev/null +++ source/simulation2/helpers/FlatMap.cpp @@ -0,0 +1 @@ + Index: source/simulation2/helpers/tests/test_FlatMap.h =================================================================== --- /dev/null +++ source/simulation2/helpers/tests/test_FlatMap.h @@ -0,0 +1,109 @@ +/* Copyright (C) 2019 Wildfire Games. + * This file is part of 0 A.D. + * + * 0 A.D. is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * 0 A.D. is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with 0 A.D. If not, see . + */ + +#include "simulation2/helpers/FlatMap.h" + + +void DllLoader::OverrideLibdir(const char*) {}; + + +struct large +{ + virtual int get() { return 0; }; +}; + +struct child_large : public large +{ + virtual int get() { return toto[19]; }; + int toto[20]; +}; + +void debug_break() +{ + printf("FAIL"); +} + +ErrorReaction debug_OnAssertionFailure(wchar_t const*, long volatile*, wchar_t const*, int, char const*) +{ + printf("FAIL"); +} + + +large* alloc(void* spot, int v) +{ + child_large* ptr = new (spot) child_large; + ptr->toto[0] = v; + ptr->toto[19] = v; + return ptr; +} + +class TestFlatMap : public CxxTest::TestSuite +{ +public: + void setUp() + { + printf("start\n"); + } + + void tearDown() + { + } + + using Map = DualSparseFlatMap; + void test_insert() + { + Map test(300, alignof(child_large)); + + for (int i = 0; i < 3000; ++i) + test.try_emplace(&alloc, i, i); + + for (int i = 0; i < 3000; ++i) + TS_ASSERT(test.at(i).get() == i); + + for (int i = 0; i < 3000; ++i) + test.erase(i); + + for (int i = 0; i < 3000; ++i) + test.try_emplace(&alloc, i, i); + + for (int i = 2999; i >= 0; --i) + test.erase(i); + + for (int i = 2999; i >= 0; --i) + test.try_emplace(&alloc, i, i); + + for (int i = 0; i < 3000; ++i) + test.erase(i); + + for (auto& t : test) + TS_ASSERT(false); + + for (const auto& t : test) + TS_ASSERT(false); + + for (int i = 0; i < 30; ++i) + { + for (int j = 0; j < 100; ++j) + test.try_emplace(&alloc, i*100 + j, i*100 + j); + TS_ASSERT(test.find(i*100+49) != test.end()); + test.at(i*100+49).get() == i*100+49; + for (int j = 0; j < 100; ++j) + test.erase(i*100 + j); + TS_ASSERT(test.find(i*100+49) == test.end()); + } + } +}; Index: source/simulation2/system/Component.h =================================================================== --- source/simulation2/system/Component.h +++ source/simulation2/system/Component.h @@ -30,20 +30,20 @@ #define REGISTER_COMPONENT_TYPE(cname) \ void RegisterComponentType_##cname(CComponentManager& mgr) \ { \ - mgr.RegisterComponentType(CCmp##cname::GetInterfaceId(), CID_##cname, CCmp##cname::Allocate, CCmp##cname::Deallocate, #cname, CCmp##cname::GetSchema()); \ + mgr.RegisterComponentType(CCmp##cname::GetInterfaceId(), CID_##cname, CCmp##cname::Allocate, CCmp##cname::Deallocate, sizeof(CCmp##cname), alignof(CCmp##cname), #cname, CCmp##cname::GetSchema()); \ CCmp##cname::ClassInit(mgr); \ } #define REGISTER_COMPONENT_SCRIPT_WRAPPER(cname) \ void RegisterComponentType_##cname(CComponentManager& mgr) \ { \ - mgr.RegisterComponentTypeScriptWrapper(CCmp##cname::GetInterfaceId(), CID_##cname, CCmp##cname::Allocate, CCmp##cname::Deallocate, #cname, CCmp##cname::GetSchema()); \ +mgr.RegisterComponentTypeScriptWrapper(CCmp##cname::GetInterfaceId(), CID_##cname, CCmp##cname::Allocate, CCmp##cname::Deallocate, sizeof(CCmp##cname), alignof(CCmp##cname), #cname, CCmp##cname::GetSchema()); \ CCmp##cname::ClassInit(mgr); \ } #define DEFAULT_COMPONENT_ALLOCATOR(cname) \ - static IComponent* Allocate(const ScriptInterface&, JS::HandleValue) { return new CCmp##cname(); } \ - static void Deallocate(IComponent* cmp) { delete static_cast (cmp); } \ + static IComponent* Allocate(void* slot, const ScriptInterface&, JS::HandleValue) { return new (slot) CCmp##cname(); } \ + static void Deallocate(IComponent* cmp) { /*delete static_cast (cmp);*/ } \ virtual int GetComponentTypeId() const \ { \ return CID_##cname; \ @@ -51,13 +51,13 @@ #define DEFAULT_SCRIPT_WRAPPER(cname) \ static void ClassInit(CComponentManager& UNUSED(componentManager)) { } \ - static IComponent* Allocate(const ScriptInterface& scriptInterface, JS::HandleValue instance) \ + static IComponent* Allocate(void* slot, const ScriptInterface& scriptInterface, JS::HandleValue instance) \ { \ - return new CCmp##cname(scriptInterface, instance); \ + return new (slot) CCmp##cname(scriptInterface, instance); \ } \ static void Deallocate(IComponent* cmp) \ { \ - delete static_cast (cmp); \ + /*delete static_cast (cmp);*/ \ } \ CCmp##cname(const ScriptInterface& scriptInterface, JS::HandleValue instance) : m_Script(scriptInterface, instance) { } \ static std::string GetSchema() \ Index: source/simulation2/system/ComponentManager.h =================================================================== --- source/simulation2/system/ComponentManager.h +++ source/simulation2/system/ComponentManager.h @@ -20,6 +20,7 @@ #include "ps/Filesystem.h" #include "scriptinterface/ScriptInterface.h" +#include "simulation2/helpers/FlatMap.h" #include "simulation2/helpers/Player.h" #include "simulation2/system/Components.h" #include "simulation2/system/Entity.h" @@ -47,7 +48,7 @@ private: // Component allocation types - typedef IComponent* (*AllocFunc)(const ScriptInterface& scriptInterface, JS::HandleValue ctor); + using AllocFunc = IComponent* (*)(void* slot, const ScriptInterface& scriptInterface, JS::HandleValue ctor); typedef void (*DeallocFunc)(IComponent*); // ComponentTypes come in three types: @@ -68,6 +69,8 @@ InterfaceId iid; AllocFunc alloc; DeallocFunc dealloc; + size_t size; + size_t align; std::string name; std::string schema; // RelaxNG fragment std::unique_ptr ctor; // only valid if type == CT_Script @@ -89,8 +92,8 @@ void RegisterMessageType(MessageTypeId mtid, const char* name); - void RegisterComponentType(InterfaceId, ComponentTypeId, AllocFunc, DeallocFunc, const char*, const std::string& schema); - void RegisterComponentTypeScriptWrapper(InterfaceId, ComponentTypeId, AllocFunc, DeallocFunc, const char*, const std::string& schema); + void RegisterComponentType(InterfaceId, ComponentTypeId, AllocFunc, DeallocFunc, size_t, size_t, const char*, const std::string& schema); + void RegisterComponentTypeScriptWrapper(InterfaceId, ComponentTypeId, AllocFunc, DeallocFunc, size_t, size_t, const char*, const std::string& schema); void MarkScriptedComponentForSystemEntity(CComponentManager::ComponentTypeId cid); @@ -308,11 +311,13 @@ ComponentTypeId m_CurrentComponent; // used when loading component types bool m_CurrentlyHotloading; + using ComponentsMap = DualSparseFlatMap; + // TODO: some of these should be vectors std::map m_ComponentTypesById; std::vector m_ScriptedSystemComponents; std::vector > m_ComponentsByInterface; // indexed by InterfaceId - std::map > m_ComponentsByTypeId; + std::map m_ComponentsByTypeId; std::map > m_LocalMessageSubscriptions; std::map > m_GlobalMessageSubscriptions; std::map m_ComponentTypeIdsByName; Index: source/simulation2/system/ComponentManager.cpp =================================================================== --- source/simulation2/system/ComponentManager.cpp +++ source/simulation2/system/ComponentManager.cpp @@ -203,7 +203,7 @@ if (ctPrevious.iid != iid) { // ...though it only matters if any components exist with this type - if (!componentManager->m_ComponentsByTypeId[cid].empty()) + if (!componentManager->m_ComponentsByTypeId.at(cid).empty()) { ScriptException::Raise(rq, "Hotloading script component type mustn't change interface ID"); return; @@ -252,6 +252,8 @@ iid, ctWrapper.alloc, ctWrapper.dealloc, + ctWrapper.size, + ctWrapper.align, cname, schema, std::unique_ptr(new JS::PersistentRootedValue(rq.cx, ctor)) @@ -304,8 +306,8 @@ { // For every script component with this cid, we need to switch its // prototype from the old constructor's prototype property to the new one's - const std::map& comps = componentManager->m_ComponentsByTypeId[cid]; - std::map::const_iterator eit = comps.begin(); + const ComponentsMap& comps = componentManager->m_ComponentsByTypeId.at(cid); + ComponentsMap::const_iterator eit = comps.begin(); for (; eit != comps.end(); ++eit) { JS::RootedValue instance(rq.cx, eit->second->GetJSInstance()); @@ -503,10 +505,10 @@ m_DynamicMessageSubscriptionsNonsyncByComponent.clear(); // Delete all IComponents - std::map >::iterator iit = m_ComponentsByTypeId.begin(); + std::map::iterator iit = m_ComponentsByTypeId.begin(); for (; iit != m_ComponentsByTypeId.end(); ++iit) { - std::map::iterator eit = iit->second.begin(); + ComponentsMap::iterator eit = iit->second.begin(); for (; eit != iit->second.end(); ++eit) { eit->second->Deinit(); @@ -540,17 +542,17 @@ } void CComponentManager::RegisterComponentType(InterfaceId iid, ComponentTypeId cid, AllocFunc alloc, DeallocFunc dealloc, - const char* name, const std::string& schema) + size_t size, size_t align, const char* name, const std::string& schema) { - ComponentType c{ CT_Native, iid, alloc, dealloc, name, schema, std::unique_ptr() }; + ComponentType c{ CT_Native, iid, alloc, dealloc, size, align, name, schema, std::unique_ptr() }; m_ComponentTypesById.insert(std::make_pair(cid, std::move(c))); m_ComponentTypeIdsByName[name] = cid; } void CComponentManager::RegisterComponentTypeScriptWrapper(InterfaceId iid, ComponentTypeId cid, AllocFunc alloc, - DeallocFunc dealloc, const char* name, const std::string& schema) + DeallocFunc dealloc, size_t size, size_t align, const char* name, const std::string& schema) { - ComponentType c{ CT_ScriptWrapper, iid, alloc, dealloc, name, schema, std::unique_ptr() }; + ComponentType c{ CT_ScriptWrapper, iid, alloc, dealloc, size, align, name, schema, std::unique_ptr() }; m_ComponentTypesById.insert(std::make_pair(cid, std::move(c))); m_ComponentTypeIdsByName[name] = cid; // TODO: merge with RegisterComponentType @@ -755,7 +757,8 @@ return NULL; } - std::map& emap2 = m_ComponentsByTypeId[cid]; + auto toto = m_ComponentsByTypeId.try_emplace(cid, ct.size, ct.align); + ComponentsMap& emap2 = toto.first->second; // If this is a scripted component, construct the appropriate JS object first JS::RootedValue obj(rq.cx); @@ -770,7 +773,9 @@ } // Construct the new component - IComponent* component = ct.alloc(m_ScriptInterface, obj); + auto comp_ = emap2.try_emplace(ct.alloc, ent.GetId(), m_ScriptInterface, obj); + IComponent* component = comp_.first->second; + ENSURE(component); component->SetEntityHandle(ent); @@ -778,7 +783,7 @@ // Store a reference to the new component emap1.insert(std::make_pair(ent.GetId(), component)); - emap2.insert(std::make_pair(ent.GetId(), component)); + //emap2.insert(std::make_pair(ent.GetId(), component)); // TODO: We need to more careful about this - if an entity is constructed by a component // while we're iterating over all components, this will invalidate the iterators and everything // will break. @@ -930,10 +935,10 @@ FlattenDynamicSubscriptions(); // Destroy the components, and remove from m_ComponentsByTypeId: - std::map >::iterator iit = m_ComponentsByTypeId.begin(); + std::map::iterator iit = m_ComponentsByTypeId.begin(); for (; iit != m_ComponentsByTypeId.end(); ++iit) { - std::map::iterator eit = iit->second.find(ent); + ComponentsMap::pseudo_iterator eit = iit->second.find(ent); if (eit != iit->second.end()) { eit->second->Deinit(); @@ -1021,12 +1026,12 @@ for (; ctit != it->second.end(); ++ctit) { // Find the component instances of this type (if any) - std::map >::const_iterator emap = m_ComponentsByTypeId.find(*ctit); + std::map::iterator emap = m_ComponentsByTypeId.find(*ctit); if (emap == m_ComponentsByTypeId.end()) continue; // Send the message to all of them - std::map::const_iterator eit = emap->second.find(ent); + ComponentsMap::pseudo_iterator eit = emap->second.find(ent); if (eit != emap->second.end()) eit->second->HandleMessage(msg, false); } @@ -1046,12 +1051,12 @@ for (; ctit != it->second.end(); ++ctit) { // Find the component instances of this type (if any) - std::map >::const_iterator emap = m_ComponentsByTypeId.find(*ctit); + std::map::iterator emap = m_ComponentsByTypeId.find(*ctit); if (emap == m_ComponentsByTypeId.end()) continue; // Send the message to all of them - std::map::const_iterator eit = emap->second.begin(); + ComponentsMap::iterator eit = emap->second.begin(); for (; eit != emap->second.end(); ++eit) eit->second->HandleMessage(msg, false); } @@ -1085,12 +1090,12 @@ } // Find the component instances of this type (if any) - std::map >::const_iterator emap = m_ComponentsByTypeId.find(*ctit); + std::map::iterator emap = m_ComponentsByTypeId.find(*ctit); if (emap == m_ComponentsByTypeId.end()) continue; // Send the message to all of them - std::map::const_iterator eit = emap->second.begin(); + ComponentsMap::iterator eit = emap->second.begin(); for (; eit != emap->second.end(); ++eit) eit->second->HandleMessage(msg, true); } Index: source/simulation2/system/ComponentManagerSerialization.cpp =================================================================== --- source/simulation2/system/ComponentManagerSerialization.cpp +++ source/simulation2/system/ComponentManagerSerialization.cpp @@ -58,10 +58,10 @@ std::map > components; //std::map names; - std::map >::const_iterator ctit = m_ComponentsByTypeId.begin(); + std::map::const_iterator ctit = m_ComponentsByTypeId.begin(); for (; ctit != m_ComponentsByTypeId.end(); ++ctit) { - std::map::const_iterator eit = ctit->second.begin(); + ComponentsMap::const_iterator eit = ctit->second.begin(); for (; eit != ctit->second.end(); ++eit) { components[eit->first][ctit->first] = eit->second; @@ -109,7 +109,7 @@ serializer.StringASCII("rng", SerializeRNG(m_RNG), 0, 32); serializer.NumberU32_Unbounded("next entity id", m_NextEntityId); - std::map >::const_iterator cit = m_ComponentsByTypeId.begin(); + std::map::const_iterator cit = m_ComponentsByTypeId.begin(); for (; cit != m_ComponentsByTypeId.end(); ++cit) { // In quick mode, only check unit positions @@ -118,7 +118,7 @@ // Only emit component types if they have a component that will be serialized bool needsSerialization = false; - for (std::map::const_iterator eit = cit->second.begin(); eit != cit->second.end(); ++eit) + for (ComponentsMap::const_iterator eit = cit->second.begin(); eit != cit->second.end(); ++eit) { // Don't serialize local entities if (ENTITY_IS_LOCAL(eit->first)) @@ -133,7 +133,7 @@ serializer.NumberI32_Unbounded("component type id", cit->first); - for (std::map::const_iterator eit = cit->second.begin(); eit != cit->second.end(); ++eit) + for (ComponentsMap::const_iterator eit = cit->second.begin(); eit != cit->second.end(); ++eit) { // Don't serialize local entities if (ENTITY_IS_LOCAL(eit->first)) @@ -189,7 +189,7 @@ serializer.StringASCII("rng", SerializeRNG(m_RNG), 0, 32); serializer.NumberU32_Unbounded("next entity id", m_NextEntityId); - std::map >::const_iterator cit; + std::map::const_iterator cit; uint32_t numSystemComponentTypes = 0; uint32_t numComponentTypes = 0; @@ -200,7 +200,7 @@ { // Only emit component types if they have a component that will be serialized bool needsSerialization = false; - for (std::map::const_iterator eit = cit->second.begin(); eit != cit->second.end(); ++eit) + for (ComponentsMap::const_iterator eit = cit->second.begin(); eit != cit->second.end(); ++eit) { // Don't serialize local entities, and handle SYSTEM_ENTITY separately if (ENTITY_IS_LOCAL(eit->first) || eit->first == SYSTEM_ENTITY) @@ -239,7 +239,7 @@ serializer.StringASCII("name", ctit->second.name, 0, 255); - std::map::const_iterator eit = cit->second.find(SYSTEM_ENTITY); + ComponentsMap::const_pseudo_iterator eit = cit->second.find(SYSTEM_ENTITY); if (eit == cit->second.end()) { debug_warn(L"Invalid eit"); // this should never happen @@ -266,7 +266,7 @@ // Count the components before serializing any of them uint32_t numComponents = 0; - for (std::map::const_iterator eit = cit->second.begin(); eit != cit->second.end(); ++eit) + for (ComponentsMap::const_iterator eit = cit->second.begin(); eit != cit->second.end(); ++eit) { // Don't serialize local entities or SYSTEM_ENTITY if (ENTITY_IS_LOCAL(eit->first) || eit->first == SYSTEM_ENTITY) @@ -279,7 +279,7 @@ serializer.NumberU32_Unbounded("num components", numComponents); // Serialize the components now - for (std::map::const_iterator eit = cit->second.begin(); eit != cit->second.end(); ++eit) + for (ComponentsMap::const_iterator eit = cit->second.begin(); eit != cit->second.end(); ++eit) { // Don't serialize local entities or SYSTEM_ENTITY if (ENTITY_IS_LOCAL(eit->first) || eit->first == SYSTEM_ENTITY)