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)