Ticket #4046: EntityMapForComponents.3.patch

File EntityMapForComponents.3.patch, 27.2 KB (added by wraitii, 8 years ago)

Tame the monster

  • system/ComponentManager.cpp

     
    2020#include "ComponentManager.h"
    2121
    2222#include "DynamicSubscription.h"
     23#include "EntityMap.h"
    2324#include "IComponent.h"
    2425#include "ParamNode.h"
    2526#include "SimContext.h"
     
    305306    {
    306307        // For every script component with this cid, we need to switch its
    307308        // 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();
    310311        for (; eit != comps.end(); ++eit)
    311312        {
    312313            JS::RootedValue instance(cx, eit->second->GetJSInstance());
     
    509510    m_DynamicMessageSubscriptionsNonsyncByComponent.clear();
    510511
    511512    // 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();
    513514    for (; iit != m_ComponentsByTypeId.end(); ++iit)
    514515    {
    515         std::map<entity_id_t, IComponent*>::iterator eit = iit->second.begin();
     516        GlobalEntityMap<IComponent*>::iterator eit = iit->second.begin();
    516517        for (; eit != iit->second.end(); ++eit)
    517518        {
    518519            eit->second->Deinit();
     
    757758        return NULL;
    758759    }
    759760
    760     std::map<entity_id_t, IComponent*>& emap2 = m_ComponentsByTypeId[cid];
     761    GlobalEntityMap<IComponent*>& emap2 = m_ComponentsByTypeId[cid];
    761762
    762763    // If this is a scripted component, construct the appropriate JS object first
    763764    JS::RootedValue obj(cx);
     
    780781
    781782    // Store a reference to the new component
    782783    emap1.insert(std::make_pair(ent.GetId(), component));
    783     emap2.insert(std::make_pair(ent.GetId(), component));
     784    emap2.insert(ent.GetId(), component);
    784785    // TODO: We need to more careful about this - if an entity is constructed by a component
    785786    // while we're iterating over all components, this will invalidate the iterators and everything
    786787    // will break.
     
    918919            PostMessage(ent, msg);
    919920
    920921            // 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();
    922923            for (; iit != m_ComponentsByTypeId.end(); ++iit)
    923924            {
    924                 std::map<entity_id_t, IComponent*>::iterator eit = iit->second.find(ent);
     925                GlobalEntityMap<IComponent*>::iterator eit = iit->second.find(ent);
    925926                if (eit != iit->second.end())
    926927                {
    927928                    eit->second->Deinit();
     
    10071008        for (; ctit != it->second.end(); ++ctit)
    10081009        {
    10091010            // 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);
    10111012            if (emap == m_ComponentsByTypeId.end())
    10121013                continue;
    10131014
    10141015            // 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);
    10161017            if (eit != emap->second.end())
    10171018                eit->second->HandleMessage(msg, false);
    10181019        }
     
    10321033        for (; ctit != it->second.end(); ++ctit)
    10331034        {
    10341035            // 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);
    10361037            if (emap == m_ComponentsByTypeId.end())
    10371038                continue;
    10381039
    10391040            // 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();
    10411042            for (; eit != emap->second.end(); ++eit)
    10421043                eit->second->HandleMessage(msg, false);
    10431044        }
     
    10691070            }
    10701071
    10711072            // 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);
    10731074            if (emap == m_ComponentsByTypeId.end())
    10741075                continue;
    10751076
    10761077            // 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();
    10781079            for (; eit != emap->second.end(); ++eit)
    10791080                eit->second->HandleMessage(msg, true);
    10801081        }
  • system/ComponentManager.h

     
    3535class CSimContext;
    3636class CDynamicSubscription;
    3737
     38template <class U>
     39class GlobalEntityMap;
     40
    3841class CComponentManager
    3942{
    4043    NONCOPYABLE(CComponentManager);
     
    355358    std::map<ComponentTypeId, ComponentType> m_ComponentTypesById;
    356359    std::vector<CComponentManager::ComponentTypeId> m_ScriptedSystemComponents;
    357360    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;
    359362    std::map<MessageTypeId, std::vector<ComponentTypeId> > m_LocalMessageSubscriptions;
    360363    std::map<MessageTypeId, std::vector<ComponentTypeId> > m_GlobalMessageSubscriptions;
    361364    std::map<std::string, ComponentTypeId> m_ComponentTypeIdsByName;
  • system/ComponentManagerSerialization.cpp

     
    1818#include "precompiled.h"
    1919
    2020#include "ComponentManager.h"
     21#include "EntityMap.h"
    2122#include "IComponent.h"
    2223#include "ParamNode.h"
    2324
     
    5859    std::map<entity_id_t, std::map<ComponentTypeId, IComponent*> > components;
    5960    //std::map<ComponentTypeId, std::string> names;
    6061
    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();
    6263    for (; ctit != m_ComponentsByTypeId.end(); ++ctit)
    6364    {
    64         std::map<entity_id_t, IComponent*>::const_iterator eit = ctit->second.begin();
     65        GlobalEntityMap<IComponent*>::const_iterator eit = ctit->second.begin();
    6566        for (; eit != ctit->second.end(); ++eit)
    6667        {
    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;
    6872        }
    6973    }
    7074
     
    109113    serializer.StringASCII("rng", SerializeRNG(m_RNG), 0, 32);
    110114    serializer.NumberU32_Unbounded("next entity id", m_NextEntityId);
    111115
    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();
    113117    for (; cit != m_ComponentsByTypeId.end(); ++cit)
    114118    {
    115119        // In quick mode, only check unit positions
     
    118122
    119123        // Only emit component types if they have a component that will be serialized
    120124        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)
    122126        {
    123127            // Don't serialize local entities
    124128            if (ENTITY_IS_LOCAL(eit->first))
     
    133137
    134138        serializer.NumberI32_Unbounded("component type id", cit->first);
    135139
    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)
    137141        {
    138142            // Don't serialize local entities
    139143            if (ENTITY_IS_LOCAL(eit->first))
     
    188192    serializer.StringASCII("rng", SerializeRNG(m_RNG), 0, 32);
    189193    serializer.NumberU32_Unbounded("next entity id", m_NextEntityId);
    190194
    191     std::map<ComponentTypeId, std::map<entity_id_t, IComponent*> >::const_iterator cit;
     195    std::map<ComponentTypeId, GlobalEntityMap<IComponent*> >::const_iterator cit;
    192196   
    193197    uint32_t numSystemComponentTypes = 0;
    194198    uint32_t numComponentTypes = 0;
     
    199203    {
    200204        // Only emit component types if they have a component that will be serialized
    201205        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)
    203207        {
    204208            // Don't serialize local entities, and handle SYSTEM_ENTITY separately
    205209            if (ENTITY_IS_LOCAL(eit->first) || eit->first == SYSTEM_ENTITY)
     
    238242
    239243        serializer.StringASCII("name", ctit->second.name, 0, 255);
    240244
    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);
    242246        if (eit == cit->second.end())
    243247        {
    244248            debug_warn(L"Invalid eit"); // this should never happen
     
    265269
    266270        // Count the components before serializing any of them
    267271        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)
    269273        {
    270274            // Don't serialize local entities or SYSTEM_ENTITY
    271275            if (ENTITY_IS_LOCAL(eit->first) || eit->first == SYSTEM_ENTITY)
     
    278282        serializer.NumberU32_Unbounded("num components", numComponents);
    279283
    280284        // 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)
    282286        {
    283287            // Don't serialize local entities or SYSTEM_ENTITY
    284288            if (ENTITY_IS_LOCAL(eit->first) || eit->first == SYSTEM_ENTITY)
  • system/EntityMap.h

     
    1 /* Copyright (C) 2013 Wildfire Games.
     1/* Copyright (C) 2016 Wildfire Games.
    22 * This file is part of 0 A.D.
    33 *
    44 * 0 A.D. is free software: you can redistribute it and/or modify
     
    1818#define INCLUDED_ENTITYMAP
    1919
    2020#include "Entity.h"
     21#include "simulation2/serialization/ISerializer.h"
     22#include "simulation2/serialization/IDeserializer.h"
    2123
    2224/**
    2325 * A fast replacement for map<entity_id_t, T>.
     
    4850    size_t m_BufferCapacity;    // capacity of the buffer
    4951    value_type* m_Buffer;       // vector with all the mapped key-value pairs
    5052
     53    size_t m_FirstEntityID;     // real ID of the [0] in the buffer, so we can offset.
    5154    size_t m_Count;             // number of 'valid' entity id's
    5255
    5356public:
    5457
    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)
    5659    {
    5760        // for entitymap we allocate the buffer right away
    5861        // with first element in buffer being the Invalid Entity
    5962        m_Buffer = (value_type*)malloc(sizeof(value_type) * (m_BufferCapacity + 1));
    6063
    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
    6465    }
     66    inline EntityMap(size_t ID) : EntityMap()
     67    {
     68        m_FirstEntityID = ID;
     69    }
     70
    6571    inline ~EntityMap()
    6672    {
    6773        free(m_Buffer);
     
    97103
    98104    inline iterator begin()
    99105    {
    100         value_type* ptr = m_Buffer + 1; // skip the first INVALID_ENTITY
     106        value_type* ptr = m_Buffer;
    101107        while (ptr->first == INVALID_ENTITY) ++ptr; // skip any other invalid entities
    102108        return ptr;
    103109    }
     
    107113    }
    108114    inline const_iterator begin() const
    109115    {
    110         value_type* ptr = m_Buffer + 1; // skip the first INVALID_ENTITY
     116        value_type* ptr = m_Buffer;
    111117        while (ptr->first == INVALID_ENTITY) ++ptr; // skip any other invalid entities
    112118        return ptr;
    113119    }
     
    121127    inline size_t size() const { return m_Count; }
    122128
    123129    // Modification
    124     void insert(const key_type key, const mapped_type& value)
     130    void insert(const key_type actual_key, const mapped_type& value)
    125131    {
     132        key_type key = actual_key - m_FirstEntityID;
    126133        if (key >= m_BufferCapacity) // do we need to resize buffer?
    127134        {
    128135            size_t newCapacity = m_BufferCapacity + 4096;
     
    143150fill_gaps:
    144151            // set all entity id's to INVALID_ENTITY inside the new range
    145152            for (size_t i = m_BufferSize; i <= key; ++i)
     153            {
    146154                m_Buffer[i].first = INVALID_ENTITY;
     155                new (&m_Buffer[i].second) mapped_type();
     156            }
    147157            m_BufferSize = key; // extend the new size
    148158        }
    149159
    150160        value_type& item = m_Buffer[key];
    151161        key_type oldKey = item.first;
    152         item.first = key;
     162        item.first = actual_key;
    153163        if (key == m_BufferSize) // push_back
    154164        {
    155165            ++m_BufferSize; // expand
     
    157167            new (&item.second) mapped_type(value); // copy ctor to init
    158168            m_Buffer[m_BufferSize].first = 0xFFFFFFFF; // ensure end() always has 0xFFFFFFFF
    159169        }
    160         else if(!item.first) // insert new to middle
    161         {
    162             ++m_Count;
    163             new (&item.second) mapped_type(value); // copy ctor to init
    164         }
    165170        else // set existing value
    166171        {
    167172            if (oldKey == INVALID_ENTITY)
    168173                m_Count++;
    169             item.second = value; // overwrite existing
     174            item.second = value;
    170175        }
    171176    }
    172177   
     
    182187    }
    183188    void erase(const entity_id_t key)
    184189    {
    185         if (key < m_BufferSize)
     190        if (key - m_FirstEntityID < m_BufferSize)
    186191        {
    187             value_type* ptr = m_Buffer + key;
     192            value_type* ptr = m_Buffer + key - m_FirstEntityID;
    188193            if (ptr->first != INVALID_ENTITY)
    189194            {
    190195                ptr->first = INVALID_ENTITY;
     
    210215    }
    211216
    212217    // 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    };
    213226    inline iterator find(const entity_id_t key)
    214227    {
    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?
    216229        {
    217             value_type* ptr = m_Buffer + key;
     230            value_type* ptr = m_Buffer + key - m_FirstEntityID;
    218231            if (ptr->first != INVALID_ENTITY)
    219232                return ptr;
    220233        }
     
    222235    }
    223236    inline const_iterator find(const entity_id_t key) const
    224237    {
    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?
    226239        {
    227             const value_type* ptr = m_Buffer + key;
     240            const value_type* ptr = m_Buffer + key - m_FirstEntityID;
    228241            if (ptr->first != INVALID_ENTITY)
    229242                return ptr;
    230243        }
     
    232245    }
    233246    inline size_t count(const entity_id_t key) const
    234247    {
    235         if (key < m_BufferSize)
     248        if (key - m_FirstEntityID >= 0 && key - m_FirstEntityID < m_BufferSize)
    236249        {
    237             if (m_Buffer[key].first != INVALID_ENTITY)
     250            if (m_Buffer[key - m_FirstEntityID].first != INVALID_ENTITY)
    238251                return 1;
    239252        }
    240253        return 0;
     
    278291    }
    279292};
    280293
     294//Implements the same interface as EntityMap but uses two internally to separate local entities
     295template<class T>
     296class GlobalEntityMap
     297{
     298protected:
    281299
     300public:
     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
     452template<class VSerializer>
     453struct 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
    282494#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.
     26class 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    }
     36public:
     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};