Ticket #1707: RangeManagerEntityMap.patch

File RangeManagerEntityMap.patch, 41.8 KB (added by Jorma Rebane, 9 years ago)

Working application of the EntityMap. Debugged and ~5x performance improvement to ExecuteActiveQuery.

  • lib/ps_stl.h

     
     1/* Copyright (c) 2013 Wildfire Games
     2 *
     3 * Permission is hereby granted, free of charge, to any person obtaining
     4 * a copy of this software and associated documentation files (the
     5 * "Software"), to deal in the Software without restriction, including
     6 * without limitation the rights to use, copy, modify, merge, publish,
     7 * distribute, sublicense, and/or sell copies of the Software, and to
     8 * permit persons to whom the Software is furnished to do so, subject to
     9 * the following conditions:
     10 *
     11 * The above copyright notice and this permission notice shall be included
     12 * in all copies or substantial portions of the Software.
     13 *
     14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
     15 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
     16 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
     17 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
     18 * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
     19 * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
     20 * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
     21 */
     22#ifndef INCLUDED_PS_STL
     23#define INCLUDED_PS_STL
     24
     25/**
     26 * @author Jorma Rebane
     27 * @note Pyrogenesis STL methods
     28 * @note This file contains useful and optimized methods for use with STL
     29 */
     30
     31namespace ps
     32{
     33    /**
     34     * Removes the first occurrence of the specified value from the container.
     35     * @param container The STL-compatible container to remove from.
     36     * @param value The value to remove.
     37     */
     38template<class Container, class T>
     39    inline void remove_first_occurrence(Container& container, const T& value)
     40    {
     41        if (int count = container.size())
     42        {
     43            T* data = &container[0];
     44            for (int i = 0; i < count; ++i)
     45            {
     46                if (data[i] == value)
     47                {
     48                    container.erase(container.begin() + i);
     49                    return;
     50                }
     51            }
     52        }
     53    }
     54
     55    /**
     56     * @param container The STL-compatible container to search in.
     57     * @param value The value to search for.
     58     * @return TRUE if [value] exists in [container].
     59     */
     60template<class Container, class T>
     61    inline bool exists_in(const Container& container, const T& value)
     62    {
     63        if (int count = container.size())
     64        {
     65            for (const T* data = &container[0]; count; ++data, --count)
     66            {
     67                if (*data == value)
     68                {
     69                    return true;
     70                }
     71            }
     72        }
     73        return false;
     74    }
     75
     76    /**
     77     * Finds a value in a container
     78     * @param container The STL-compatible container to search in.
     79     * @param value The value to search for.
     80     * @return Pointer to the value if found, NULL if not found.
     81     */
     82template<class Container, class T>
     83    inline T* find_in(const Container& container, const T& value)
     84    {
     85        if (int count = container.size())
     86        {
     87            for (const T* data = &container[0]; count; ++data, --count)
     88            {
     89                if (*data == value)
     90                {
     91                    return (T*)data;
     92                }
     93            }
     94        }
     95        return NULL;
     96    }
     97
     98
     99} // namespace ps
     100
     101#endif // INCLUDED_PS_STL
     102 No newline at end of file
  • simulation2/components/CCmpObstructionManager.cpp

     
    124124    bool m_DebugOverlayDirty;
    125125    std::vector<SOverlayLine> m_DebugOverlayLines;
    126126
    127     SpatialSubdivision<u32> m_UnitSubdivision;
    128     SpatialSubdivision<u32> m_StaticSubdivision;
     127    SpatialSubdivision m_UnitSubdivision;
     128    SpatialSubdivision m_StaticSubdivision;
    129129
    130130    // TODO: using std::map is a bit inefficient; is there a better way to store these?
    131131    std::map<u32, UnitShape> m_UnitShapes;
     
    161161
    162162        // Initialise with bogus values (these will get replaced when
    163163        // SetBounds is called)
    164         ResetSubdivisions(entity_pos_t::FromInt(1), entity_pos_t::FromInt(1));
     164        ResetSubdivisions(entity_pos_t::FromInt(1024), entity_pos_t::FromInt(1024));
    165165    }
    166166
    167167    virtual void Deinit()
     
    171171    template<typename S>
    172172    void SerializeCommon(S& serialize)
    173173    {
    174         SerializeSpatialSubdivision<SerializeU32_Unbounded>()(serialize, "unit subdiv", m_UnitSubdivision);
    175         SerializeSpatialSubdivision<SerializeU32_Unbounded>()(serialize, "static subdiv", m_StaticSubdivision);
     174        SerializeSpatialSubdivision()(serialize, "unit subdiv", m_UnitSubdivision);
     175        SerializeSpatialSubdivision()(serialize, "static subdiv", m_StaticSubdivision);
    176176
    177177        SerializeMap<SerializeU32_Unbounded, SerializeUnitShape>()(serialize, "unit shapes", m_UnitShapes);
    178178        SerializeMap<SerializeU32_Unbounded, SerializeStaticShape>()(serialize, "static shapes", m_StaticShapes);
     
    544544    CFixedVector2D posMin (std::min(x0, x1) - r, std::min(z0, z1) - r);
    545545    CFixedVector2D posMax (std::max(x0, x1) + r, std::max(z0, z1) + r);
    546546
    547     std::vector<u32> unitShapes = m_UnitSubdivision.GetInRange(posMin, posMax);
    548     for (size_t i = 0; i < unitShapes.size(); ++i)
     547    SpatialQueryArray unitShapes;
     548    m_UnitSubdivision.GetInRange(unitShapes, posMin, posMax);
     549    for (int i = 0; i < unitShapes.size(); ++i)
    549550    {
    550551        std::map<u32, UnitShape>::iterator it = m_UnitShapes.find(unitShapes[i]);
    551552        ENSURE(it != m_UnitShapes.end());
     
    559560            return true;
    560561    }
    561562
    562     std::vector<u32> staticShapes = m_StaticSubdivision.GetInRange(posMin, posMax);
    563     for (size_t i = 0; i < staticShapes.size(); ++i)
     563    SpatialQueryArray staticShapes;
     564    m_StaticSubdivision.GetInRange(staticShapes, posMin, posMax);
     565    for (int i = 0; i < staticShapes.size(); ++i)
    564566    {
    565567        std::map<u32, StaticShape>::iterator it = m_StaticShapes.find(staticShapes[i]);
    566568        ENSURE(it != m_StaticShapes.end());
     
    880882
    881883    ENSURE(x0 <= x1 && z0 <= z1);
    882884
    883     std::vector<u32> unitShapes = m_UnitSubdivision.GetInRange(CFixedVector2D(x0, z0), CFixedVector2D(x1, z1));
    884     for (size_t i = 0; i < unitShapes.size(); ++i)
     885    SpatialQueryArray unitShapes;
     886    m_UnitSubdivision.GetInRange(unitShapes, CFixedVector2D(x0, z0), CFixedVector2D(x1, z1));
     887    for (int i = 0; i < unitShapes.size(); ++i)
    885888    {
    886889        std::map<u32, UnitShape>::iterator it = m_UnitShapes.find(unitShapes[i]);
    887890        ENSURE(it != m_UnitShapes.end());
     
    901904        squares.push_back(s);
    902905    }
    903906
    904     std::vector<u32> staticShapes = m_StaticSubdivision.GetInRange(CFixedVector2D(x0, z0), CFixedVector2D(x1, z1));
    905     for (size_t i = 0; i < staticShapes.size(); ++i)
     907    SpatialQueryArray staticShapes;
     908    m_StaticSubdivision.GetInRange(staticShapes, CFixedVector2D(x0, z0), CFixedVector2D(x1, z1));
     909    for (int i = 0; i < staticShapes.size(); ++i)
    906910    {
    907911        std::map<u32, StaticShape>::iterator it = m_StaticShapes.find(staticShapes[i]);
    908912        ENSURE(it != m_StaticShapes.end());
  • simulation2/components/CCmpRangeManager.cpp

     
    2121#include "ICmpRangeManager.h"
    2222
    2323#include "ICmpTerrain.h"
     24#include "simulation2/system/EntityMap.h"
    2425#include "simulation2/MessageTypes.h"
    2526#include "simulation2/components/ICmpPosition.h"
    2627#include "simulation2/components/ICmpTerritoryManager.h"
     
    3738#include "ps/Overlay.h"
    3839#include "ps/Profile.h"
    3940#include "renderer/Scene.h"
     41#include "lib/ps_stl.h"
    4042
     43
    4144#define DEBUG_RANGE_MANAGER_BOUNDS 0
    4245
    4346/**
     
    6164 * Convert an owner ID (-1 = unowned, 0 = gaia, 1..30 = players)
    6265 * into a 32-bit mask for quick set-membership tests.
    6366 */
    64 static u32 CalcOwnerMask(player_id_t owner)
     67static inline u32 CalcOwnerMask(player_id_t owner)
    6568{
    6669    if (owner >= -1 && owner < 31)
    6770        return 1 << (1+owner);
     
    7275/**
    7376 * Returns LOS mask for given player.
    7477 */
    75 static u32 CalcPlayerLosMask(player_id_t player)
     78static inline u32 CalcPlayerLosMask(player_id_t player)
    7679{
    7780    if (player > 0 && player <= 16)
    7881        return ICmpRangeManager::LOS_MASK << (2*(player-1));
     
    210213 */
    211214struct EntityDistanceOrdering
    212215{
    213     EntityDistanceOrdering(const std::map<entity_id_t, EntityData>& entities, const CFixedVector2D& source) :
     216    EntityDistanceOrdering(const EntityMap<EntityData>& entities, const CFixedVector2D& source) :
    214217        m_EntityData(entities), m_Source(source)
    215218    {
    216219    }
     
    224227        return (vecA.CompareLength(vecB) < 0);
    225228    }
    226229
    227     const std::map<entity_id_t, EntityData>& m_EntityData;
     230    const EntityMap<EntityData>& m_EntityData;
    228231    CFixedVector2D m_Source;
    229232
    230233private:
     
    271274    // Range query state:
    272275    tag_t m_QueryNext; // next allocated id
    273276    std::map<tag_t, Query> m_Queries;
    274     std::map<entity_id_t, EntityData> m_EntityData;
    275     SpatialSubdivision<entity_id_t> m_Subdivision; // spatial index of m_EntityData
     277    EntityMap<EntityData> m_EntityData;
    276278
     279    SpatialSubdivision m_Subdivision; // spatial index of m_EntityData
     280
    277281    // LOS state:
    278282
    279283    std::map<player_id_t, bool> m_LosRevealAll;
     
    319323
    320324        // Initialise with bogus values (these will get replaced when
    321325        // SetBounds is called)
    322         ResetSubdivisions(entity_pos_t::FromInt(1), entity_pos_t::FromInt(1));
     326        ResetSubdivisions(entity_pos_t::FromInt(1024), entity_pos_t::FromInt(1024));
    323327
    324328        // The whole map should be visible to Gaia by default, else e.g. animals
    325329        // will get confused when trying to run from enemies
     
    349353
    350354        serialize.NumberU32_Unbounded("query next", m_QueryNext);
    351355        SerializeMap<SerializeU32_Unbounded, SerializeQuery>()(serialize, "queries", m_Queries, GetSimContext());
    352         SerializeMap<SerializeU32_Unbounded, SerializeEntityData>()(serialize, "entity data", m_EntityData);
     356        SerializeEntityMap<SerializeEntityData>()(serialize, "entity data", m_EntityData);
    353357
    354358        SerializeMap<SerializeI32_Unbounded, SerializeBool>()(serialize, "los reveal all", m_LosRevealAll);
    355359        serialize.Bool("los circular", m_LosCircular);
     
    411415            }
    412416
    413417            // Remember this entity
    414             m_EntityData.insert(std::make_pair(ent, entdata));
    415 
     418            m_EntityData.insert(ent, entdata);
    416419            break;
    417420        }
    418421        case MT_PositionChanged:
     
    420423            const CMessagePositionChanged& msgData = static_cast<const CMessagePositionChanged&> (msg);
    421424            entity_id_t ent = msgData.entity;
    422425
    423             std::map<entity_id_t, EntityData>::iterator it = m_EntityData.find(ent);
     426            EntityMap<EntityData>::iterator it = m_EntityData.find(ent);
    424427
    425428            // Ignore if we're not already tracking this entity
    426429            if (it == m_EntityData.end())
     
    467470            const CMessageOwnershipChanged& msgData = static_cast<const CMessageOwnershipChanged&> (msg);
    468471            entity_id_t ent = msgData.entity;
    469472
    470             std::map<entity_id_t, EntityData>::iterator it = m_EntityData.find(ent);
     473            EntityMap<EntityData>::iterator it = m_EntityData.find(ent);
    471474
    472475            // Ignore if we're not already tracking this entity
    473476            if (it == m_EntityData.end())
     
    490493            const CMessageDestroy& msgData = static_cast<const CMessageDestroy&> (msg);
    491494            entity_id_t ent = msgData.entity;
    492495
    493             std::map<entity_id_t, EntityData>::iterator it = m_EntityData.find(ent);
     496            EntityMap<EntityData>::iterator it = m_EntityData.find(ent);
    494497
    495498            // Ignore if we're not already tracking this entity
    496499            if (it == m_EntityData.end())
     
    512515            const CMessageVisionRangeChanged& msgData = static_cast<const CMessageVisionRangeChanged&> (msg);
    513516            entity_id_t ent = msgData.entity;
    514517
    515             std::map<entity_id_t, EntityData>::iterator it = m_EntityData.find(ent);
     518            EntityMap<EntityData>::iterator it = m_EntityData.find(ent);
    516519
    517520            // Ignore if we're not already tracking this entity
    518521            if (it == m_EntityData.end())
     
    576579
    577580        std::vector<std::vector<u16> > oldPlayerCounts = m_LosPlayerCounts;
    578581        std::vector<u32> oldStateRevealed = m_LosStateRevealed;
    579         SpatialSubdivision<entity_id_t> oldSubdivision = m_Subdivision;
     582        SpatialSubdivision oldSubdivision = m_Subdivision;
    580583
    581584        ResetDerivedData(true);
    582585
     
    637640        m_LosStateRevealed.clear();
    638641        m_LosStateRevealed.resize(m_TerrainVerticesPerSide*m_TerrainVerticesPerSide);
    639642
    640         for (std::map<entity_id_t, EntityData>::const_iterator it = m_EntityData.begin(); it != m_EntityData.end(); ++it)
     643        for (EntityMap<EntityData>::const_iterator it = m_EntityData.begin(); it != m_EntityData.end(); ++it)
    641644        {
    642645            if (it->second.inWorld)
    643646                LosAdd(it->second.owner, it->second.visionRange, CFixedVector2D(it->second.x, it->second.z));
     
    663666        // (TODO: find the optimal number instead of blindly guessing)
    664667        m_Subdivision.Reset(x1, z1, entity_pos_t::FromInt(8*TERRAIN_TILE_SIZE));
    665668
    666         for (std::map<entity_id_t, EntityData>::const_iterator it = m_EntityData.begin(); it != m_EntityData.end(); ++it)
     669        for (EntityMap<EntityData>::const_iterator it = m_EntityData.begin(); it != m_EntityData.end(); ++it)
    667670        {
    668671            if (it->second.inWorld)
    669672                m_Subdivision.Add(it->first, CFixedVector2D(it->second.x, it->second.z));
     
    794797
    795798        u32 ownerMask = CalcOwnerMask(player);
    796799
    797         for (std::map<entity_id_t, EntityData>::const_iterator it = m_EntityData.begin(); it != m_EntityData.end(); ++it)
     800        for (EntityMap<EntityData>::const_iterator it = m_EntityData.begin(); it != m_EntityData.end(); ++it)
    798801        {
    799802            // Check owner and add to list if it matches
    800803            if (CalcOwnerMask(it->second.owner) & ownerMask)
     
    822825        // Store a queue of all messages before sending any, so we can assume
    823826        // no entities will move until we've finished checking all the ranges
    824827        std::vector<std::pair<entity_id_t, CMessageRangeUpdate> > messages;
     828        std::vector<entity_id_t> results;
     829        std::vector<entity_id_t> added;
     830        std::vector<entity_id_t> removed;
    825831
    826832        for (std::map<tag_t, Query>::iterator it = m_Queries.begin(); it != m_Queries.end(); ++it)
    827833        {
    828             Query& q = it->second;
     834            Query& query = it->second;
    829835
    830             if (!q.enabled)
     836            if (!query.enabled)
    831837                continue;
    832838
    833             CmpPtr<ICmpPosition> cmpSourcePosition(q.source);
     839            CmpPtr<ICmpPosition> cmpSourcePosition(query.source);           
    834840            if (!cmpSourcePosition || !cmpSourcePosition->IsInWorld())
    835841                continue;
    836842
    837             std::vector<entity_id_t> r;
    838             r.reserve(q.lastMatch.size());
     843            results.clear();
     844            results.reserve(query.lastMatch.size());
     845            PerformQuery(query, results);
    839846
    840             PerformQuery(q, r);
    841 
    842847            // Compute the changes vs the last match
    843             std::vector<entity_id_t> added;
    844             std::vector<entity_id_t> removed;
    845             std::set_difference(r.begin(), r.end(), q.lastMatch.begin(), q.lastMatch.end(), std::back_inserter(added));
    846             std::set_difference(q.lastMatch.begin(), q.lastMatch.end(), r.begin(), r.end(), std::back_inserter(removed));
     848            added.clear();
     849            removed.clear();
     850            size_t resultsSize = results.size();
     851            size_t lastMatchSize = query.lastMatch.size();
    847852
     853            // check results for any new ones:
     854            for (size_t i = 0; i < resultsSize; ++i)
     855            {
     856                entity_id_t entity = results[i];
     857                if (ps::exists_in(query.lastMatch, entity) == false)
     858                    added.push_back(entity); // not in last matches, so it's NEW
     859            }
     860            // check last matches for any missing ones:
     861            for (size_t i = 0; i < lastMatchSize; ++i)
     862            {
     863                entity_id_t entity = query.lastMatch[i];
     864                if (ps::exists_in(results, entity) == false)
     865                    removed.push_back(entity); // not in results, so it's moved out of range
     866            }
    848867            if (added.empty() && removed.empty())
    849868                continue;
    850869
    851870            // Return the 'added' list sorted by distance from the entity
    852871            // (Don't bother sorting 'removed' because they might not even have positions or exist any more)
    853             CFixedVector2D pos = cmpSourcePosition->GetPosition2D();
    854             std::stable_sort(added.begin(), added.end(), EntityDistanceOrdering(m_EntityData, pos));
     872            if (!added.empty())
     873            {
     874                CFixedVector2D pos = cmpSourcePosition->GetPosition2D();
     875                std::stable_sort(&added[0], &added[0] + added.size(), EntityDistanceOrdering(m_EntityData, pos));
     876            }
    855877
    856             messages.push_back(std::make_pair(q.source.GetId(), CMessageRangeUpdate(it->first)));
    857             messages.back().second.added.swap(added);
    858             messages.back().second.removed.swap(removed);
    859 
    860             it->second.lastMatch.swap(r);
     878            messages.resize(messages.size() + 1);
     879            std::pair<entity_id_t, CMessageRangeUpdate>& back = messages.back();
     880            back.first = query.source.GetId();
     881            back.second.tag = it->first;
     882            back.second.added.swap(added);
     883            back.second.removed.swap(removed);
     884            it->second.lastMatch.swap(results);
    861885        }
    862886
     887        CComponentManager& cmpMgr = GetSimContext().GetComponentManager();
    863888        for (size_t i = 0; i < messages.size(); ++i)
    864             GetSimContext().GetComponentManager().PostMessage(messages[i].first, messages[i].second);
     889            cmpMgr.PostMessage(messages[i].first, messages[i].second);
    865890    }
    866891
    867892    /**
     
    905930        // Special case: range -1.0 means check all entities ignoring distance
    906931        if (q.maxRange == entity_pos_t::FromInt(-1))
    907932        {
    908             for (std::map<entity_id_t, EntityData>::const_iterator it = m_EntityData.begin(); it != m_EntityData.end(); ++it)
     933            for (EntityMap<EntityData>::const_iterator it = m_EntityData.begin(); it != m_EntityData.end(); ++it)
    909934            {
    910935                if (!TestEntityQuery(q, it->first, it->second))
    911936                    continue;
     
    920945            CFixedVector3D pos3d = cmpSourcePosition->GetPosition()+
    921946                CFixedVector3D(entity_pos_t::Zero(), q.elevationBonus, entity_pos_t::Zero()) ;
    922947            // Get a quick list of entities that are potentially in range, with a cutoff of 2*maxRange
    923             std::vector<entity_id_t> ents = m_Subdivision.GetNear(pos, q.maxRange*2);
     948            SpatialQueryArray ents;
     949            m_Subdivision.GetNear(ents, pos, q.maxRange*2);
    924950
    925             for (size_t i = 0; i < ents.size(); ++i)
     951            for (int i = 0; i < ents.size(); ++i)
    926952            {
    927                 std::map<entity_id_t, EntityData>::const_iterator it = m_EntityData.find(ents[i]);
     953                EntityMap<EntityData>::const_iterator it = m_EntityData.find(ents[i]);
    928954                ENSURE(it != m_EntityData.end());
    929955
    930956                if (!TestEntityQuery(q, it->first, it->second))
     
    950976                }
    951977
    952978                r.push_back(it->first);
    953 
    954979            }
    955980        }
    956981        // check a regular range (i.e. not the entire world, and not parabolic)
     
    957982        else
    958983        {
    959984            // Get a quick list of entities that are potentially in range
    960             std::vector<entity_id_t> ents = m_Subdivision.GetNear(pos, q.maxRange);
    961 
    962             for (size_t i = 0; i < ents.size(); ++i)
     985            SpatialQueryArray ents;
     986            m_Subdivision.GetNear(ents, pos, q.maxRange);
     987           
     988            for (int i = 0; i < ents.size(); ++i)
    963989            {
    964                 std::map<entity_id_t, EntityData>::const_iterator it = m_EntityData.find(ents[i]);
     990                EntityMap<EntityData>::const_iterator it = m_EntityData.find(ents[i]);
    965991                ENSURE(it != m_EntityData.end());
    966992
    967993                if (!TestEntityQuery(q, it->first, it->second))
     
    9801006                }
    9811007
    9821008                r.push_back(it->first);
    983 
    9841009            }
    9851010        }
    9861011    }
     
    11351160    {
    11361161        if (!m_DebugOverlayEnabled)
    11371162            return;
    1138         CColor enabledRingColour(0, 1, 0, 1);
    1139         CColor disabledRingColour(1, 0, 0, 1);
    1140         CColor rayColour(1, 1, 0, 0.2f);
     1163        static CColor disabledRingColour(1, 0, 0, 1);   // red
     1164        static CColor enabledRingColour(0, 1, 0, 1);    // green
     1165        static CColor subdivColour(0, 0, 1, 1);         // blue
     1166        static CColor rayColour(1, 1, 0, 0.2f);
    11411167
    11421168        if (m_DebugOverlayDirty)
    11431169        {
     
    12441270                }
    12451271            }
    12461272
     1273            // render subdivision grid
     1274            float divSize = m_Subdivision.GetDivisionSize().ToFloat();
     1275            int width = m_Subdivision.GetWidth();
     1276            int height = m_Subdivision.GetHeight();
     1277            for (int x = 0; x < width; ++x)
     1278            {
     1279                for (int y = 0; y < height; ++y)
     1280                {
     1281                    m_DebugOverlayLines.push_back(SOverlayLine());
     1282                    m_DebugOverlayLines.back().m_Color = subdivColour;
     1283                   
     1284                    float xpos = x*divSize + divSize/2;
     1285                    float zpos = y*divSize + divSize/2;
     1286                    SimRender::ConstructSquareOnGround(GetSimContext(), xpos, zpos, divSize, divSize, 0.0f,
     1287                        m_DebugOverlayLines.back(), false, 1.0f);
     1288                }
     1289            }
     1290
    12471291            m_DebugOverlayDirty = false;
    12481292        }
    12491293
     
    12641308
    12651309    virtual void SetEntityFlag(entity_id_t ent, std::string identifier, bool value)
    12661310    {
    1267         std::map<entity_id_t, EntityData>::iterator it = m_EntityData.find(ent);
     1311        EntityMap<EntityData>::iterator it = m_EntityData.find(ent);
    12681312
    12691313        // We don't have this entity
    12701314        if (it == m_EntityData.end())
  • simulation2/helpers/Spatial.h

     
    2121#include "simulation2/serialization/SerializeTemplates.h"
    2222
    2323/**
     24 * A simple fixed-size array that works similar to an std::vector
     25 * but is obviously limited in its max items
     26 */
     27struct SpatialQueryArray
     28{
     29    enum { MAX_COUNT = 1024 };
     30    int count;
     31    uint32_t items[MAX_COUNT];
     32
     33    inline SpatialQueryArray() : count(0) {}
     34    inline const uint32_t& operator[](int index) const { return items[index]; }
     35    inline uint32_t& operator[](int index) { return items[index]; }
     36    inline int size() const { return count; }
     37    inline void clear() { count = 0; }
     38    void make_unique() // removes any duplicate entries
     39    {
     40        if (count)
     41            count = int(std::unique(items, items + count) - items);
     42    }
     43};
     44
     45/**
    2446 * A very basic subdivision scheme for finding items in ranges.
    2547 * Items are stored in lists in fixed-size divisions.
    2648 * Items have a size (min/max values of their axis-aligned bounding box)
     
    3456 *
    3557 * (TODO: maybe an adaptive quadtree would be better than fixed sizes?)
    3658 */
    37 template<typename T>
    3859class SpatialSubdivision
    3960{
     61    struct SubDivisionGrid
     62    {
     63        std::vector<uint32_t> items;
     64
     65        inline void push_back(uint32_t value)
     66        {
     67            items.push_back(value);
     68        }
     69
     70        inline void erase(int index)
     71        {
     72            // Delete by swapping with the last element then popping
     73            if ((int)items.size() > 1) // but only if we have more than 1 elements
     74                items[index] = items.back();
     75            items.pop_back();
     76        }
     77
     78        void copy_items(SpatialQueryArray& out)
     79        {
     80            if (items.empty())
     81                return; // nothing to copy
     82
     83            int dsti = out.count;               // the index in [out] where to start copying
     84            int count = (int)items.size();
     85            if ((dsti + count) > SpatialQueryArray::MAX_COUNT)
     86                count = SpatialQueryArray::MAX_COUNT - dsti; // silently fail to copy overflowing items
     87            uint32_t* dst = &out.items[dsti];
     88            uint32_t* src = &items[0];
     89            for (int i = 0; i < count; ++i) // copy all items
     90                dst[i] = src[i];
     91            out.count += count;
     92        }
     93    };
     94
     95
     96    entity_pos_t m_DivisionSize;
     97    SubDivisionGrid* m_Divisions;
     98    uint32_t m_DivisionsW;
     99    uint32_t m_DivisionsH;
     100
     101    friend struct SerializeSubDivisionGrid;
     102    friend struct SerializeSpatialSubdivision;
     103
    40104public:
    41     SpatialSubdivision() :
    42         m_DivisionsW(0), m_DivisionsH(0)
     105    SpatialSubdivision() : m_Divisions(NULL), m_DivisionsW(0), m_DivisionsH(0)
    43106    {
    44107    }
     108    ~SpatialSubdivision()
     109    {
     110        delete[] m_Divisions;
     111    }
     112    SpatialSubdivision(const SpatialSubdivision& rhs)
     113    {
     114        m_DivisionSize = rhs.m_DivisionSize;
     115        m_DivisionsW = rhs.m_DivisionsW;
     116        m_DivisionsH = rhs.m_DivisionsH;
     117        size_t n = m_DivisionsW * m_DivisionsH;
     118        m_Divisions = new SubDivisionGrid[n];
     119        for (size_t i = 0; i < n; ++i)
     120            m_Divisions[i] = rhs.m_Divisions[i]; // just fall back to piecemeal copy
     121    }
     122    SpatialSubdivision& operator=(const SpatialSubdivision& rhs)
     123    {
     124        if (this != &rhs)
     125        {
     126            m_DivisionSize = rhs.m_DivisionSize;
     127            size_t n = rhs.m_DivisionsW * rhs.m_DivisionsH;
     128            if (m_DivisionsW != rhs.m_DivisionsW || m_DivisionsH != rhs.m_DivisionsH)
     129                Create(n); // size changed, recreate
     130           
     131            m_DivisionsW = rhs.m_DivisionsW;
     132            m_DivisionsH = rhs.m_DivisionsH;
     133            for (size_t i = 0; i < n; ++i)
     134                m_Divisions[i] = rhs.m_Divisions[i]; // just fall back to piecemeal copy
     135        }
     136        return *this;
     137    }
    45138
     139    inline entity_pos_t GetDivisionSize() const { return m_DivisionSize; }
     140    inline uint32_t GetWidth() const { return m_DivisionsW; }
     141    inline uint32_t GetHeight() const { return m_DivisionsH; }
     142
     143    void Create(size_t count)
     144    {
     145        if (m_Divisions) delete[] m_Divisions;
     146        m_Divisions = new SubDivisionGrid[count];
     147    }
     148
    46149    /**
    47150     * Equivalence test (ignoring order of items within each subdivision)
    48151     */
     
    51154        if (m_DivisionSize != rhs.m_DivisionSize || m_DivisionsW != rhs.m_DivisionsW || m_DivisionsH != rhs.m_DivisionsH)
    52155            return false;
    53156       
    54         for (u32 j = 0; j < m_DivisionsH; ++j)
     157        uint32_t n = m_DivisionsH * m_DivisionsW;
     158        for (uint32_t i = 0; i < n; ++i)
    55159        {
    56             for (u32 i = 0; i < m_DivisionsW; ++i)
    57             {
    58                 std::vector<T> div1 = m_Divisions.at(i + j*m_DivisionsW);
    59                 std::vector<T> div2 = rhs.m_Divisions.at(i + j*m_DivisionsW);
    60                 std::sort(div1.begin(), div1.end());
    61                 std::sort(div2.begin(), div2.end());
    62                 if (div1 != div2)
    63                     return false;
    64             }
     160            if (m_Divisions[i].items.size() != rhs.m_Divisions[i].items.size())
     161                return false;
     162
     163            // don't bother optimizing this, this is only used in the TESTING SUITE
     164            std::vector<uint32_t> a = m_Divisions[i].items;
     165            std::vector<uint32_t> b = rhs.m_Divisions[i].items;
     166            std::sort(a.begin(), a.end());
     167            std::sort(b.begin(), b.end());
     168            if (a != b)
     169                return false;
    65170        }
    66 
    67171        return true;
    68172    }
    69173
    70     bool operator!=(const SpatialSubdivision& rhs)
     174    inline bool operator!=(const SpatialSubdivision& rhs)
    71175    {
    72176        return !(*this == rhs);
    73177    }
     
    77181        m_DivisionSize = divisionSize;
    78182        m_DivisionsW = (maxX / m_DivisionSize).ToInt_RoundToInfinity();
    79183        m_DivisionsH = (maxZ / m_DivisionSize).ToInt_RoundToInfinity();
    80         m_Divisions.clear();
    81         m_Divisions.resize(m_DivisionsW * m_DivisionsH);
     184
     185        Create(m_DivisionsW * m_DivisionsH);
    82186    }
    83187
     188
    84189    /**
    85190     * Add an item with the given 'to' size.
    86191     * The item must not already be present.
    87192     */
    88     void Add(T item, CFixedVector2D toMin, CFixedVector2D toMax)
     193    void Add(uint32_t item, CFixedVector2D toMin, CFixedVector2D toMax)
    89194    {
    90195        ENSURE(toMin.X <= toMax.X && toMin.Y <= toMax.Y);
    91196
     
    97202        {
    98203            for (u32 i = i0; i <= i1; ++i)
    99204            {
    100                 std::vector<T>& div = m_Divisions.at(i + j*m_DivisionsW);
    101                 div.push_back(item);
     205                m_Divisions[i + j*m_DivisionsW].push_back(item);
    102206            }
    103207        }
    104208    }
     
    108212     * The item should already be present.
    109213     * The size must match the size that was last used when adding the item.
    110214     */
    111     void Remove(T item, CFixedVector2D fromMin, CFixedVector2D fromMax)
     215    void Remove(uint32_t item, CFixedVector2D fromMin, CFixedVector2D fromMax)
    112216    {
    113217        ENSURE(fromMin.X <= fromMax.X && fromMin.Y <= fromMax.Y);
    114218
     
    120224        {
    121225            for (u32 i = i0; i <= i1; ++i)
    122226            {
    123                 std::vector<T>& div = m_Divisions.at(i + j*m_DivisionsW);
    124 
    125                 for (u32 n = 0; n < div.size(); ++n)
     227                SubDivisionGrid& div = m_Divisions[i + j*m_DivisionsW];
     228                int size = div.items.size();
     229                for (int n = 0; n < size; ++n)
    126230                {
    127                     if (div[n] == item)
     231                    if (div.items[n] == item)
    128232                    {
    129                         // Delete by swapping with the last element then popping
    130                         div[n] = div.back();
    131                         div.pop_back();
     233                        div.erase(n);
    132234                        break;
    133235                    }
    134236                }
     
    139241    /**
    140242     * Equivalent to Remove() then Add(), but potentially faster.
    141243     */
    142     void Move(T item, CFixedVector2D fromMin, CFixedVector2D fromMax, CFixedVector2D toMin, CFixedVector2D toMax)
     244    void Move(uint32_t item, CFixedVector2D fromMin, CFixedVector2D fromMax, CFixedVector2D toMin, CFixedVector2D toMax)
    143245    {
    144246        // Skip the work if we're staying in the same divisions
    145247        if (GetIndex0(fromMin) == GetIndex0(toMin) && GetIndex1(fromMax) == GetIndex1(toMax))
     
    153255     * Convenience function for Add() of individual points.
    154256     * (Note that points on a boundary may occupy multiple divisions.)
    155257     */
    156     void Add(T item, CFixedVector2D to)
     258    void Add(uint32_t item, CFixedVector2D to)
    157259    {
    158260        Add(item, to, to);
    159261    }
     
    161263    /**
    162264     * Convenience function for Remove() of individual points.
    163265     */
    164     void Remove(T item, CFixedVector2D from)
     266    void Remove(uint32_t item, CFixedVector2D from)
    165267    {
    166268        Remove(item, from, from);
    167269    }
     
    169271    /**
    170272     * Convenience function for Move() of individual points.
    171273     */
    172     void Move(T item, CFixedVector2D from, CFixedVector2D to)
     274    void Move(uint32_t item, CFixedVector2D from, CFixedVector2D to)
    173275    {
    174276        Move(item, from, from, to, to);
    175277    }
     
    178280     * Returns a sorted list of unique items that includes all items
    179281     * within the given axis-aligned square range.
    180282     */
    181     std::vector<T> GetInRange(CFixedVector2D posMin, CFixedVector2D posMax)
     283    void GetInRange(SpatialQueryArray& out, CFixedVector2D posMin, CFixedVector2D posMax)
    182284    {
    183         std::vector<T> ret;
    184 
     285        out.clear();
    185286        ENSURE(posMin.X <= posMax.X && posMin.Y <= posMax.Y);
    186287
    187288        u32 i0 = GetI0(posMin.X);
     
    192293        {
    193294            for (u32 i = i0; i <= i1; ++i)
    194295            {
    195                 std::vector<T>& div = m_Divisions.at(i + j*m_DivisionsW);
    196                 ret.insert(ret.end(), div.begin(), div.end());
     296                m_Divisions[i + j*m_DivisionsW].copy_items(out);
    197297            }
    198298        }
    199 
    200         // Remove duplicates
    201         std::sort(ret.begin(), ret.end());
    202         ret.erase(std::unique(ret.begin(), ret.end()), ret.end());
    203 
    204         return ret;
     299        // some buildings span several tiles, so we need to make it unique
     300        out.make_unique();
    205301    }
    206302
    207303    /**
     
    208304     * Returns a sorted list of unique items that includes all items
    209305     * within the given circular distance of the given point.
    210306     */
    211     std::vector<T> GetNear(CFixedVector2D pos, entity_pos_t range)
     307    void GetNear(SpatialQueryArray& out, CFixedVector2D pos, entity_pos_t range)
    212308    {
    213309        // TODO: be cleverer and return a circular pattern of divisions,
    214310        // not this square over-approximation
    215 
    216         return GetInRange(pos - CFixedVector2D(range, range), pos + CFixedVector2D(range, range));
     311        CFixedVector2D r(range, range);
     312        GetInRange(out, pos - r, pos + r);
    217313    }
    218314
    219315private:
     
    221317    // (avoiding out-of-bounds accesses, and rounding correctly so that
    222318    // points precisely between divisions are counted in both):
    223319
    224     u32 GetI0(entity_pos_t x)
     320    uint32_t GetI0(entity_pos_t x)
    225321    {
    226322        return Clamp((x / m_DivisionSize).ToInt_RoundToInfinity()-1, 0, (int)m_DivisionsW-1);
    227323    }
    228324
    229     u32 GetJ0(entity_pos_t z)
     325    uint32_t GetJ0(entity_pos_t z)
    230326    {
    231327        return Clamp((z / m_DivisionSize).ToInt_RoundToInfinity()-1, 0, (int)m_DivisionsH-1);
    232328    }
    233329
    234     u32 GetI1(entity_pos_t x)
     330    uint32_t GetI1(entity_pos_t x)
    235331    {
    236332        return Clamp((x / m_DivisionSize).ToInt_RoundToNegInfinity(), 0, (int)m_DivisionsW-1);
    237333    }
    238334
    239     u32 GetJ1(entity_pos_t z)
     335    uint32_t GetJ1(entity_pos_t z)
    240336    {
    241337        return Clamp((z / m_DivisionSize).ToInt_RoundToNegInfinity(), 0, (int)m_DivisionsH-1);
    242338    }
    243339
    244     u32 GetIndex0(CFixedVector2D pos)
     340    uint32_t GetIndex0(CFixedVector2D pos)
    245341    {
    246342        return GetI0(pos.X) + GetJ0(pos.Y)*m_DivisionsW;
    247343    }
    248344
    249     u32 GetIndex1(CFixedVector2D pos)
     345    uint32_t GetIndex1(CFixedVector2D pos)
    250346    {
    251347        return GetI1(pos.X) + GetJ1(pos.Y)*m_DivisionsW;
    252348    }
    253 
    254     entity_pos_t m_DivisionSize;
    255     std::vector<std::vector<T> > m_Divisions;
    256     u32 m_DivisionsW;
    257     u32 m_DivisionsH;
    258 
    259     template<typename ELEM> friend struct SerializeSpatialSubdivision;
    260349};
    261350
    262351/**
    263352 * Serialization helper template for SpatialSubdivision
    264353 */
    265 template<typename ELEM>
    266354struct SerializeSpatialSubdivision
    267355{
    268     template<typename T>
    269     void operator()(ISerializer& serialize, const char* UNUSED(name), SpatialSubdivision<T>& value)
     356    void operator()(ISerializer& serialize, const char* UNUSED(name), SpatialSubdivision& value)
    270357    {
    271358        serialize.NumberFixed_Unbounded("div size", value.m_DivisionSize);
    272         SerializeVector<SerializeVector<ELEM> >()(serialize, "divs", value.m_Divisions);
    273359        serialize.NumberU32_Unbounded("divs w", value.m_DivisionsW);
    274360        serialize.NumberU32_Unbounded("divs h", value.m_DivisionsH);
     361
     362        size_t count = value.m_DivisionsH * value.m_DivisionsW;
     363        for (size_t i = 0; i < count; ++i)
     364            SerializeVector<SerializeU32_Unbounded>()(serialize, "subdiv items", value.m_Divisions[i].items);
    275365    }
    276366
    277     template<typename T>
    278     void operator()(IDeserializer& serialize, const char* UNUSED(name), SpatialSubdivision<T>& value)
     367    void operator()(IDeserializer& serialize, const char* UNUSED(name), SpatialSubdivision& value)
    279368    {
    280369        serialize.NumberFixed_Unbounded("div size", value.m_DivisionSize);
    281         SerializeVector<SerializeVector<ELEM> >()(serialize, "divs", value.m_Divisions);
     370        serialize.NumberU32_Unbounded("divs w", value.m_DivisionsW);
     371        serialize.NumberU32_Unbounded("divs h", value.m_DivisionsH);
    282372
    283         u32 w, h;
    284         serialize.NumberU32_Unbounded("divs w", w);
    285         serialize.NumberU32_Unbounded("divs h", h);
    286         value.m_DivisionsW = w;
    287         value.m_DivisionsH = h;
     373        size_t count = value.m_DivisionsW * value.m_DivisionsH;
     374        value.Create(count);
     375        for (size_t i = 0; i < count; ++i)
     376            SerializeVector<SerializeU32_Unbounded>()(serialize, "subdiv items", value.m_Divisions[i].items);
    288377    }
    289378};
    290379
  • simulation2/MessageTypes.h

     
    314314public:
    315315    DEFAULT_MESSAGE_IMPL(RangeUpdate)
    316316
    317     CMessageRangeUpdate(u32 tag, const std::vector<entity_id_t>& added, const std::vector<entity_id_t>& removed) :
    318         tag(tag), added(added), removed(removed)
    319     {
    320     }
    321317
     318
    322319    u32 tag;
    323320    std::vector<entity_id_t> added;
    324321    std::vector<entity_id_t> removed;
     
    327324    // swap vectors instead of copying (to save on memory allocations),
    328325    // so add some constructors for it:
    329326
    330     CMessageRangeUpdate(u32 tag) :
    331         tag(tag)
     327    // don't init tag in empty ctor
     328    CMessageRangeUpdate()
    332329    {
    333330    }
    334 
    335     CMessageRangeUpdate(const CMessageRangeUpdate& other) :
    336         CMessage(), tag(other.tag), added(other.added), removed(other.removed)
     331    CMessageRangeUpdate(u32 tag) : tag(tag)
    337332    {
    338333    }
    339 
     334    CMessageRangeUpdate(u32 tag, const std::vector<entity_id_t>& added, const std::vector<entity_id_t>& removed)
     335        : tag(tag), added(added), removed(removed)
     336    {
     337    }
     338    CMessageRangeUpdate(const CMessageRangeUpdate& other)
     339        : CMessage(), tag(other.tag), added(other.added), removed(other.removed)
     340    {
     341    }
    340342    CMessageRangeUpdate& operator=(const CMessageRangeUpdate& other)
    341343    {
    342344        tag = other.tag;
  • simulation2/system/EntityMap.h

     
     1/* Copyright (C) 2013 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#ifndef INCLUDED_ENTITYMAP
     18#define INCLUDED_ENTITYMAP
     19
     20#include "Entity.h"
     21
     22/**
     23 * A fast replacement for map<entity_id_t, T>.
     24 * We make the following assumptions:
     25 *  - entity id's (keys) are unique and are inserted in increasing order
     26 *  - an entity id that was removed is never added again
     27 *  - modifications (add / delete) are far less frequent then look-ups
     28 *  - preformance for iteration is important
     29 */
     30template<class T> class EntityMap
     31{
     32private:
     33    EntityMap(const EntityMap&);            // non-copyable
     34    EntityMap& operator=(const EntityMap&); // non-copyable
     35
     36public:
     37    typedef entity_id_t key_type;
     38    typedef T mapped_type;
     39    template<class K, class V> struct key_val {
     40        typedef K first_type;
     41        typedef V second_type;
     42        K first;
     43        V second;
     44    };
     45    typedef key_val<entity_id_t, T> value_type;
     46
     47private:
     48    size_t m_BufferSize;        // number of elements in the buffer
     49    size_t m_BufferCapacity;    // capacity of the buffer
     50    value_type* m_Buffer;       // vector with all the mapped key-value pairs
     51
     52    size_t m_Count;             // number of 'valid' entity id's
     53
     54public:
     55
     56    inline EntityMap() : m_BufferSize(1), m_BufferCapacity(4096), m_Count(0)
     57    {
     58        // for entitymap we allocate the buffer right away
     59        // with first element in buffer being the Invalid Entity
     60        m_Buffer = (value_type*)malloc(sizeof(value_type) * (m_BufferCapacity + 1));
     61
     62        // create the first element:
     63        m_Buffer[0].first = INVALID_ENTITY;
     64        m_Buffer[1].first = 0xFFFFFFFF; // ensure end() always has 0xFFFFFFFF
     65    }
     66    inline ~EntityMap()
     67    {
     68        free(m_Buffer);
     69    }
     70
     71    // Iterators
     72    template<class U> struct _iter : public std::iterator<std::forward_iterator_tag, U>
     73    {
     74        U* val;
     75        inline _iter(U* init) : val(init) {}
     76        inline U& operator*() { return *val; }
     77        inline U* operator->() { return val; }
     78        inline _iter& operator++() // ++it
     79        {
     80            ++val;
     81            while (val->first == INVALID_ENTITY) ++val; // skip any invalid entities
     82            return *this;
     83        }
     84        inline _iter& operator++(int) // it++
     85        {
     86            U* ptr = val;
     87            ++val;
     88            while (val->first == INVALID_ENTITY) ++val; // skip any invalid entities
     89            return ptr;
     90        }
     91        inline bool operator==(_iter other) { return val == other.val; }
     92        inline bool operator!=(_iter other) { return val != other.val; }
     93        inline operator _iter<U const>() const { return _iter<U const>(val); }
     94    };
     95   
     96    typedef _iter<value_type> iterator;
     97    typedef _iter<value_type const> const_iterator;
     98
     99    inline iterator begin()
     100    {
     101        value_type* ptr = m_Buffer + 1; // skip the first INVALID_ENTITY
     102        while (ptr->first == INVALID_ENTITY) ++ptr; // skip any other invalid entities
     103        return ptr;
     104    }
     105    inline iterator end()
     106    {
     107        return iterator(m_Buffer + m_BufferSize);
     108    }
     109    inline const_iterator begin() const
     110    {
     111        value_type* ptr = m_Buffer + 1; // skip the first INVALID_ENTITY
     112        while (ptr->first == INVALID_ENTITY) ++ptr; // skip any other invalid entities
     113        return ptr;
     114    }
     115    inline const_iterator end() const
     116    {
     117        return const_iterator(m_Buffer + m_BufferSize);
     118    }
     119
     120    // Size
     121    inline bool empty() const { return m_Count == 0; }
     122    inline size_t size() const { return m_Count; }
     123
     124    // Modification
     125    void insert(const key_type key, const mapped_type& value)
     126    {
     127        if (key >= m_BufferCapacity) // do we need to resize buffer?
     128        {
     129            do { m_BufferCapacity += 4096; } while (key >= m_BufferCapacity);
     130
     131            // always allocate +1 behind the scenes, because end() must have a 0xFFFFFFFF key
     132            m_Buffer = (value_type*)realloc(m_Buffer, sizeof(value_type) * (m_BufferCapacity + 1));
     133
     134            goto fill_gaps;
     135        }
     136        else if (key > m_BufferSize) // weird insert far beyond the end
     137        {
     138fill_gaps:
     139            // set all entity id's to INVALID_ENTITY inside the new range
     140            for (size_t i = m_BufferSize; i <= key; ++i)
     141                m_Buffer[i].first = INVALID_ENTITY;
     142            m_BufferSize = key; // extend the new size
     143        }
     144
     145        value_type& item = m_Buffer[key];
     146        item.first = key;
     147        if (key == m_BufferSize) // push_back
     148        {
     149            ++m_BufferSize; // expand
     150            ++m_Count;
     151            new (&item.second) mapped_type(value); // copy ctor to init
     152            m_Buffer[m_BufferSize].first = 0xFFFFFFFF; // ensure end() always has 0xFFFFFFFF
     153        }
     154        else if(!item.first) // insert new to middle
     155        {
     156            ++m_Count;
     157            new (&item.second) mapped_type(value); // copy ctor to init
     158        }
     159        else // set existing value
     160        {
     161            item.second = value; // overwrite existing
     162        }
     163    }
     164   
     165    void erase(iterator it)
     166    {
     167        value_type* ptr = it.val;
     168        if (ptr->first != INVALID_ENTITY)
     169        {
     170            ptr->first = INVALID_ENTITY;
     171            ptr->second.~T(); // call dtor
     172            --m_Count;
     173        }
     174    }
     175    void erase(const entity_id_t key)
     176    {
     177        if (key < m_BufferSize)
     178        {
     179            value_type* ptr = m_Buffer + key;
     180            if (ptr->first != INVALID_ENTITY)
     181            {
     182                ptr->first = INVALID_ENTITY;
     183                ptr->second.~T(); // call dtor
     184                --m_Count;
     185            }
     186        }
     187    }
     188    inline void clear()
     189    {
     190        // orphan whole range
     191        value_type* ptr = m_Buffer;
     192        value_type* end = m_Buffer + m_BufferSize;
     193        for (; ptr != end; ++ptr)
     194        {
     195            if (ptr->first != INVALID_ENTITY)
     196            {
     197                ptr->first = INVALID_ENTITY;
     198                ptr->second.~T(); // call dtor
     199            }
     200        }
     201        m_Count = 0; // no more valid entities
     202    }
     203
     204    // Operations
     205    inline iterator find(const entity_id_t key)
     206    {
     207        if (key < m_BufferSize) // is this key in the range of existing entitites?
     208        {
     209            value_type* ptr = m_Buffer + key;
     210            if (ptr->first != INVALID_ENTITY)
     211                return ptr;
     212        }
     213        return m_Buffer + m_BufferSize; // return iterator end()
     214    }
     215    inline const_iterator find(const entity_id_t key) const
     216    {
     217        if (key < m_BufferSize) // is this key in the range of existing entitites?
     218        {
     219            const value_type* ptr = m_Buffer + key;
     220            if (ptr->first != INVALID_ENTITY)
     221                return ptr;
     222        }
     223        return m_Buffer + m_BufferSize; // return iterator end()
     224    }
     225    inline size_t count(const entity_id_t key) const
     226    {
     227        if (key < m_BufferSize)
     228        {
     229            if (m_Buffer[key].first != INVALID_ENTITY)
     230                return 1;
     231        }
     232        return 0;
     233    }
     234};
     235
     236template<class VSerializer>
     237struct SerializeEntityMap
     238{
     239    template<class V>
     240    void operator()(ISerializer& serialize, const char* UNUSED(name), EntityMap<V>& value)
     241    {
     242        size_t len = value.size();
     243        serialize.NumberU32_Unbounded("length", (u32)len);
     244        for (typename EntityMap<V>::iterator it = value.begin(); it != value.end(); ++it)
     245        {
     246            serialize.NumberI32_Unbounded("key", it->first);
     247            VSerializer()(serialize, "value", it->second);
     248        }
     249    }
     250
     251    template<class V>
     252    void operator()(IDeserializer& deserialize, const char* UNUSED(name), EntityMap<V>& value)
     253    {
     254        value.clear();
     255        uint32_t len;
     256        deserialize.NumberU32_Unbounded("length", len);
     257        for (size_t i = 0; i < len; ++i)
     258        {
     259            entity_id_t k;
     260            V v;
     261            deserialize.NumberU32_Unbounded("key", k);
     262            VSerializer()(deserialize, "value", v);
     263            value.insert(k, v);
     264        }
     265    }
     266};
     267
     268
     269#endif
  • simulation2/system/SimContext.cpp

     
    3434
    3535CComponentManager& CSimContext::GetComponentManager() const
    3636{
    37     ENSURE(m_ComponentManager);
    3837    return *m_ComponentManager;
    3938}
    4039