Ticket #4046: EntityMapForComponents.3.patch
File EntityMapForComponents.3.patch, 27.2 KB (added by , 8 years ago) |
---|
-
system/ComponentManager.cpp
20 20 #include "ComponentManager.h" 21 21 22 22 #include "DynamicSubscription.h" 23 #include "EntityMap.h" 23 24 #include "IComponent.h" 24 25 #include "ParamNode.h" 25 26 #include "SimContext.h" … … 305 306 { 306 307 // For every script component with this cid, we need to switch its 307 308 // prototype from the old constructor's prototype property to the new one's 308 const std::map<entity_id_t,IComponent*>& comps = componentManager->m_ComponentsByTypeId[cid];309 std::map<entity_id_t,IComponent*>::const_iterator eit = comps.begin();309 const GlobalEntityMap<IComponent*>& comps = componentManager->m_ComponentsByTypeId[cid]; 310 GlobalEntityMap<IComponent*>::const_iterator eit = comps.begin(); 310 311 for (; eit != comps.end(); ++eit) 311 312 { 312 313 JS::RootedValue instance(cx, eit->second->GetJSInstance()); … … 509 510 m_DynamicMessageSubscriptionsNonsyncByComponent.clear(); 510 511 511 512 // Delete all IComponents 512 std::map<ComponentTypeId, std::map<entity_id_t,IComponent*> >::iterator iit = m_ComponentsByTypeId.begin();513 std::map<ComponentTypeId, GlobalEntityMap<IComponent*> >::iterator iit = m_ComponentsByTypeId.begin(); 513 514 for (; iit != m_ComponentsByTypeId.end(); ++iit) 514 515 { 515 std::map<entity_id_t,IComponent*>::iterator eit = iit->second.begin();516 GlobalEntityMap<IComponent*>::iterator eit = iit->second.begin(); 516 517 for (; eit != iit->second.end(); ++eit) 517 518 { 518 519 eit->second->Deinit(); … … 757 758 return NULL; 758 759 } 759 760 760 std::map<entity_id_t,IComponent*>& emap2 = m_ComponentsByTypeId[cid];761 GlobalEntityMap<IComponent*>& emap2 = m_ComponentsByTypeId[cid]; 761 762 762 763 // If this is a scripted component, construct the appropriate JS object first 763 764 JS::RootedValue obj(cx); … … 780 781 781 782 // Store a reference to the new component 782 783 emap1.insert(std::make_pair(ent.GetId(), component)); 783 emap2.insert( std::make_pair(ent.GetId(), component));784 emap2.insert(ent.GetId(), component); 784 785 // TODO: We need to more careful about this - if an entity is constructed by a component 785 786 // while we're iterating over all components, this will invalidate the iterators and everything 786 787 // will break. … … 918 919 PostMessage(ent, msg); 919 920 920 921 // Destroy the components, and remove from m_ComponentsByTypeId: 921 std::map<ComponentTypeId, std::map<entity_id_t,IComponent*> >::iterator iit = m_ComponentsByTypeId.begin();922 std::map<ComponentTypeId, GlobalEntityMap<IComponent*> >::iterator iit = m_ComponentsByTypeId.begin(); 922 923 for (; iit != m_ComponentsByTypeId.end(); ++iit) 923 924 { 924 std::map<entity_id_t,IComponent*>::iterator eit = iit->second.find(ent);925 GlobalEntityMap<IComponent*>::iterator eit = iit->second.find(ent); 925 926 if (eit != iit->second.end()) 926 927 { 927 928 eit->second->Deinit(); … … 1007 1008 for (; ctit != it->second.end(); ++ctit) 1008 1009 { 1009 1010 // Find the component instances of this type (if any) 1010 std::map<ComponentTypeId, std::map<entity_id_t,IComponent*> >::const_iterator emap = m_ComponentsByTypeId.find(*ctit);1011 std::map<ComponentTypeId, GlobalEntityMap< IComponent*> >::const_iterator emap = m_ComponentsByTypeId.find(*ctit); 1011 1012 if (emap == m_ComponentsByTypeId.end()) 1012 1013 continue; 1013 1014 1014 1015 // Send the message to all of them 1015 std::map<entity_id_t,IComponent*>::const_iterator eit = emap->second.find(ent);1016 GlobalEntityMap<IComponent*>::const_iterator eit = emap->second.find(ent); 1016 1017 if (eit != emap->second.end()) 1017 1018 eit->second->HandleMessage(msg, false); 1018 1019 } … … 1032 1033 for (; ctit != it->second.end(); ++ctit) 1033 1034 { 1034 1035 // Find the component instances of this type (if any) 1035 std::map<ComponentTypeId, std::map<entity_id_t,IComponent*> >::const_iterator emap = m_ComponentsByTypeId.find(*ctit);1036 std::map<ComponentTypeId, GlobalEntityMap<IComponent*> >::const_iterator emap = m_ComponentsByTypeId.find(*ctit); 1036 1037 if (emap == m_ComponentsByTypeId.end()) 1037 1038 continue; 1038 1039 1039 1040 // Send the message to all of them 1040 std::map<entity_id_t,IComponent*>::const_iterator eit = emap->second.begin();1041 GlobalEntityMap<IComponent*>::const_iterator eit = emap->second.begin(); 1041 1042 for (; eit != emap->second.end(); ++eit) 1042 1043 eit->second->HandleMessage(msg, false); 1043 1044 } … … 1069 1070 } 1070 1071 1071 1072 // Find the component instances of this type (if any) 1072 std::map<ComponentTypeId, std::map<entity_id_t,IComponent*> >::const_iterator emap = m_ComponentsByTypeId.find(*ctit);1073 std::map<ComponentTypeId, GlobalEntityMap<IComponent*> >::const_iterator emap = m_ComponentsByTypeId.find(*ctit); 1073 1074 if (emap == m_ComponentsByTypeId.end()) 1074 1075 continue; 1075 1076 1076 1077 // Send the message to all of them 1077 std::map<entity_id_t,IComponent*>::const_iterator eit = emap->second.begin();1078 GlobalEntityMap<IComponent*>::const_iterator eit = emap->second.begin(); 1078 1079 for (; eit != emap->second.end(); ++eit) 1079 1080 eit->second->HandleMessage(msg, true); 1080 1081 } -
system/ComponentManager.h
35 35 class CSimContext; 36 36 class CDynamicSubscription; 37 37 38 template <class U> 39 class GlobalEntityMap; 40 38 41 class CComponentManager 39 42 { 40 43 NONCOPYABLE(CComponentManager); … … 355 358 std::map<ComponentTypeId, ComponentType> m_ComponentTypesById; 356 359 std::vector<CComponentManager::ComponentTypeId> m_ScriptedSystemComponents; 357 360 std::vector<boost::unordered_map<entity_id_t, IComponent*> > m_ComponentsByInterface; // indexed by InterfaceId 358 std::map<ComponentTypeId, std::map<entity_id_t,IComponent*> > m_ComponentsByTypeId;361 std::map<ComponentTypeId, GlobalEntityMap<IComponent*> > m_ComponentsByTypeId; 359 362 std::map<MessageTypeId, std::vector<ComponentTypeId> > m_LocalMessageSubscriptions; 360 363 std::map<MessageTypeId, std::vector<ComponentTypeId> > m_GlobalMessageSubscriptions; 361 364 std::map<std::string, ComponentTypeId> m_ComponentTypeIdsByName; -
system/ComponentManagerSerialization.cpp
18 18 #include "precompiled.h" 19 19 20 20 #include "ComponentManager.h" 21 #include "EntityMap.h" 21 22 #include "IComponent.h" 22 23 #include "ParamNode.h" 23 24 … … 58 59 std::map<entity_id_t, std::map<ComponentTypeId, IComponent*> > components; 59 60 //std::map<ComponentTypeId, std::string> names; 60 61 61 std::map<ComponentTypeId, std::map<entity_id_t,IComponent*> >::const_iterator ctit = m_ComponentsByTypeId.begin();62 std::map<ComponentTypeId, GlobalEntityMap<IComponent*> >::const_iterator ctit = m_ComponentsByTypeId.begin(); 62 63 for (; ctit != m_ComponentsByTypeId.end(); ++ctit) 63 64 { 64 std::map<entity_id_t,IComponent*>::const_iterator eit = ctit->second.begin();65 GlobalEntityMap<IComponent*>::const_iterator eit = ctit->second.begin(); 65 66 for (; eit != ctit->second.end(); ++eit) 66 67 { 67 components[eit->first][ctit->first] = eit->second; 68 if (ENTITY_IS_NORMAL(eit->first)) 69 components[eit->first][ctit->first] = eit->second; 70 else 71 components[eit->first][ctit->first] = eit->second; 68 72 } 69 73 } 70 74 … … 109 113 serializer.StringASCII("rng", SerializeRNG(m_RNG), 0, 32); 110 114 serializer.NumberU32_Unbounded("next entity id", m_NextEntityId); 111 115 112 std::map<ComponentTypeId, std::map<entity_id_t,IComponent*> >::const_iterator cit = m_ComponentsByTypeId.begin();116 std::map<ComponentTypeId, GlobalEntityMap<IComponent*> >::const_iterator cit = m_ComponentsByTypeId.begin(); 113 117 for (; cit != m_ComponentsByTypeId.end(); ++cit) 114 118 { 115 119 // In quick mode, only check unit positions … … 118 122 119 123 // Only emit component types if they have a component that will be serialized 120 124 bool needsSerialization = false; 121 for ( std::map<entity_id_t,IComponent*>::const_iterator eit = cit->second.begin(); eit != cit->second.end(); ++eit)125 for (GlobalEntityMap<IComponent*>::const_iterator eit = cit->second.begin(); eit != cit->second.end(); ++eit) 122 126 { 123 127 // Don't serialize local entities 124 128 if (ENTITY_IS_LOCAL(eit->first)) … … 133 137 134 138 serializer.NumberI32_Unbounded("component type id", cit->first); 135 139 136 for ( std::map<entity_id_t,IComponent*>::const_iterator eit = cit->second.begin(); eit != cit->second.end(); ++eit)140 for (GlobalEntityMap<IComponent*>::const_iterator eit = cit->second.begin(); eit != cit->second.end(); ++eit) 137 141 { 138 142 // Don't serialize local entities 139 143 if (ENTITY_IS_LOCAL(eit->first)) … … 188 192 serializer.StringASCII("rng", SerializeRNG(m_RNG), 0, 32); 189 193 serializer.NumberU32_Unbounded("next entity id", m_NextEntityId); 190 194 191 std::map<ComponentTypeId, std::map<entity_id_t,IComponent*> >::const_iterator cit;195 std::map<ComponentTypeId, GlobalEntityMap<IComponent*> >::const_iterator cit; 192 196 193 197 uint32_t numSystemComponentTypes = 0; 194 198 uint32_t numComponentTypes = 0; … … 199 203 { 200 204 // Only emit component types if they have a component that will be serialized 201 205 bool needsSerialization = false; 202 for ( std::map<entity_id_t,IComponent*>::const_iterator eit = cit->second.begin(); eit != cit->second.end(); ++eit)206 for (GlobalEntityMap<IComponent*>::const_iterator eit = cit->second.begin(); eit != cit->second.end(); ++eit) 203 207 { 204 208 // Don't serialize local entities, and handle SYSTEM_ENTITY separately 205 209 if (ENTITY_IS_LOCAL(eit->first) || eit->first == SYSTEM_ENTITY) … … 238 242 239 243 serializer.StringASCII("name", ctit->second.name, 0, 255); 240 244 241 std::map<entity_id_t,IComponent*>::const_iterator eit = cit->second.find(SYSTEM_ENTITY);245 GlobalEntityMap<IComponent*>::const_iterator eit = cit->second.find(SYSTEM_ENTITY); 242 246 if (eit == cit->second.end()) 243 247 { 244 248 debug_warn(L"Invalid eit"); // this should never happen … … 265 269 266 270 // Count the components before serializing any of them 267 271 uint32_t numComponents = 0; 268 for ( std::map<entity_id_t,IComponent*>::const_iterator eit = cit->second.begin(); eit != cit->second.end(); ++eit)272 for (GlobalEntityMap<IComponent*>::const_iterator eit = cit->second.begin(); eit != cit->second.end(); ++eit) 269 273 { 270 274 // Don't serialize local entities or SYSTEM_ENTITY 271 275 if (ENTITY_IS_LOCAL(eit->first) || eit->first == SYSTEM_ENTITY) … … 278 282 serializer.NumberU32_Unbounded("num components", numComponents); 279 283 280 284 // Serialize the components now 281 for ( std::map<entity_id_t,IComponent*>::const_iterator eit = cit->second.begin(); eit != cit->second.end(); ++eit)285 for (GlobalEntityMap<IComponent*>::const_iterator eit = cit->second.begin(); eit != cit->second.end(); ++eit) 282 286 { 283 287 // Don't serialize local entities or SYSTEM_ENTITY 284 288 if (ENTITY_IS_LOCAL(eit->first) || eit->first == SYSTEM_ENTITY) -
system/EntityMap.h
1 /* Copyright (C) 201 3Wildfire Games.1 /* Copyright (C) 2016 Wildfire Games. 2 2 * This file is part of 0 A.D. 3 3 * 4 4 * 0 A.D. is free software: you can redistribute it and/or modify … … 18 18 #define INCLUDED_ENTITYMAP 19 19 20 20 #include "Entity.h" 21 #include "simulation2/serialization/ISerializer.h" 22 #include "simulation2/serialization/IDeserializer.h" 21 23 22 24 /** 23 25 * A fast replacement for map<entity_id_t, T>. … … 48 50 size_t m_BufferCapacity; // capacity of the buffer 49 51 value_type* m_Buffer; // vector with all the mapped key-value pairs 50 52 53 size_t m_FirstEntityID; // real ID of the [0] in the buffer, so we can offset. 51 54 size_t m_Count; // number of 'valid' entity id's 52 55 53 56 public: 54 57 55 inline EntityMap() : m_BufferSize( 1), m_BufferCapacity(4096), m_Count(0)58 inline EntityMap() : m_BufferSize(0), m_BufferCapacity(4096), m_Count(0), m_FirstEntityID(1) 56 59 { 57 60 // for entitymap we allocate the buffer right away 58 61 // with first element in buffer being the Invalid Entity 59 62 m_Buffer = (value_type*)malloc(sizeof(value_type) * (m_BufferCapacity + 1)); 60 63 61 // create the first element: 62 m_Buffer[0].first = INVALID_ENTITY; 63 m_Buffer[1].first = 0xFFFFFFFF; // ensure end() always has 0xFFFFFFFF 64 m_Buffer[0].first = 0xFFFFFFFF; // ensure end() always has 0xFFFFFFFF 64 65 } 66 inline EntityMap(size_t ID) : EntityMap() 67 { 68 m_FirstEntityID = ID; 69 } 70 65 71 inline ~EntityMap() 66 72 { 67 73 free(m_Buffer); … … 97 103 98 104 inline iterator begin() 99 105 { 100 value_type* ptr = m_Buffer + 1; // skip the first INVALID_ENTITY106 value_type* ptr = m_Buffer; 101 107 while (ptr->first == INVALID_ENTITY) ++ptr; // skip any other invalid entities 102 108 return ptr; 103 109 } … … 107 113 } 108 114 inline const_iterator begin() const 109 115 { 110 value_type* ptr = m_Buffer + 1; // skip the first INVALID_ENTITY116 value_type* ptr = m_Buffer; 111 117 while (ptr->first == INVALID_ENTITY) ++ptr; // skip any other invalid entities 112 118 return ptr; 113 119 } … … 121 127 inline size_t size() const { return m_Count; } 122 128 123 129 // Modification 124 void insert(const key_type key, const mapped_type& value)130 void insert(const key_type actual_key, const mapped_type& value) 125 131 { 132 key_type key = actual_key - m_FirstEntityID; 126 133 if (key >= m_BufferCapacity) // do we need to resize buffer? 127 134 { 128 135 size_t newCapacity = m_BufferCapacity + 4096; … … 143 150 fill_gaps: 144 151 // set all entity id's to INVALID_ENTITY inside the new range 145 152 for (size_t i = m_BufferSize; i <= key; ++i) 153 { 146 154 m_Buffer[i].first = INVALID_ENTITY; 155 new (&m_Buffer[i].second) mapped_type(); 156 } 147 157 m_BufferSize = key; // extend the new size 148 158 } 149 159 150 160 value_type& item = m_Buffer[key]; 151 161 key_type oldKey = item.first; 152 item.first = key;162 item.first = actual_key; 153 163 if (key == m_BufferSize) // push_back 154 164 { 155 165 ++m_BufferSize; // expand … … 157 167 new (&item.second) mapped_type(value); // copy ctor to init 158 168 m_Buffer[m_BufferSize].first = 0xFFFFFFFF; // ensure end() always has 0xFFFFFFFF 159 169 } 160 else if(!item.first) // insert new to middle161 {162 ++m_Count;163 new (&item.second) mapped_type(value); // copy ctor to init164 }165 170 else // set existing value 166 171 { 167 172 if (oldKey == INVALID_ENTITY) 168 173 m_Count++; 169 item.second = value; // overwrite existing174 item.second = value; 170 175 } 171 176 } 172 177 … … 182 187 } 183 188 void erase(const entity_id_t key) 184 189 { 185 if (key < m_BufferSize)190 if (key - m_FirstEntityID < m_BufferSize) 186 191 { 187 value_type* ptr = m_Buffer + key ;192 value_type* ptr = m_Buffer + key - m_FirstEntityID; 188 193 if (ptr->first != INVALID_ENTITY) 189 194 { 190 195 ptr->first = INVALID_ENTITY; … … 210 215 } 211 216 212 217 // Operations 218 inline iterator operator[](const entity_id_t key) 219 { 220 return m_Buffer + key - m_FirstEntityID; 221 }; 222 inline const_iterator operator[](const entity_id_t key) const 223 { 224 return m_Buffer + key - m_FirstEntityID; 225 }; 213 226 inline iterator find(const entity_id_t key) 214 227 { 215 if (key < m_BufferSize) // is this key in the range of existing entitites?228 if (key - m_FirstEntityID >= 0 && key - m_FirstEntityID < m_BufferSize) // is this key in the range of existing entitites? 216 229 { 217 value_type* ptr = m_Buffer + key ;230 value_type* ptr = m_Buffer + key - m_FirstEntityID; 218 231 if (ptr->first != INVALID_ENTITY) 219 232 return ptr; 220 233 } … … 222 235 } 223 236 inline const_iterator find(const entity_id_t key) const 224 237 { 225 if (key < m_BufferSize) // is this key in the range of existing entitites?238 if (key - m_FirstEntityID >= 0 && key - m_FirstEntityID < m_BufferSize) // is this key in the range of existing entitites? 226 239 { 227 const value_type* ptr = m_Buffer + key ;240 const value_type* ptr = m_Buffer + key - m_FirstEntityID; 228 241 if (ptr->first != INVALID_ENTITY) 229 242 return ptr; 230 243 } … … 232 245 } 233 246 inline size_t count(const entity_id_t key) const 234 247 { 235 if (key < m_BufferSize)248 if (key - m_FirstEntityID >= 0 && key - m_FirstEntityID < m_BufferSize) 236 249 { 237 if (m_Buffer[key ].first != INVALID_ENTITY)250 if (m_Buffer[key - m_FirstEntityID].first != INVALID_ENTITY) 238 251 return 1; 239 252 } 240 253 return 0; … … 278 291 } 279 292 }; 280 293 294 //Implements the same interface as EntityMap but uses two internally to separate local entities 295 template<class T> 296 class GlobalEntityMap 297 { 298 protected: 281 299 300 public: 301 EntityMap<T> m_Entities; 302 EntityMap<T> m_LocalEntities; 303 304 inline GlobalEntityMap() : m_LocalEntities(ENTITY_TAGMASK) {} 305 306 typedef typename EntityMap<T>::mapped_type mapped_type; 307 typedef typename EntityMap<T>::key_type key_type; 308 typedef typename EntityMap<T>::value_type value_type; 309 310 // iterator aware of GlobalEntityMap to jump between the two vectors 311 template<class U, class V, class W> struct _iter : public std::iterator<std::forward_iterator_tag, U> 312 { 313 U* val; 314 V* orig; 315 inline _iter(V* mapInit) : orig(mapInit), val(orig.begin()) {} 316 inline _iter(V* mapInit, U* init) : orig(mapInit), val(init) {} 317 inline _iter(V* mapInit, W& init) : orig(mapInit), val(&*init) {} 318 inline U& operator*() { return *val; } 319 inline U* operator->() { return val; } 320 inline _iter& operator++() // ++it 321 { 322 ++val; 323 while (val->first == INVALID_ENTITY) ++val; 324 auto end = &*orig->m_Entities.end(); 325 auto toto = &*orig->m_LocalEntities.begin(); 326 auto realtoto = &*orig->m_LocalEntities.end(); 327 if (val == &*orig->m_Entities.end()) 328 val = &*orig->m_LocalEntities.begin(); 329 while (val->first == INVALID_ENTITY) ++val; 330 return *this; 331 } 332 inline _iter& operator++(int) // it++ 333 { 334 U* ptr = val; 335 ++val; 336 while (val->first == INVALID_ENTITY) ++val; // skip any invalid entities 337 if (val == &*orig->m_Entities.end()) 338 val = &*orig->m_LocalEntities.begin(); 339 while (val->first == INVALID_ENTITY) ++val; 340 return ptr; 341 } 342 inline bool operator==(_iter other) { return val == other.val; } 343 inline bool operator!=(_iter other) { return val != other.val; } 344 inline operator _iter<U const, V const, W const>() const { return _iter<U const, V const, W const>(orig, val); } 345 }; 346 347 typedef _iter<value_type, GlobalEntityMap, typename EntityMap<T>::iterator> iterator; 348 typedef _iter<value_type const, GlobalEntityMap const, typename EntityMap<T>::const_iterator> const_iterator; 349 350 inline iterator begin() 351 { 352 if (m_Entities.empty()) 353 return iterator(this, m_LocalEntities.begin()); 354 return iterator(this, m_Entities.begin()); 355 } 356 inline iterator end() 357 { 358 return iterator(this, m_LocalEntities.end()); 359 } 360 inline const_iterator begin() const 361 { 362 if (m_Entities.empty()) 363 return const_iterator(this, m_LocalEntities.begin()); 364 return const_iterator(this, m_Entities.begin()); 365 } 366 inline const_iterator end() const 367 { 368 return const_iterator(this, m_LocalEntities.end()); 369 } 370 371 // Size 372 inline bool empty() const { return m_Entities.empty() && m_LocalEntities.empty(); } 373 inline size_t size() const { return m_Entities.size() + m_LocalEntities.size(); } 374 375 // Modification 376 void insert(const key_type key, const mapped_type& value) 377 { 378 if (key < ENTITY_TAGMASK) 379 m_Entities.insert(key, value); 380 else 381 m_LocalEntities.insert(key, value); 382 } 383 384 void erase(iterator it) 385 { 386 if ((*it)->first < ENTITY_TAGMASK) 387 m_Entities.erase(it); 388 else 389 m_LocalEntities.erase(it); 390 } 391 void erase(const entity_id_t key) 392 { 393 if (key < ENTITY_TAGMASK) 394 m_Entities.erase(key); 395 else 396 m_LocalEntities.erase(key); 397 } 398 inline void clear() 399 { 400 m_Entities.clear(); 401 m_LocalEntities.clear(); 402 } 403 404 // Operations 405 inline iterator operator[](const entity_id_t key) 406 { 407 if (key < ENTITY_TAGMASK) 408 return iterator(this, m_Entities[key]); 409 else 410 return iterator(this, m_LocalEntities[key]); 411 }; 412 inline const_iterator operator[](const entity_id_t key) const 413 { 414 if (key < ENTITY_TAGMASK) 415 return const_iterator(this, m_Entities[key]); 416 else 417 return const_iterator(this, m_LocalEntities[key]); 418 }; 419 inline iterator find(const entity_id_t key) 420 { 421 if (key < ENTITY_TAGMASK) 422 { 423 iterator ret(this, m_Entities.find(key)); 424 if (&*ret == &*m_Entities.end()) 425 return end(); 426 return ret; 427 } 428 else 429 return iterator(this, m_LocalEntities.find(key)); 430 } 431 inline const_iterator find(const entity_id_t key) const 432 { 433 if (key < ENTITY_TAGMASK) 434 { 435 const_iterator ret(this, m_Entities.find(key)); 436 if (&*ret == &*m_Entities.end()) 437 return end(); 438 return ret; 439 } 440 else 441 return const_iterator(this, m_LocalEntities.find(key)); 442 } 443 inline size_t count(const entity_id_t key) const 444 { 445 if (key < ENTITY_TAGMASK) 446 return m_Entities.count(key); 447 else 448 return m_LocalEntities.count(key); 449 } 450 }; 451 452 template<class VSerializer> 453 struct SerializeGlobalEntityMap 454 { 455 template<class V> 456 void operator()(ISerializer& serialize, const char* UNUSED(name), GlobalEntityMap<V>& value) 457 { 458 size_t len = value.size(); 459 serialize.NumberU32_Unbounded("length", (u32)len); 460 size_t locallen = value.localSize(); 461 serialize.NumberU32_Unbounded("localLength", (u32)locallen); 462 size_t count = 0; 463 for (typename EntityMap<V>::iterator it = value.begin(); it != value.end(); ++it) 464 { 465 serialize.NumberU32_Unbounded("key", it->first); 466 VSerializer()(serialize, "value", it->second); 467 count++; 468 } 469 // test to see if the entityMap count wasn't wrong 470 // (which causes a crashing deserialisation) 471 ENSURE(count == len); 472 } 473 474 template<class V> 475 void operator()(IDeserializer& deserialize, const char* UNUSED(name), GlobalEntityMap<V>& value) 476 { 477 value.clear(); 478 uint32_t len, locallen; 479 deserialize.NumberU32_Unbounded("length", len); 480 deserialize.NumberU32_Unbounded("localLength", locallen); 481 for (size_t i = 0; i < len; ++i) 482 { 483 entity_id_t k; 484 V v; 485 deserialize.NumberU32_Unbounded("key", k); 486 VSerializer()(deserialize, "value", v); 487 if (i >= len - locallen) 488 k = k | ENTITY_TAGMASK; 489 value.insert(k, v); 490 } 491 } 492 }; 493 282 494 #endif -
tests/test_EntityMap.h
1 /* Copyright (C) 2016 Wildfire Games. 2 * This file is part of 0 A.D. 3 * 4 * 0 A.D. is free software: you can redistribute it and/or modify 5 * it under the terms of the GNU General Public License as published by 6 * the Free Software Foundation, either version 2 of the License, or 7 * (at your option) any later version. 8 * 9 * 0 A.D. is distributed in the hope that it will be useful, 10 * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 * GNU General Public License for more details. 13 * 14 * You should have received a copy of the GNU General Public License 15 * along with 0 A.D. If not, see <http://www.gnu.org/licenses/>. 16 */ 17 18 #include "lib/self_test.h" 19 20 #include <array> 21 #include "simulation2/system/EntityMap.h" 22 23 #include <iostream> 24 25 // Test the EntityMap container using the GlobalEntityMap, which uses EntityMap internally. 26 class TestEntityMap : public CxxTest::TestSuite 27 { 28 GlobalEntityMap<int* > map; 29 std::vector<int> verif; 30 31 void clear() 32 { 33 map.clear(); 34 verif.clear(); 35 } 36 public: 37 void test_TestClear() 38 { 39 for (size_t i = 1; i <= 20; ++i) 40 map.insert(i, verif.data()); 41 map.clear(); 42 TS_ASSERT_EQUALS(map.size(), 0); 43 TS_ASSERT_EQUALS(map.begin(), map.end()) 44 } 45 46 void test_TestInsert() 47 { 48 clear(); 49 // insert items in key positions and verify they are retrieved correctly 50 // I don't actually care about the values, so store pointers in the EntityMap 51 verif = std::vector<int>(20); 52 53 for (size_t i = 1; i <= 20; ++i) 54 map.insert(i, verif.data() + i); 55 56 TS_ASSERT_EQUALS(map.size(), 20); 57 58 for (size_t i = 1; i <= 20; ++i) 59 TS_ASSERT_EQUALS(map[i]->second, verif.data() + i); 60 61 map.insert(1, verif.data()); 62 map.insert(5, verif.data() + 1); 63 map.insert(1500, verif.data() + 2); 64 65 TS_ASSERT_EQUALS(map[1]->second, verif.data()); 66 TS_ASSERT_EQUALS(map[5]->second, verif.data()+1); 67 TS_ASSERT_EQUALS(map[1500]->second, verif.data()+2); 68 69 // check that we properly pad 70 TS_ASSERT_EQUALS(map[1300]->first, INVALID_ENTITY); 71 } 72 void test_TestLargeInsert() 73 { 74 clear(); 75 verif = std::vector<int>(21); 76 77 for (size_t i = 1; i <= 10; ++i) 78 map.insert(i, verif.data() + i); 79 80 for (size_t i = 11; i <= 20; ++i) 81 map.insert(i + ENTITY_TAGMASK, verif.data() + i); 82 83 TS_ASSERT_EQUALS(map.size(), 20); 84 85 for (size_t i = 1; i <= 10; ++i) 86 TS_ASSERT_EQUALS(map[i]->second, verif.data() + i); 87 for (size_t i = 11; i <= 20; ++i) 88 TS_ASSERT_EQUALS(map[i+ENTITY_TAGMASK]->second, verif.data() + i); 89 } 90 void test_TestIter() 91 { 92 clear(); 93 94 // verify the returned iterators 95 verif = std::vector<int>(20); 96 97 for (size_t i = 1; i < 10; i++) 98 map.insert(i, verif.data() + i-1); 99 for (size_t i = 10; i < 20; i++) 100 map.insert(i + ENTITY_TAGMASK, verif.data() + i - 1); 101 102 TS_ASSERT_EQUALS(map.begin()->second, verif.data()); 103 TS_ASSERT_EQUALS(map.end()->first, 0xFFFFFFFF); 104 105 size_t i = 0; 106 auto it = map.begin(); 107 for (; it != map.end(); ++it) 108 { 109 TS_ASSERT_EQUALS(it->second, verif.data() + i); 110 i++; 111 } 112 TS_ASSERT_EQUALS(i, map.size()) 113 } 114 void test_TestID() 115 { 116 clear(); 117 verif = std::vector<int>(20); 118 119 for (size_t i = 1; i <= 10; ++i) 120 map.insert(i, verif.data()); 121 122 for (size_t i = 11; i <= 20; ++i) 123 map.insert(i + ENTITY_TAGMASK, verif.data()); 124 125 TS_ASSERT_EQUALS(map.begin()->second, verif.data()); 126 TS_ASSERT_EQUALS(map.end()->first, 0xFFFFFFFF); 127 128 size_t i = 1; 129 auto it = map.begin(); 130 for (; it != map.end(); ++it) 131 { 132 TS_ASSERT_EQUALS(it->first, i); 133 i++; 134 if (i == 11) 135 i += ENTITY_TAGMASK; 136 } 137 } 138 void test_TestFind() 139 { 140 clear(); 141 verif = std::vector<int>(20); 142 143 map.insert(5, verif.data()); 144 map.insert(10, verif.data()+5); 145 map.insert(50, verif.data() + 1); 146 map.insert(ENTITY_TAGMASK + 5, verif.data()+2); 147 map.insert(ENTITY_TAGMASK + 50, verif.data()+3); 148 149 TS_ASSERT_EQUALS(map.find(5)->second, verif.data()); 150 TS_ASSERT_EQUALS(map[5]->second, verif.data()); 151 TS_ASSERT_EQUALS(map.find(50)->second, verif.data()+1); 152 TS_ASSERT_EQUALS(map[50]->second, verif.data()+1); 153 TS_ASSERT_EQUALS(map.find(40), map.end()); 154 TS_ASSERT_EQUALS(map[40]->first, INVALID_ENTITY); 155 156 TS_ASSERT_EQUALS(map.find(5 + ENTITY_TAGMASK)->second, verif.data()+2); 157 TS_ASSERT_EQUALS(map[5 + ENTITY_TAGMASK]->second, verif.data()+2); 158 TS_ASSERT_EQUALS(map.find(50 + ENTITY_TAGMASK)->second, verif.data()+3); 159 TS_ASSERT_EQUALS(map[50 + ENTITY_TAGMASK]->second, verif.data()+3); 160 TS_ASSERT_EQUALS(map.find(40 + ENTITY_TAGMASK), map.end()); 161 TS_ASSERT_EQUALS(map[40 + ENTITY_TAGMASK]->first, INVALID_ENTITY); 162 163 164 TS_ASSERT_EQUALS(map.find(-5), map.end()); 165 } 166 167 void test_TestErase() 168 { 169 clear(); 170 verif = std::vector<int>(21); 171 172 for (size_t i = 1; i <= 10; ++i) 173 map.insert(i, verif.data() + i); 174 175 for (size_t i = 11; i <= 20; ++i) 176 map.insert(i + ENTITY_TAGMASK, verif.data() + i); 177 178 map.erase(5); 179 map.erase(6); 180 map.erase(5); 181 map.erase(5 + ENTITY_TAGMASK); 182 183 TS_ASSERT_EQUALS(map[5]->first, INVALID_ENTITY); 184 TS_ASSERT_EQUALS(map[6]->first, INVALID_ENTITY); 185 TS_ASSERT_EQUALS(map[5 + ENTITY_TAGMASK]->first, INVALID_ENTITY); 186 TS_ASSERT_EQUALS(map.find(5), map.end()); 187 } 188 };