Ticket #4046: EntityMapForComponents.2.patch

File EntityMapForComponents.2.patch, 24.9 KB (added by wraitii, 8 years ago)

Version using an extension of EntityMap?

  • source/simulation2/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        }
  • source/simulation2/system/ComponentManager.h

     
    2626
    2727#include <boost/random/linear_congruential.hpp>
    2828#include <boost/unordered_map.hpp>
    29 
    3029#include <map>
    3130
    3231class IComponent;
     
    3534class CSimContext;
    3635class CDynamicSubscription;
    3736
     37template <class U>
     38class GlobalEntityMap;
     39
    3840class CComponentManager
    3941{
    4042    NONCOPYABLE(CComponentManager);
     
    355357    std::map<ComponentTypeId, ComponentType> m_ComponentTypesById;
    356358    std::vector<CComponentManager::ComponentTypeId> m_ScriptedSystemComponents;
    357359    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;
    359361    std::map<MessageTypeId, std::vector<ComponentTypeId> > m_LocalMessageSubscriptions;
    360362    std::map<MessageTypeId, std::vector<ComponentTypeId> > m_GlobalMessageSubscriptions;
    361363    std::map<std::string, ComponentTypeId> m_ComponentTypeIdsByName;
  • source/simulation2/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        {
    6768            components[eit->first][ctit->first] = eit->second;
     
    109110    serializer.StringASCII("rng", SerializeRNG(m_RNG), 0, 32);
    110111    serializer.NumberU32_Unbounded("next entity id", m_NextEntityId);
    111112
    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();
    113114    for (; cit != m_ComponentsByTypeId.end(); ++cit)
    114115    {
    115116        // In quick mode, only check unit positions
     
    118119
    119120        // Only emit component types if they have a component that will be serialized
    120121        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)
    122123        {
    123124            // Don't serialize local entities
    124125            if (ENTITY_IS_LOCAL(eit->first))
     
    133134
    134135        serializer.NumberI32_Unbounded("component type id", cit->first);
    135136
    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)
    137138        {
    138139            // Don't serialize local entities
    139140            if (ENTITY_IS_LOCAL(eit->first))
     
    188189    serializer.StringASCII("rng", SerializeRNG(m_RNG), 0, 32);
    189190    serializer.NumberU32_Unbounded("next entity id", m_NextEntityId);
    190191
    191     std::map<ComponentTypeId, std::map<entity_id_t, IComponent*> >::const_iterator cit;
     192    std::map<ComponentTypeId, GlobalEntityMap<IComponent*> >::const_iterator cit;
    192193   
    193194    uint32_t numSystemComponentTypes = 0;
    194195    uint32_t numComponentTypes = 0;
     
    199200    {
    200201        // Only emit component types if they have a component that will be serialized
    201202        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)
    203204        {
    204205            // Don't serialize local entities, and handle SYSTEM_ENTITY separately
    205206            if (ENTITY_IS_LOCAL(eit->first) || eit->first == SYSTEM_ENTITY)
     
    238239
    239240        serializer.StringASCII("name", ctit->second.name, 0, 255);
    240241
    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);
    242243        if (eit == cit->second.end())
    243244        {
    244245            debug_warn(L"Invalid eit"); // this should never happen
     
    265266
    266267        // Count the components before serializing any of them
    267268        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)
    269270        {
    270271            // Don't serialize local entities or SYSTEM_ENTITY
    271272            if (ENTITY_IS_LOCAL(eit->first) || eit->first == SYSTEM_ENTITY)
     
    278279        serializer.NumberU32_Unbounded("num components", numComponents);
    279280
    280281        // 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)
    282283        {
    283284            // Don't serialize local entities or SYSTEM_ENTITY
    284285            if (ENTITY_IS_LOCAL(eit->first) || eit->first == SYSTEM_ENTITY)
  • source/simulation2/system/EntityMap.h

     
    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>.
     
    4345    };
    4446    typedef key_val<entity_id_t, T> value_type;
    4547
    46 private:
     48protected:
    4749    size_t m_BufferSize;        // number of elements in the buffer
    4850    size_t m_BufferCapacity;    // capacity of the buffer
    4951    value_type* m_Buffer;       // vector with all the mapped key-value pairs
     
    210212    }
    211213
    212214    // 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    };
    213223    inline iterator find(const entity_id_t key)
    214224    {
    215225        if (key < m_BufferSize) // is this key in the range of existing entitites?
    216226        {
    217227            value_type* ptr = m_Buffer + key;
    218             if (ptr->first != INVALID_ENTITY)
    219                 return ptr;
     228        if (ptr->first != INVALID_ENTITY)
     229            return ptr;
    220230        }
    221231        return m_Buffer + m_BufferSize; // return iterator end()
    222232    }
     
    225235        if (key < m_BufferSize) // is this key in the range of existing entitites?
    226236        {
    227237            const value_type* ptr = m_Buffer + key;
    228             if (ptr->first != INVALID_ENTITY)
    229                 return ptr;
     238        if (ptr->first != INVALID_ENTITY)
     239            return ptr;
    230240        }
    231241        return m_Buffer + m_BufferSize; // return iterator end()
    232242    }
     
    278288    }
    279289};
    280290
     291template<class T>
     292class GlobalEntityMap : public EntityMap<T>
     293{
     294protected:
     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
    281300
     301public:
     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        {
     429fill_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
     558template<class VSerializer>
     559struct 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
    282600#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
     23class 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    }
     38public:
     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};