Ticket #4046: EntityMapForComponents.2.patch
File EntityMapForComponents.2.patch, 24.9 KB (added by , 8 years ago) |
---|
-
source/simulation2/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 } -
source/simulation2/system/ComponentManager.h
26 26 27 27 #include <boost/random/linear_congruential.hpp> 28 28 #include <boost/unordered_map.hpp> 29 30 29 #include <map> 31 30 32 31 class IComponent; … … 35 34 class CSimContext; 36 35 class CDynamicSubscription; 37 36 37 template <class U> 38 class GlobalEntityMap; 39 38 40 class CComponentManager 39 41 { 40 42 NONCOPYABLE(CComponentManager); … … 355 357 std::map<ComponentTypeId, ComponentType> m_ComponentTypesById; 356 358 std::vector<CComponentManager::ComponentTypeId> m_ScriptedSystemComponents; 357 359 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;360 std::map<ComponentTypeId, GlobalEntityMap<IComponent*> > m_ComponentsByTypeId; 359 361 std::map<MessageTypeId, std::vector<ComponentTypeId> > m_LocalMessageSubscriptions; 360 362 std::map<MessageTypeId, std::vector<ComponentTypeId> > m_GlobalMessageSubscriptions; 361 363 std::map<std::string, ComponentTypeId> m_ComponentTypeIdsByName; -
source/simulation2/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 68 components[eit->first][ctit->first] = eit->second; … … 109 110 serializer.StringASCII("rng", SerializeRNG(m_RNG), 0, 32); 110 111 serializer.NumberU32_Unbounded("next entity id", m_NextEntityId); 111 112 112 std::map<ComponentTypeId, std::map<entity_id_t,IComponent*> >::const_iterator cit = m_ComponentsByTypeId.begin();113 std::map<ComponentTypeId, GlobalEntityMap<IComponent*> >::const_iterator cit = m_ComponentsByTypeId.begin(); 113 114 for (; cit != m_ComponentsByTypeId.end(); ++cit) 114 115 { 115 116 // In quick mode, only check unit positions … … 118 119 119 120 // Only emit component types if they have a component that will be serialized 120 121 bool needsSerialization = false; 121 for ( std::map<entity_id_t,IComponent*>::const_iterator eit = cit->second.begin(); eit != cit->second.end(); ++eit)122 for (GlobalEntityMap<IComponent*>::const_iterator eit = cit->second.begin(); eit != cit->second.end(); ++eit) 122 123 { 123 124 // Don't serialize local entities 124 125 if (ENTITY_IS_LOCAL(eit->first)) … … 133 134 134 135 serializer.NumberI32_Unbounded("component type id", cit->first); 135 136 136 for ( std::map<entity_id_t,IComponent*>::const_iterator eit = cit->second.begin(); eit != cit->second.end(); ++eit)137 for (GlobalEntityMap<IComponent*>::const_iterator eit = cit->second.begin(); eit != cit->second.end(); ++eit) 137 138 { 138 139 // Don't serialize local entities 139 140 if (ENTITY_IS_LOCAL(eit->first)) … … 188 189 serializer.StringASCII("rng", SerializeRNG(m_RNG), 0, 32); 189 190 serializer.NumberU32_Unbounded("next entity id", m_NextEntityId); 190 191 191 std::map<ComponentTypeId, std::map<entity_id_t,IComponent*> >::const_iterator cit;192 std::map<ComponentTypeId, GlobalEntityMap<IComponent*> >::const_iterator cit; 192 193 193 194 uint32_t numSystemComponentTypes = 0; 194 195 uint32_t numComponentTypes = 0; … … 199 200 { 200 201 // Only emit component types if they have a component that will be serialized 201 202 bool needsSerialization = false; 202 for ( std::map<entity_id_t,IComponent*>::const_iterator eit = cit->second.begin(); eit != cit->second.end(); ++eit)203 for (GlobalEntityMap<IComponent*>::const_iterator eit = cit->second.begin(); eit != cit->second.end(); ++eit) 203 204 { 204 205 // Don't serialize local entities, and handle SYSTEM_ENTITY separately 205 206 if (ENTITY_IS_LOCAL(eit->first) || eit->first == SYSTEM_ENTITY) … … 238 239 239 240 serializer.StringASCII("name", ctit->second.name, 0, 255); 240 241 241 std::map<entity_id_t,IComponent*>::const_iterator eit = cit->second.find(SYSTEM_ENTITY);242 GlobalEntityMap<IComponent*>::const_iterator eit = cit->second.find(SYSTEM_ENTITY); 242 243 if (eit == cit->second.end()) 243 244 { 244 245 debug_warn(L"Invalid eit"); // this should never happen … … 265 266 266 267 // Count the components before serializing any of them 267 268 uint32_t numComponents = 0; 268 for ( std::map<entity_id_t,IComponent*>::const_iterator eit = cit->second.begin(); eit != cit->second.end(); ++eit)269 for (GlobalEntityMap<IComponent*>::const_iterator eit = cit->second.begin(); eit != cit->second.end(); ++eit) 269 270 { 270 271 // Don't serialize local entities or SYSTEM_ENTITY 271 272 if (ENTITY_IS_LOCAL(eit->first) || eit->first == SYSTEM_ENTITY) … … 278 279 serializer.NumberU32_Unbounded("num components", numComponents); 279 280 280 281 // Serialize the components now 281 for ( std::map<entity_id_t,IComponent*>::const_iterator eit = cit->second.begin(); eit != cit->second.end(); ++eit)282 for (GlobalEntityMap<IComponent*>::const_iterator eit = cit->second.begin(); eit != cit->second.end(); ++eit) 282 283 { 283 284 // Don't serialize local entities or SYSTEM_ENTITY 284 285 if (ENTITY_IS_LOCAL(eit->first) || eit->first == SYSTEM_ENTITY) -
source/simulation2/system/EntityMap.h
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>. … … 43 45 }; 44 46 typedef key_val<entity_id_t, T> value_type; 45 47 46 pr ivate:48 protected: 47 49 size_t m_BufferSize; // number of elements in the buffer 48 50 size_t m_BufferCapacity; // capacity of the buffer 49 51 value_type* m_Buffer; // vector with all the mapped key-value pairs … … 210 212 } 211 213 212 214 // Operations 215 inline iterator operator[](const entity_id_t key) 216 { 217 return m_Buffer + key; 218 }; 219 inline const_iterator operator[](const entity_id_t key) const 220 { 221 return m_Buffer + key; 222 }; 213 223 inline iterator find(const entity_id_t key) 214 224 { 215 225 if (key < m_BufferSize) // is this key in the range of existing entitites? 216 226 { 217 227 value_type* ptr = m_Buffer + key; 218 219 228 if (ptr->first != INVALID_ENTITY) 229 return ptr; 220 230 } 221 231 return m_Buffer + m_BufferSize; // return iterator end() 222 232 } … … 225 235 if (key < m_BufferSize) // is this key in the range of existing entitites? 226 236 { 227 237 const value_type* ptr = m_Buffer + key; 228 229 238 if (ptr->first != INVALID_ENTITY) 239 return ptr; 230 240 } 231 241 return m_Buffer + m_BufferSize; // return iterator end() 232 242 } … … 278 288 } 279 289 }; 280 290 291 template<class T> 292 class GlobalEntityMap : public EntityMap<T> 293 { 294 protected: 295 // Variants for local entities 296 size_t m_LocalBufferSize; // number of elements in the buffer 297 size_t m_LocalBufferCapacity; // capacity of the buffer 298 value_type* m_LocalBuffer; // vector with all the mapped key-value pairs 299 size_t m_LocalCount; // number of 'valid' entity id's 281 300 301 public: 302 303 inline GlobalEntityMap() : m_LocalBufferSize(1), m_LocalBufferCapacity(4096), m_LocalCount(0) 304 { 305 m_LocalBuffer = (value_type*)malloc(sizeof(value_type) * (m_LocalBufferCapacity + 1)); 306 307 // create the first element: 308 m_LocalBuffer[0].first = INVALID_ENTITY; 309 m_LocalBuffer[1].first = 0xFFFFFFFF; // ensure end() always has 0xFFFFFFFF 310 } 311 inline ~GlobalEntityMap() 312 { 313 free(m_LocalBuffer); 314 } 315 316 // Iterators 317 template<class U, class V> struct _iter : public std::iterator<std::forward_iterator_tag, U> 318 { 319 private: 320 inline _iter(U* init) : val(init) {} 321 public: 322 V* const map; 323 U* val; 324 inline U& operator*() { return *val; } 325 inline U* operator->() { return val; } 326 inline _iter(V* const init, U* ival) : map(init), val(ival) {} 327 328 inline _iter& operator++()// ++it 329 { 330 ++val; 331 // skip any invalid entities, jump to local 332 while (val->first == INVALID_ENTITY) ++val; 333 if (val->first == 0xFFFFFFFF && val == &*map->normalEnd()) 334 val = &*(map->localBegin()); 335 while (val->first == INVALID_ENTITY) ++val; 336 return *this; 337 } 338 inline _iter& operator++(int) // it++ 339 { 340 U* ptr = val; 341 ++val; 342 while (val->first == INVALID_ENTITY) ++val; // skip any invalid entities 343 if (val->first == 0xFFFFFFFF && val == &*map->normalEnd()) 344 val = &*map->localBegin(); 345 while (val->first == INVALID_ENTITY) ++val; 346 return ptr; 347 } 348 inline bool operator==(_iter other) { return val == other.val; } 349 inline bool operator!=(_iter other) { return val != other.val; } 350 inline operator _iter<U const, V const>() const { return _iter<U const, V const>(map, val); } 351 }; 352 353 typedef _iter<value_type, GlobalEntityMap> iterator; 354 typedef _iter<value_type const, GlobalEntityMap const> const_iterator; 355 356 inline iterator begin() 357 { 358 auto iter = EntityMap::begin(); 359 if (iter->first == 0xFFFFFFFF) 360 return localBegin(); 361 return iterator(this, &*iter); 362 } 363 inline iterator localBegin() 364 { 365 value_type* ptr = m_LocalBuffer + 1; // skip the first INVALID_ENTITY 366 while (ptr->first == INVALID_ENTITY) ++ptr; // skip any other invalid entities 367 return iterator(this, ptr); 368 } 369 inline iterator end() 370 { 371 return iterator(this, m_LocalBuffer + m_LocalBufferSize); 372 } 373 inline iterator normalEnd() 374 { 375 return iterator(this, &*EntityMap::end()); 376 } 377 inline const_iterator begin() const 378 { 379 auto iter = EntityMap::begin(); 380 if (iter->first == 0xFFFFFFFF) 381 return localBegin(); 382 return const_iterator(this, &*iter); 383 } 384 inline const_iterator localBegin() const 385 { 386 value_type* ptr = m_LocalBuffer + 1; // skip the first INVALID_ENTITY 387 while (ptr->first == INVALID_ENTITY) ++ptr; // skip any other invalid entities 388 return const_iterator(this, ptr); 389 } 390 inline const_iterator end() const 391 { 392 return const_iterator(this, m_LocalBuffer + m_LocalBufferSize); 393 } 394 inline const_iterator normalEnd() const 395 { 396 return const_iterator(this, &*EntityMap::end()); 397 } 398 399 // Size 400 inline bool localEmpty() const { return m_LocalCount == 0; } 401 inline size_t localSize() const { return m_LocalCount; } 402 403 // Modification 404 void insert(const key_type actual_key, const mapped_type& value) 405 { 406 if (actual_key < ENTITY_TAGMASK) 407 { 408 EntityMap::insert(actual_key, value); 409 return; 410 } 411 key_type key = actual_key & ~ENTITY_TAGMASK; 412 if (key>= m_LocalBufferCapacity) 413 { 414 size_t newCapacity = m_LocalBufferCapacity + 4096; 415 while (key >= newCapacity) newCapacity += 4096; 416 // always allocate +1 behind the scenes, because end() must have a 0xFFFFFFFF key 417 value_type* mem = (value_type*)realloc(m_LocalBuffer, sizeof(value_type) * (newCapacity + 1)); 418 if (!mem) 419 { 420 debug_warn("GlobalEntityMap::insert() realloc failed! Out of memory."); 421 throw std::bad_alloc(); // fail to expand and insert 422 } 423 m_LocalBufferCapacity = newCapacity; 424 m_LocalBuffer = mem; 425 goto fill_gaps; 426 } 427 else if (key > m_LocalBufferSize) // weird insert far beyond the end 428 { 429 fill_gaps: 430 // set all entity id's to INVALID_ENTITY inside the new range 431 for (size_t i = m_LocalBufferSize; i <= key; ++i) 432 m_LocalBuffer[i].first = INVALID_ENTITY; 433 m_LocalBufferSize = key; // extend the new size 434 } 435 436 value_type& item = m_LocalBuffer[key]; 437 key_type oldKey = item.first; 438 item.first = key; 439 if (key == m_LocalBufferSize) // push_back 440 { 441 ++m_LocalBufferSize; // expand 442 ++m_Count; 443 ++m_LocalCount; 444 new (&item.second) mapped_type(value); // copy ctor to init 445 m_LocalBuffer[m_LocalBufferSize].first = 0xFFFFFFFF; // ensure end() always has 0xFFFFFFFF 446 } 447 else if (!item.first) // insert new to middle 448 { 449 ++m_Count; 450 ++m_LocalCount; 451 new (&item.second) mapped_type(value); // copy ctor to init 452 } 453 else // set existing value 454 { 455 if (oldKey == INVALID_ENTITY) 456 { 457 ++m_Count; 458 ++m_LocalCount; 459 } 460 item.second = value; // overwrite existing 461 } 462 } 463 464 void erase(iterator it) 465 { 466 if (ptr->first != INVALID_ENTITY && ptr >= m_LocalBuffer && ptr < m_LocalBuffer + m_LocalBufferSize) 467 --m_LocalCount; 468 EntityMap::erase(it); 469 } 470 void erase(const entity_id_t actual_key) 471 { 472 if (actual_key < ENTITY_TAGMASK) 473 { 474 EntityMap::erase(actual_key); 475 return; 476 } 477 key_type key = actual_key & ~ENTITY_TAGMASK; 478 if (key < m_LocalBufferSize) 479 { 480 value_type* ptr = m_LocalBuffer + key; 481 if (ptr->first != INVALID_ENTITY) 482 { 483 ptr->first = INVALID_ENTITY; 484 ptr->second.~T(); // call dtor 485 --m_Count; 486 --m_LocalCount; 487 } 488 } 489 } 490 inline void clear() 491 { 492 EntityMap::clear(); 493 // orphan whole range 494 value_type* ptr = m_LocalBuffer; 495 value_type* end = m_LocalBuffer + m_LocalBufferSize; 496 for (; ptr != end; ++ptr) 497 { 498 if (ptr->first != INVALID_ENTITY) 499 { 500 ptr->first = INVALID_ENTITY; 501 ptr->second.~T(); // call dtor 502 } 503 } 504 m_Count = 0; 505 m_LocalCount = 0; 506 } 507 508 // Operations 509 inline iterator operator[](const entity_id_t actual_key) 510 { 511 if (actual_key < ENTITY_TAGMASK) 512 return iterator(this,&*(EntityMap::operator[](actual_key))); 513 key_type key = actual_key & ~ENTITY_TAGMASK; 514 return iterator(this, m_LocalBuffer + key); 515 }; 516 inline const_iterator operator[](const entity_id_t actual_key) const 517 { 518 if (actual_key < ENTITY_TAGMASK) 519 return const_iterator(this, &*(EntityMap::operator[](actual_key))); 520 key_type key = actual_key & ~ENTITY_TAGMASK; 521 return const_iterator(this, m_LocalBuffer + key); 522 }; 523 inline iterator find(const entity_id_t actual_key) 524 { 525 if (actual_key < ENTITY_TAGMASK) 526 return iterator(this, &*EntityMap::find(actual_key)) == normalEnd() ? end() : iterator(this, &*EntityMap::find(actual_key)); 527 key_type key = actual_key & ~ENTITY_TAGMASK; 528 529 value_type* ptr = key < m_LocalBufferSize ? m_LocalBuffer + key : m_LocalBuffer + m_LocalBufferSize; 530 if (ptr->first != INVALID_ENTITY) 531 return iterator(this, ptr); 532 return iterator(this, m_LocalBuffer + m_LocalBufferSize); 533 } 534 inline const_iterator find(const entity_id_t actual_key) const 535 { 536 if (actual_key < ENTITY_TAGMASK) 537 return const_iterator(this, &*EntityMap::find(actual_key)) == normalEnd() ? end() : const_iterator(this, &*EntityMap::find(actual_key)); 538 key_type key = actual_key & ~ENTITY_TAGMASK; 539 const value_type* ptr = key < m_LocalBufferSize ? m_LocalBuffer + key : m_LocalBuffer + m_LocalBufferSize; 540 if (ptr->first != INVALID_ENTITY) 541 return const_iterator(this, ptr); 542 return const_iterator(this, m_LocalBuffer + m_LocalBufferSize); 543 } 544 inline size_t count(const entity_id_t actual_key) const 545 { 546 if (actual_key < ENTITY_TAGMASK) 547 return EntityMap::count(actual_key) 548 key_type key = actual_key & ~ENTITY_TAGMASK; 549 if (key < m_LocalBufferSize) 550 { 551 if (m_LocalBuffer[key].first != INVALID_ENTITY) 552 return 1; 553 } 554 return 0; 555 } 556 }; 557 558 template<class VSerializer> 559 struct SerializeGlobalEntityMap 560 { 561 template<class V> 562 void operator()(ISerializer& serialize, const char* UNUSED(name), GlobalEntityMap<V>& value) 563 { 564 size_t len = value.size(); 565 serialize.NumberU32_Unbounded("length", (u32)len); 566 size_t locallen = value.localSize(); 567 serialize.NumberU32_Unbounded("localLength", (u32)locallen); 568 size_t count = 0; 569 for (typename EntityMap<V>::iterator it = value.begin(); it != value.end(); ++it) 570 { 571 serialize.NumberU32_Unbounded("key", it->first); 572 VSerializer()(serialize, "value", it->second); 573 count++; 574 } 575 // test to see if the entityMap count wasn't wrong 576 // (which causes a crashing deserialisation) 577 ENSURE(count == len); 578 } 579 580 template<class V> 581 void operator()(IDeserializer& deserialize, const char* UNUSED(name), GlobalEntityMap<V>& value) 582 { 583 value.clear(); 584 uint32_t len, locallen; 585 deserialize.NumberU32_Unbounded("length", len); 586 deserialize.NumberU32_Unbounded("localLength", locallen); 587 for (size_t i = 0; i < len; ++i) 588 { 589 entity_id_t k; 590 V v; 591 deserialize.NumberU32_Unbounded("key", k); 592 VSerializer()(deserialize, "value", v); 593 if (i >= len - locallen) 594 k = k | ENTITY_TAGMASK; 595 value.insert(k, v); 596 } 597 } 598 }; 599 282 600 #endif -
source/simulation2/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 class TestGlobalEntityMap : public CxxTest::TestSuite 24 { 25 GlobalEntityMap<int* > map; 26 EntityMap<int* > testMap; 27 std::array<int, 6> verif; 28 void setUp() 29 { 30 verif.fill(0); 31 testMap.insert(5, verif.data()); 32 testMap.insert(6, verif.data()+1); 33 map.insert(5, verif.data()); 34 map.insert(6, verif.data()+1); 35 map.insert(ENTITY_TAGMASK + 5, verif.data() + 2); 36 map.insert(ENTITY_TAGMASK + 6, verif.data() + 3); 37 } 38 public: 39 void test_TestEntity() 40 { 41 setUp(); 42 TS_ASSERT_EQUALS((int)testMap.size(), 2); 43 TS_ASSERT_EQUALS(map.size(), 4); 44 TS_ASSERT_EQUALS(map.localSize(), 2); 45 46 TS_ASSERT_EQUALS(map.begin()->second, verif.data()); 47 TS_ASSERT_EQUALS(map.normalEnd()->first, 0xFFFFFFFF); 48 TS_ASSERT_EQUALS(testMap.begin()->second, verif.data()); 49 TS_ASSERT_EQUALS(testMap.end()->first, 0xFFFFFFFF); 50 51 TS_ASSERT_EQUALS(map.localBegin()->second, verif.data() + 2); 52 TS_ASSERT_EQUALS(map.end()->first, 0xFFFFFFFF); 53 54 int i = 0; 55 auto it = map.begin(); 56 for (; it != map.end(); ++it) 57 { 58 TS_ASSERT_EQUALS(&verif[i], it->second); 59 i++; 60 } 61 62 map.erase(5); 63 TS_ASSERT_EQUALS(map.begin()->second, verif.data() + 1); 64 65 map.erase(ENTITY_TAGMASK + 5); 66 TS_ASSERT_EQUALS(map.localBegin()->second, verif.data() + 3); 67 68 map.clear(); 69 testMap.clear(); 70 71 TS_ASSERT_EQUALS((int)testMap.size(), 0); 72 TS_ASSERT_EQUALS(map.size(), 0); 73 TS_ASSERT_EQUALS(map.localSize(), 0); 74 75 map.insert(ENTITY_TAGMASK + 5, verif.data() + 2); 76 map.insert(ENTITY_TAGMASK + 6, verif.data() + 3); 77 78 TS_ASSERT_EQUALS(map.begin()->second, verif.data() + 2); 79 TS_ASSERT_EQUALS(map.normalEnd()->first, 0xFFFFFFFF); 80 81 TS_ASSERT_EQUALS(map.localBegin()->second, verif.data() + 2); 82 TS_ASSERT_EQUALS(map.end()->first, 0xFFFFFFFF); 83 84 map.insert(1500, verif.data()); 85 TS_ASSERT_EQUALS(map.find(1500)->second, verif.data()); 86 TS_ASSERT_EQUALS(map[1500]->second, verif.data()); 87 88 } 89 };