Ticket #2573: 0001-Revert-r13854-spatial-subdivision-optimisations.patch

File 0001-Revert-r13854-spatial-subdivision-optimisations.patch, 45.4 KB (added by Philip Taylor, 10 years ago)
  • deleted file source/lib/ps_stl.h

    From b6fe72e60ea20016d0df5b37e6ff548669c9acc1 Mon Sep 17 00:00:00 2001
    From: Philip Taylor <philip@zaynar.co.uk>
    Date: Tue, 20 May 2014 23:33:49 +0100
    Subject: [PATCH] Revert r13854 (spatial subdivision optimisations)
    
    The hardcoded limit on the number of returned entities causes warnings and
    buggy behaviour, especially when PickEntitiesAtPoint calls GetNear() with
    a large range.
    
    The attempted optimisations are not a good enough solution by themselves,
    and are not worth the bugs they introduced.
    ---
     source/lib/ps_stl.h                                |  101 -------
     source/simulation2/MessageTypes.h                  |   22 +-
     .../components/CCmpObstructionManager.cpp          |   30 +--
     source/simulation2/components/CCmpRangeManager.cpp |  137 ++++------
     source/simulation2/components/ICmpRangeManager.h   |    2 +-
     source/simulation2/helpers/Selection.cpp           |    5 +-
     source/simulation2/helpers/Spatial.h               |  237 +++++------------
     source/simulation2/system/EntityMap.h              |  282 --------------------
     source/simulation2/system/SimContext.cpp           |    1 +
     9 files changed, 153 insertions(+), 664 deletions(-)
     delete mode 100644 source/lib/ps_stl.h
     delete mode 100644 source/simulation2/system/EntityMap.h
    
    diff --git a/source/lib/ps_stl.h b/source/lib/ps_stl.h
    deleted file mode 100644
    index ce7eb47..0000000
    + -  
    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 
    31 namespace 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      */
    38 template<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      */
    60 template<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      */
    82 template<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
  • source/simulation2/MessageTypes.h

    diff --git a/source/simulation2/MessageTypes.h b/source/simulation2/MessageTypes.h
    index 80e9e22..8dce8a4 100644
    a b class CMessageRangeUpdate : public CMessage  
    329329public:
    330330    DEFAULT_MESSAGE_IMPL(RangeUpdate)
    331331
    332 
     332    CMessageRangeUpdate(u32 tag, const std::vector<entity_id_t>& added, const std::vector<entity_id_t>& removed) :
     333        tag(tag), added(added), removed(removed)
     334    {
     335    }
    333336
    334337    u32 tag;
    335338    std::vector<entity_id_t> added;
    public:  
    339342    // swap vectors instead of copying (to save on memory allocations),
    340343    // so add some constructors for it:
    341344
    342     // don't init tag in empty ctor
    343     CMessageRangeUpdate()
    344     {
    345     }
    346     CMessageRangeUpdate(u32 tag) : tag(tag)
     345    CMessageRangeUpdate(u32 tag) :
     346        tag(tag)
    347347    {
    348348    }
    349     CMessageRangeUpdate(u32 tag, const std::vector<entity_id_t>& added, const std::vector<entity_id_t>& removed)
    350         : tag(tag), added(added), removed(removed)
    351     {
    352     }
    353     CMessageRangeUpdate(const CMessageRangeUpdate& other)
    354         : CMessage(), tag(other.tag), added(other.added), removed(other.removed)
     349
     350    CMessageRangeUpdate(const CMessageRangeUpdate& other) :
     351        CMessage(), tag(other.tag), added(other.added), removed(other.removed)
    355352    {
    356353    }
     354
    357355    CMessageRangeUpdate& operator=(const CMessageRangeUpdate& other)
    358356    {
    359357        tag = other.tag;
  • source/simulation2/components/CCmpObstructionManager.cpp

    diff --git a/source/simulation2/components/CCmpObstructionManager.cpp b/source/simulation2/components/CCmpObstructionManager.cpp
    index fe843e8..2f5eed0 100644
    a b public:  
    124124    bool m_DebugOverlayDirty;
    125125    std::vector<SOverlayLine> m_DebugOverlayLines;
    126126
    127     SpatialSubdivision m_UnitSubdivision;
    128     SpatialSubdivision m_StaticSubdivision;
     127    SpatialSubdivision<u32> m_UnitSubdivision;
     128    SpatialSubdivision<u32> 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;
    public:  
    161161
    162162        // Initialise with bogus values (these will get replaced when
    163163        // SetBounds is called)
    164         ResetSubdivisions(entity_pos_t::FromInt(1024), entity_pos_t::FromInt(1024));
     164        ResetSubdivisions(entity_pos_t::FromInt(1), entity_pos_t::FromInt(1));
    165165    }
    166166
    167167    virtual void Deinit()
    public:  
    171171    template<typename S>
    172172    void SerializeCommon(S& serialize)
    173173    {
    174         SerializeSpatialSubdivision()(serialize, "unit subdiv", m_UnitSubdivision);
    175         SerializeSpatialSubdivision()(serialize, "static subdiv", m_StaticSubdivision);
     174        SerializeSpatialSubdivision<SerializeU32_Unbounded>()(serialize, "unit subdiv", m_UnitSubdivision);
     175        SerializeSpatialSubdivision<SerializeU32_Unbounded>()(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);
    bool CCmpObstructionManager::TestLine(const IObstructionTestFilter& filter, enti  
    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     SpatialQueryArray unitShapes;
    548     m_UnitSubdivision.GetInRange(unitShapes, posMin, posMax);
    549     for (int i = 0; i < unitShapes.size(); ++i)
     547    std::vector<u32> unitShapes = m_UnitSubdivision.GetInRange(posMin, posMax);
     548    for (size_t i = 0; i < unitShapes.size(); ++i)
    550549    {
    551550        std::map<u32, UnitShape>::iterator it = m_UnitShapes.find(unitShapes[i]);
    552551        ENSURE(it != m_UnitShapes.end());
    bool CCmpObstructionManager::TestLine(const IObstructionTestFilter& filter, enti  
    560559            return true;
    561560    }
    562561
    563     SpatialQueryArray staticShapes;
    564     m_StaticSubdivision.GetInRange(staticShapes, posMin, posMax);
    565     for (int i = 0; i < staticShapes.size(); ++i)
     562    std::vector<u32> staticShapes = m_StaticSubdivision.GetInRange(posMin, posMax);
     563    for (size_t i = 0; i < staticShapes.size(); ++i)
    566564    {
    567565        std::map<u32, StaticShape>::iterator it = m_StaticShapes.find(staticShapes[i]);
    568566        ENSURE(it != m_StaticShapes.end());
    void CCmpObstructionManager::GetObstructionsInRange(const IObstructionTestFilter  
    882880
    883881    ENSURE(x0 <= x1 && z0 <= z1);
    884882
    885     SpatialQueryArray unitShapes;
    886     m_UnitSubdivision.GetInRange(unitShapes, CFixedVector2D(x0, z0), CFixedVector2D(x1, z1));
    887     for (int i = 0; i < unitShapes.size(); ++i)
     883    std::vector<u32> unitShapes = m_UnitSubdivision.GetInRange(CFixedVector2D(x0, z0), CFixedVector2D(x1, z1));
     884    for (size_t i = 0; i < unitShapes.size(); ++i)
    888885    {
    889886        std::map<u32, UnitShape>::iterator it = m_UnitShapes.find(unitShapes[i]);
    890887        ENSURE(it != m_UnitShapes.end());
    void CCmpObstructionManager::GetObstructionsInRange(const IObstructionTestFilter  
    904901        squares.push_back(s);
    905902    }
    906903
    907     SpatialQueryArray staticShapes;
    908     m_StaticSubdivision.GetInRange(staticShapes, CFixedVector2D(x0, z0), CFixedVector2D(x1, z1));
    909     for (int i = 0; i < staticShapes.size(); ++i)
     904    std::vector<u32> staticShapes = m_StaticSubdivision.GetInRange(CFixedVector2D(x0, z0), CFixedVector2D(x1, z1));
     905    for (size_t i = 0; i < staticShapes.size(); ++i)
    910906    {
    911907        std::map<u32, StaticShape>::iterator it = m_StaticShapes.find(staticShapes[i]);
    912908        ENSURE(it != m_StaticShapes.end());
  • source/simulation2/components/CCmpRangeManager.cpp

    diff --git a/source/simulation2/components/CCmpRangeManager.cpp b/source/simulation2/components/CCmpRangeManager.cpp
    index a281332..e4504f4 100644
    a b  
    2121#include "ICmpRangeManager.h"
    2222
    2323#include "ICmpTerrain.h"
    24 #include "simulation2/system/EntityMap.h"
    2524#include "simulation2/MessageTypes.h"
    2625#include "simulation2/components/ICmpPosition.h"
    2726#include "simulation2/components/ICmpTerritoryManager.h"
     
    3736#include "ps/Overlay.h"
    3837#include "ps/Profile.h"
    3938#include "renderer/Scene.h"
    40 #include "lib/ps_stl.h"
    41 
    4239
    4340#define DEBUG_RANGE_MANAGER_BOUNDS 0
    4441
    struct Query  
    6360 * Convert an owner ID (-1 = unowned, 0 = gaia, 1..30 = players)
    6461 * into a 32-bit mask for quick set-membership tests.
    6562 */
    66 static inline u32 CalcOwnerMask(player_id_t owner)
     63static u32 CalcOwnerMask(player_id_t owner)
    6764{
    6865    if (owner >= -1 && owner < 31)
    6966        return 1 << (1+owner);
    static inline u32 CalcOwnerMask(player_id_t owner)  
    7471/**
    7572 * Returns LOS mask for given player.
    7673 */
    77 static inline u32 CalcPlayerLosMask(player_id_t player)
     74static u32 CalcPlayerLosMask(player_id_t player)
    7875{
    7976    if (player > 0 && player <= 16)
    8077        return ICmpRangeManager::LOS_MASK << (2*(player-1));
    struct SerializeEntityData  
    211208 */
    212209struct EntityDistanceOrdering
    213210{
    214     EntityDistanceOrdering(const EntityMap<EntityData>& entities, const CFixedVector2D& source) :
     211    EntityDistanceOrdering(const std::map<entity_id_t, EntityData>& entities, const CFixedVector2D& source) :
    215212        m_EntityData(entities), m_Source(source)
    216213    {
    217214    }
    struct EntityDistanceOrdering  
    225222        return (vecA.CompareLength(vecB) < 0);
    226223    }
    227224
    228     const EntityMap<EntityData>& m_EntityData;
     225    const std::map<entity_id_t, EntityData>& m_EntityData;
    229226    CFixedVector2D m_Source;
    230227
    231228private:
    public:  
    272269    // Range query state:
    273270    tag_t m_QueryNext; // next allocated id
    274271    std::map<tag_t, Query> m_Queries;
    275     EntityMap<EntityData> m_EntityData;
    276 
    277     SpatialSubdivision m_Subdivision; // spatial index of m_EntityData
     272    std::map<entity_id_t, EntityData> m_EntityData;
     273    SpatialSubdivision<entity_id_t> m_Subdivision; // spatial index of m_EntityData
    278274
    279275    // LOS state:
    280276    static const player_id_t MAX_LOS_PLAYER_ID = 16;
    public:  
    321317
    322318        // Initialise with bogus values (these will get replaced when
    323319        // SetBounds is called)
    324         ResetSubdivisions(entity_pos_t::FromInt(1024), entity_pos_t::FromInt(1024));
     320        ResetSubdivisions(entity_pos_t::FromInt(1), entity_pos_t::FromInt(1));
    325321
    326322        // The whole map should be visible to Gaia by default, else e.g. animals
    327323        // will get confused when trying to run from enemies
    public:  
    348344
    349345        serialize.NumberU32_Unbounded("query next", m_QueryNext);
    350346        SerializeMap<SerializeU32_Unbounded, SerializeQuery>()(serialize, "queries", m_Queries, GetSimContext());
    351         SerializeEntityMap<SerializeEntityData>()(serialize, "entity data", m_EntityData);
     347        SerializeMap<SerializeU32_Unbounded, SerializeEntityData>()(serialize, "entity data", m_EntityData);
    352348
    353349        SerializeVector<SerializeBool>()(serialize, "los reveal all", m_LosRevealAll);
    354350        serialize.Bool("los circular", m_LosCircular);
    public:  
    409405            }
    410406
    411407            // Remember this entity
    412             m_EntityData.insert(ent, entdata);
     408            m_EntityData.insert(std::make_pair(ent, entdata));
     409
    413410            break;
    414411        }
    415412        case MT_PositionChanged:
    public:  
    417414            const CMessagePositionChanged& msgData = static_cast<const CMessagePositionChanged&> (msg);
    418415            entity_id_t ent = msgData.entity;
    419416
    420             EntityMap<EntityData>::iterator it = m_EntityData.find(ent);
     417            std::map<entity_id_t, EntityData>::iterator it = m_EntityData.find(ent);
    421418
    422419            // Ignore if we're not already tracking this entity
    423420            if (it == m_EntityData.end())
    public:  
    464461            const CMessageOwnershipChanged& msgData = static_cast<const CMessageOwnershipChanged&> (msg);
    465462            entity_id_t ent = msgData.entity;
    466463
    467             EntityMap<EntityData>::iterator it = m_EntityData.find(ent);
     464            std::map<entity_id_t, EntityData>::iterator it = m_EntityData.find(ent);
    468465
    469466            // Ignore if we're not already tracking this entity
    470467            if (it == m_EntityData.end())
    public:  
    487484            const CMessageDestroy& msgData = static_cast<const CMessageDestroy&> (msg);
    488485            entity_id_t ent = msgData.entity;
    489486
    490             EntityMap<EntityData>::iterator it = m_EntityData.find(ent);
     487            std::map<entity_id_t, EntityData>::iterator it = m_EntityData.find(ent);
    491488
    492489            // Ignore if we're not already tracking this entity
    493490            if (it == m_EntityData.end())
    public:  
    509506            const CMessageVisionRangeChanged& msgData = static_cast<const CMessageVisionRangeChanged&> (msg);
    510507            entity_id_t ent = msgData.entity;
    511508
    512             EntityMap<EntityData>::iterator it = m_EntityData.find(ent);
     509            std::map<entity_id_t, EntityData>::iterator it = m_EntityData.find(ent);
    513510
    514511            // Ignore if we're not already tracking this entity
    515512            if (it == m_EntityData.end())
    public:  
    573570
    574571        std::vector<std::vector<u16> > oldPlayerCounts = m_LosPlayerCounts;
    575572        std::vector<u32> oldStateRevealed = m_LosStateRevealed;
    576         SpatialSubdivision oldSubdivision = m_Subdivision;
     573        SpatialSubdivision<entity_id_t> oldSubdivision = m_Subdivision;
    577574
    578575        ResetDerivedData(true);
    579576
    public:  
    601598            debug_warn(L"inconsistent subdivs");
    602599    }
    603600
    604     SpatialSubdivision* GetSubdivision()
     601    SpatialSubdivision<entity_id_t>* GetSubdivision()
    605602    {
    606         return & m_Subdivision;
     603        return &m_Subdivision;
    607604    }
    608605
    609606    // Reinitialise subdivisions and LOS data, based on entity data
    public:  
    639636        m_LosStateRevealed.clear();
    640637        m_LosStateRevealed.resize(m_TerrainVerticesPerSide*m_TerrainVerticesPerSide);
    641638
    642         for (EntityMap<EntityData>::const_iterator it = m_EntityData.begin(); it != m_EntityData.end(); ++it)
     639        for (std::map<entity_id_t, EntityData>::const_iterator it = m_EntityData.begin(); it != m_EntityData.end(); ++it)
    643640        {
    644641            if (it->second.inWorld)
    645642                LosAdd(it->second.owner, it->second.visionRange, CFixedVector2D(it->second.x, it->second.z));
    public:  
    665662        // (TODO: find the optimal number instead of blindly guessing)
    666663        m_Subdivision.Reset(x1, z1, entity_pos_t::FromInt(8*TERRAIN_TILE_SIZE));
    667664
    668         for (EntityMap<EntityData>::const_iterator it = m_EntityData.begin(); it != m_EntityData.end(); ++it)
     665        for (std::map<entity_id_t, EntityData>::const_iterator it = m_EntityData.begin(); it != m_EntityData.end(); ++it)
    669666        {
    670667            if (it->second.inWorld)
    671668                m_Subdivision.Add(it->first, CFixedVector2D(it->second.x, it->second.z));
    public:  
    810807
    811808        u32 ownerMask = CalcOwnerMask(player);
    812809
    813         for (EntityMap<EntityData>::const_iterator it = m_EntityData.begin(); it != m_EntityData.end(); ++it)
     810        for (std::map<entity_id_t, EntityData>::const_iterator it = m_EntityData.begin(); it != m_EntityData.end(); ++it)
    814811        {
    815812            // Check owner and add to list if it matches
    816813            if (CalcOwnerMask(it->second.owner) & ownerMask)
    public:  
    838835        // Store a queue of all messages before sending any, so we can assume
    839836        // no entities will move until we've finished checking all the ranges
    840837        std::vector<std::pair<entity_id_t, CMessageRangeUpdate> > messages;
    841         std::vector<entity_id_t> results;
    842         std::vector<entity_id_t> added;
    843         std::vector<entity_id_t> removed;
    844838
    845839        for (std::map<tag_t, Query>::iterator it = m_Queries.begin(); it != m_Queries.end(); ++it)
    846840        {
    847             Query& query = it->second;
     841            Query& q = it->second;
    848842
    849             if (!query.enabled)
     843            if (!q.enabled)
    850844                continue;
    851845
    852             CmpPtr<ICmpPosition> cmpSourcePosition(query.source);
     846            CmpPtr<ICmpPosition> cmpSourcePosition(q.source);
    853847            if (!cmpSourcePosition || !cmpSourcePosition->IsInWorld())
    854848                continue;
    855849
    856             results.clear();
    857             results.reserve(query.lastMatch.size());
     850            std::vector<entity_id_t> r;
     851            r.reserve(q.lastMatch.size());
     852
    858853            CFixedVector2D pos = cmpSourcePosition->GetPosition2D();
    859             PerformQuery(query, results, pos);
     854            PerformQuery(q, r, pos);
    860855
    861856            // Compute the changes vs the last match
    862             added.clear();
    863             removed.clear();
    864             // Return the 'added' list sorted by distance from the entity
    865             // (Don't bother sorting 'removed' because they might not even have positions or exist any more)
    866             std::set_difference(results.begin(), results.end(), query.lastMatch.begin(), query.lastMatch.end(),
    867                 std::back_inserter(added));
    868             std::set_difference(query.lastMatch.begin(), query.lastMatch.end(), results.begin(), results.end(),
    869                 std::back_inserter(removed));
     857            std::vector<entity_id_t> added;
     858            std::vector<entity_id_t> removed;
     859            std::set_difference(r.begin(), r.end(), q.lastMatch.begin(), q.lastMatch.end(), std::back_inserter(added));
     860            std::set_difference(q.lastMatch.begin(), q.lastMatch.end(), r.begin(), r.end(), std::back_inserter(removed));
     861
    870862            if (added.empty() && removed.empty())
    871863                continue;
    872864
    873             std::stable_sort(added.begin(), added.end(), EntityDistanceOrdering(m_EntityData, cmpSourcePosition->GetPosition2D()));
     865            // Return the 'added' list sorted by distance from the entity
     866            // (Don't bother sorting 'removed' because they might not even have positions or exist any more)
     867            std::stable_sort(added.begin(), added.end(), EntityDistanceOrdering(m_EntityData, pos));
     868
     869            messages.push_back(std::make_pair(q.source.GetId(), CMessageRangeUpdate(it->first)));
     870            messages.back().second.added.swap(added);
     871            messages.back().second.removed.swap(removed);
    874872
    875             messages.resize(messages.size() + 1);
    876             std::pair<entity_id_t, CMessageRangeUpdate>& back = messages.back();
    877             back.first = query.source.GetId();
    878             back.second.tag = it->first;
    879             back.second.added.swap(added);
    880             back.second.removed.swap(removed);
    881             it->second.lastMatch.swap(results);
     873            it->second.lastMatch.swap(r);
    882874        }
    883875
    884         CComponentManager& cmpMgr = GetSimContext().GetComponentManager();
    885876        for (size_t i = 0; i < messages.size(); ++i)
    886             cmpMgr.PostMessage(messages[i].first, messages[i].second);
     877            GetSimContext().GetComponentManager().PostMessage(messages[i].first, messages[i].second);
    887878    }
    888879
    889880    /**
    public:  
    923914        // Special case: range -1.0 means check all entities ignoring distance
    924915        if (q.maxRange == entity_pos_t::FromInt(-1))
    925916        {
    926             for (EntityMap<EntityData>::const_iterator it = m_EntityData.begin(); it != m_EntityData.end(); ++it)
     917            for (std::map<entity_id_t, EntityData>::const_iterator it = m_EntityData.begin(); it != m_EntityData.end(); ++it)
    927918            {
    928919                if (!TestEntityQuery(q, it->first, it->second))
    929920                    continue;
    public:  
    939930            CFixedVector3D pos3d = cmpSourcePosition->GetPosition()+
    940931                CFixedVector3D(entity_pos_t::Zero(), q.elevationBonus, entity_pos_t::Zero()) ;
    941932            // Get a quick list of entities that are potentially in range, with a cutoff of 2*maxRange
    942             SpatialQueryArray ents;
    943             m_Subdivision.GetNear(ents, pos, q.maxRange*2);
     933            std::vector<entity_id_t> ents = m_Subdivision.GetNear(pos, q.maxRange*2);
    944934
    945             for (int i = 0; i < ents.size(); ++i)
     935            for (size_t i = 0; i < ents.size(); ++i)
    946936            {
    947                 EntityMap<EntityData>::const_iterator it = m_EntityData.find(ents[i]);
     937                std::map<entity_id_t, EntityData>::const_iterator it = m_EntityData.find(ents[i]);
    948938                ENSURE(it != m_EntityData.end());
    949939
    950940                if (!TestEntityQuery(q, it->first, it->second))
    public:  
    970960                }
    971961
    972962                r.push_back(it->first);
     963
    973964            }
    974965        }
    975966        // check a regular range (i.e. not the entire world, and not parabolic)
    976967        else
    977968        {
    978969            // Get a quick list of entities that are potentially in range
    979             SpatialQueryArray ents;
    980             m_Subdivision.GetNear(ents, pos, q.maxRange);
     970            std::vector<entity_id_t> ents = m_Subdivision.GetNear(pos, q.maxRange);
    981971
    982             for (int i = 0; i < ents.size(); ++i)
     972            for (size_t i = 0; i < ents.size(); ++i)
    983973            {
    984                 EntityMap<EntityData>::const_iterator it = m_EntityData.find(ents[i]);
     974                std::map<entity_id_t, EntityData>::const_iterator it = m_EntityData.find(ents[i]);
    985975                ENSURE(it != m_EntityData.end());
    986976
    987977                if (!TestEntityQuery(q, it->first, it->second))
    public:  
    1000990                }
    1001991
    1002992                r.push_back(it->first);
     993
    1003994            }
    1004995        }
    1005996    }
    public:  
    11531144    {
    11541145        if (!m_DebugOverlayEnabled)
    11551146            return;
    1156         static CColor disabledRingColour(1, 0, 0, 1);   // red
    1157         static CColor enabledRingColour(0, 1, 0, 1);    // green
    1158         static CColor subdivColour(0, 0, 1, 1);         // blue
    1159         static CColor rayColour(1, 1, 0, 0.2f);
     1147
     1148        CColor enabledRingColour(0, 1, 0, 1);
     1149        CColor disabledRingColour(1, 0, 0, 1);
     1150        CColor rayColour(1, 1, 0, 0.2f);
    11601151
    11611152        if (m_DebugOverlayDirty)
    11621153        {
    public:  
    12631254                }
    12641255            }
    12651256
    1266             // render subdivision grid
    1267             float divSize = m_Subdivision.GetDivisionSize().ToFloat();
    1268             int width = m_Subdivision.GetWidth();
    1269             int height = m_Subdivision.GetHeight();
    1270             for (int x = 0; x < width; ++x)
    1271             {
    1272                 for (int y = 0; y < height; ++y)
    1273                 {
    1274                     m_DebugOverlayLines.push_back(SOverlayLine());
    1275                     m_DebugOverlayLines.back().m_Color = subdivColour;
    1276 
    1277                     float xpos = x*divSize + divSize/2;
    1278                     float zpos = y*divSize + divSize/2;
    1279                     SimRender::ConstructSquareOnGround(GetSimContext(), xpos, zpos, divSize, divSize, 0.0f,
    1280                         m_DebugOverlayLines.back(), false, 1.0f);
    1281                 }
    1282             }
    1283 
    12841257            m_DebugOverlayDirty = false;
    12851258        }
    12861259
    public:  
    13011274
    13021275    virtual void SetEntityFlag(entity_id_t ent, std::string identifier, bool value)
    13031276    {
    1304         EntityMap<EntityData>::iterator it = m_EntityData.find(ent);
     1277        std::map<entity_id_t, EntityData>::iterator it = m_EntityData.find(ent);
    13051278
    13061279        // We don't have this entity
    13071280        if (it == m_EntityData.end())
  • source/simulation2/components/ICmpRangeManager.h

    diff --git a/source/simulation2/components/ICmpRangeManager.h b/source/simulation2/components/ICmpRangeManager.h
    index f68a2d7..62dcdad 100644
    a b public:  
    7777     * Access the spatial subdivision kept by the range manager.
    7878     * @return pointer to spatial subdivision structure.
    7979     */
    80     virtual SpatialSubdivision* GetSubdivision() = 0;
     80    virtual SpatialSubdivision<entity_id_t>* GetSubdivision() = 0;
    8181
    8282    /**
    8383     * Set the bounds of the world.
  • source/simulation2/helpers/Selection.cpp

    diff --git a/source/simulation2/helpers/Selection.cpp b/source/simulation2/helpers/Selection.cpp
    index fc83f6f..b5f39b4 100644
    a b std::vector<entity_id_t> EntitySelection::PickEntitiesAtPoint(CSimulation2& simu  
    4949    CFixedVector2D pos(fixed::FromFloat(pos3d.X), fixed::FromFloat(pos3d.Z));
    5050
    5151    // Get a rough group of entities using our approximated origin.
    52     SpatialQueryArray ents;
    53     cmpRangeManager->GetSubdivision()->GetNear(ents, pos, entity_pos_t::FromInt(range));
     52    std::vector<entity_id_t> ents = cmpRangeManager->GetSubdivision()->GetNear(pos, entity_pos_t::FromInt(range));
    5453
    5554    // Filter for relevent entities and calculate precise distances.
    5655    std::vector<std::pair<float, entity_id_t> > hits; // (dist^2, entity) pairs
    57     for (int i = 0; i < ents.size(); ++i)
     56    for (size_t i = 0; i < ents.size(); ++i)
    5857    {
    5958        CmpPtr<ICmpSelectable> cmpSelectable(simulation, ents[i]);
    6059        if (!cmpSelectable)
  • source/simulation2/helpers/Spatial.h

    diff --git a/source/simulation2/helpers/Spatial.h b/source/simulation2/helpers/Spatial.h
    index cd3b8d8..78f0b6b 100644
    a b  
    2323#include "ps/CLogger.h"
    2424
    2525/**
    26  * A simple fixed-size array that works similar to an std::vector
    27  * but is obviously limited in its max items
    28  */
    29 struct SpatialQueryArray
    30 {
    31     enum { MAX_COUNT = 2048 };
    32     int count;
    33     uint32_t items[MAX_COUNT];
    34 
    35     inline SpatialQueryArray() : count(0) {}
    36     inline const uint32_t& operator[](int index) const { return items[index]; }
    37     inline uint32_t& operator[](int index) { return items[index]; }
    38     inline int size() const { return count; }
    39     inline void clear() { count = 0; }
    40     void make_unique() // removes any duplicate entries
    41     {
    42         if (count)
    43         {
    44             std::sort(items, items + count); // we need a sorted list for std::unique to work
    45             count = int(std::unique(items, items + count) - items);
    46         }
    47     }
    48 };
    49 
    50 /**
    5126 * A very basic subdivision scheme for finding items in ranges.
    5227 * Items are stored in lists in fixed-size divisions.
    5328 * Items have a size (min/max values of their axis-aligned bounding box)
    struct SpatialQueryArray  
    6136 *
    6237 * (TODO: maybe an adaptive quadtree would be better than fixed sizes?)
    6338 */
     39template<typename T>
    6440class SpatialSubdivision
    6541{
    66     struct SubDivisionGrid
    67     {
    68         std::vector<uint32_t> items;
    69 
    70         inline void push_back(uint32_t value)
    71         {
    72             items.push_back(value);
    73         }
    74 
    75         inline void erase(int index)
    76         {
    77             // Delete by swapping with the last element then popping
    78             if ((int)items.size() > 1) // but only if we have more than 1 elements
    79                 items[index] = items.back();
    80             items.pop_back();
    81         }
    82 
    83         void copy_items(SpatialQueryArray& out)
    84         {
    85             if (items.empty())
    86                 return; // nothing to copy
    87 
    88             int dsti = out.count;               // the index in [out] where to start copying
    89             int count = (int)items.size();
    90             if ((dsti + count) > SpatialQueryArray::MAX_COUNT)
    91             {
    92                 LOGWARNING(L"SpatialSubdivision Query too large. Results truncated.");
    93                 count = SpatialQueryArray::MAX_COUNT - dsti; // don't copy overflowing items
    94             }
    95             uint32_t* dst = &out.items[dsti];
    96             uint32_t* src = &items[0];
    97             for (int i = 0; i < count; ++i) // copy all items
    98                 dst[i] = src[i];
    99             out.count += count;
    100         }
    101     };
    102 
    103 
    104     entity_pos_t m_DivisionSize;
    105     SubDivisionGrid* m_Divisions;
    106     uint32_t m_DivisionsW;
    107     uint32_t m_DivisionsH;
    108 
    109     friend struct SerializeSubDivisionGrid;
    110     friend struct SerializeSpatialSubdivision;
    111 
    11242public:
    113     SpatialSubdivision() : m_Divisions(NULL), m_DivisionsW(0), m_DivisionsH(0)
     43    SpatialSubdivision() :
     44        m_DivisionsW(0), m_DivisionsH(0)
    11445    {
    11546    }
    116     ~SpatialSubdivision()
    117     {
    118         delete[] m_Divisions;
    119     }
    120     SpatialSubdivision(const SpatialSubdivision& rhs)
    121     {
    122         m_DivisionSize = rhs.m_DivisionSize;
    123         m_DivisionsW = rhs.m_DivisionsW;
    124         m_DivisionsH = rhs.m_DivisionsH;
    125         size_t n = m_DivisionsW * m_DivisionsH;
    126         m_Divisions = new SubDivisionGrid[n];
    127         for (size_t i = 0; i < n; ++i)
    128             m_Divisions[i] = rhs.m_Divisions[i]; // just fall back to piecemeal copy
    129     }
    130     SpatialSubdivision& operator=(const SpatialSubdivision& rhs)
    131     {
    132         if (this != &rhs)
    133         {
    134             m_DivisionSize = rhs.m_DivisionSize;
    135             size_t n = rhs.m_DivisionsW * rhs.m_DivisionsH;
    136             if (m_DivisionsW != rhs.m_DivisionsW || m_DivisionsH != rhs.m_DivisionsH)
    137                 Create(n); // size changed, recreate
    138            
    139             m_DivisionsW = rhs.m_DivisionsW;
    140             m_DivisionsH = rhs.m_DivisionsH;
    141             for (size_t i = 0; i < n; ++i)
    142                 m_Divisions[i] = rhs.m_Divisions[i]; // just fall back to piecemeal copy
    143         }
    144         return *this;
    145     }
    146 
    147     inline entity_pos_t GetDivisionSize() const { return m_DivisionSize; }
    148     inline uint32_t GetWidth() const { return m_DivisionsW; }
    149     inline uint32_t GetHeight() const { return m_DivisionsH; }
    150 
    151     void Create(size_t count)
    152     {
    153         if (m_Divisions) delete[] m_Divisions;
    154         m_Divisions = new SubDivisionGrid[count];
    155     }
    15647
    15748    /**
    15849     * Equivalence test (ignoring order of items within each subdivision)
    public:  
    16253        if (m_DivisionSize != rhs.m_DivisionSize || m_DivisionsW != rhs.m_DivisionsW || m_DivisionsH != rhs.m_DivisionsH)
    16354            return false;
    16455       
    165         uint32_t n = m_DivisionsH * m_DivisionsW;
    166         for (uint32_t i = 0; i < n; ++i)
     56        for (u32 j = 0; j < m_DivisionsH; ++j)
    16757        {
    168             if (m_Divisions[i].items.size() != rhs.m_Divisions[i].items.size())
    169                 return false;
    170 
    171             // don't bother optimizing this, this is only used in the TESTING SUITE
    172             std::vector<uint32_t> a = m_Divisions[i].items;
    173             std::vector<uint32_t> b = rhs.m_Divisions[i].items;
    174             std::sort(a.begin(), a.end());
    175             std::sort(b.begin(), b.end());
    176             if (a != b)
    177                 return false;
     58            for (u32 i = 0; i < m_DivisionsW; ++i)
     59            {
     60                std::vector<T> div1 = m_Divisions.at(i + j*m_DivisionsW);
     61                std::vector<T> div2 = rhs.m_Divisions.at(i + j*m_DivisionsW);
     62                std::sort(div1.begin(), div1.end());
     63                std::sort(div2.begin(), div2.end());
     64                if (div1 != div2)
     65                    return false;
     66            }
    17867        }
     68
    17969        return true;
    18070    }
    18171
    182     inline bool operator!=(const SpatialSubdivision& rhs)
     72    bool operator!=(const SpatialSubdivision& rhs)
    18373    {
    18474        return !(*this == rhs);
    18575    }
    public:  
    18979        m_DivisionSize = divisionSize;
    19080        m_DivisionsW = (maxX / m_DivisionSize).ToInt_RoundToInfinity();
    19181        m_DivisionsH = (maxZ / m_DivisionSize).ToInt_RoundToInfinity();
    192 
    193         Create(m_DivisionsW * m_DivisionsH);
     82        m_Divisions.clear();
     83        m_Divisions.resize(m_DivisionsW * m_DivisionsH);
    19484    }
    19585
    196 
    19786    /**
    19887     * Add an item with the given 'to' size.
    19988     * The item must not already be present.
    20089     */
    201     void Add(uint32_t item, CFixedVector2D toMin, CFixedVector2D toMax)
     90    void Add(T item, CFixedVector2D toMin, CFixedVector2D toMax)
    20291    {
    20392        ENSURE(toMin.X <= toMax.X && toMin.Y <= toMax.Y);
    20493
    public:  
    21099        {
    211100            for (u32 i = i0; i <= i1; ++i)
    212101            {
    213                 m_Divisions[i + j*m_DivisionsW].push_back(item);
     102                std::vector<T>& div = m_Divisions.at(i + j*m_DivisionsW);
     103                div.push_back(item);
    214104            }
    215105        }
    216106    }
    public:  
    220110     * The item should already be present.
    221111     * The size must match the size that was last used when adding the item.
    222112     */
    223     void Remove(uint32_t item, CFixedVector2D fromMin, CFixedVector2D fromMax)
     113    void Remove(T item, CFixedVector2D fromMin, CFixedVector2D fromMax)
    224114    {
    225115        ENSURE(fromMin.X <= fromMax.X && fromMin.Y <= fromMax.Y);
    226116
    public:  
    232122        {
    233123            for (u32 i = i0; i <= i1; ++i)
    234124            {
    235                 SubDivisionGrid& div = m_Divisions[i + j*m_DivisionsW];
    236                 int size = div.items.size();
    237                 for (int n = 0; n < size; ++n)
     125                std::vector<T>& div = m_Divisions.at(i + j*m_DivisionsW);
     126
     127                for (u32 n = 0; n < div.size(); ++n)
    238128                {
    239                     if (div.items[n] == item)
     129                    if (div[n] == item)
    240130                    {
    241                         div.erase(n);
     131                        // Delete by swapping with the last element then popping
     132                        div[n] = div.back();
     133                        div.pop_back();
    242134                        break;
    243135                    }
    244136                }
    public:  
    249141    /**
    250142     * Equivalent to Remove() then Add(), but potentially faster.
    251143     */
    252     void Move(uint32_t item, CFixedVector2D fromMin, CFixedVector2D fromMax, CFixedVector2D toMin, CFixedVector2D toMax)
     144    void Move(T item, CFixedVector2D fromMin, CFixedVector2D fromMax, CFixedVector2D toMin, CFixedVector2D toMax)
    253145    {
    254146        // Skip the work if we're staying in the same divisions
    255147        if (GetIndex0(fromMin) == GetIndex0(toMin) && GetIndex1(fromMax) == GetIndex1(toMax))
    public:  
    263155     * Convenience function for Add() of individual points.
    264156     * (Note that points on a boundary may occupy multiple divisions.)
    265157     */
    266     void Add(uint32_t item, CFixedVector2D to)
     158    void Add(T item, CFixedVector2D to)
    267159    {
    268160        Add(item, to, to);
    269161    }
    public:  
    271163    /**
    272164     * Convenience function for Remove() of individual points.
    273165     */
    274     void Remove(uint32_t item, CFixedVector2D from)
     166    void Remove(T item, CFixedVector2D from)
    275167    {
    276168        Remove(item, from, from);
    277169    }
    public:  
    279171    /**
    280172     * Convenience function for Move() of individual points.
    281173     */
    282     void Move(uint32_t item, CFixedVector2D from, CFixedVector2D to)
     174    void Move(T item, CFixedVector2D from, CFixedVector2D to)
    283175    {
    284176        Move(item, from, from, to, to);
    285177    }
    public:  
    288180     * Returns a sorted list of unique items that includes all items
    289181     * within the given axis-aligned square range.
    290182     */
    291     void GetInRange(SpatialQueryArray& out, CFixedVector2D posMin, CFixedVector2D posMax)
     183    std::vector<T> GetInRange(CFixedVector2D posMin, CFixedVector2D posMax)
    292184    {
    293         out.clear();
     185        std::vector<T> ret;
     186
    294187        ENSURE(posMin.X <= posMax.X && posMin.Y <= posMax.Y);
    295188
    296189        u32 i0 = GetI0(posMin.X);
    public:  
    301194        {
    302195            for (u32 i = i0; i <= i1; ++i)
    303196            {
    304                 m_Divisions[i + j*m_DivisionsW].copy_items(out);
     197                std::vector<T>& div = m_Divisions.at(i + j*m_DivisionsW);
     198                ret.insert(ret.end(), div.begin(), div.end());
    305199            }
    306200        }
    307         // some buildings span several tiles, so we need to make it unique
    308         out.make_unique();
     201
     202        // Remove duplicates
     203        std::sort(ret.begin(), ret.end());
     204        ret.erase(std::unique(ret.begin(), ret.end()), ret.end());
     205
     206        return ret;
    309207    }
    310208
    311209    /**
    312210     * Returns a sorted list of unique items that includes all items
    313211     * within the given circular distance of the given point.
    314212     */
    315     void GetNear(SpatialQueryArray& out, CFixedVector2D pos, entity_pos_t range)
     213    std::vector<T> GetNear(CFixedVector2D pos, entity_pos_t range)
    316214    {
    317215        // TODO: be cleverer and return a circular pattern of divisions,
    318216        // not this square over-approximation
    319         CFixedVector2D r(range, range);
    320         GetInRange(out, pos - r, pos + r);
     217
     218        return GetInRange(pos - CFixedVector2D(range, range), pos + CFixedVector2D(range, range));
    321219    }
    322220
    323221private:
    private:  
    325223    // (avoiding out-of-bounds accesses, and rounding correctly so that
    326224    // points precisely between divisions are counted in both):
    327225
    328     uint32_t GetI0(entity_pos_t x)
     226    u32 GetI0(entity_pos_t x)
    329227    {
    330228        return Clamp((x / m_DivisionSize).ToInt_RoundToInfinity()-1, 0, (int)m_DivisionsW-1);
    331229    }
    332230
    333     uint32_t GetJ0(entity_pos_t z)
     231    u32 GetJ0(entity_pos_t z)
    334232    {
    335233        return Clamp((z / m_DivisionSize).ToInt_RoundToInfinity()-1, 0, (int)m_DivisionsH-1);
    336234    }
    337235
    338     uint32_t GetI1(entity_pos_t x)
     236    u32 GetI1(entity_pos_t x)
    339237    {
    340238        return Clamp((x / m_DivisionSize).ToInt_RoundToNegInfinity(), 0, (int)m_DivisionsW-1);
    341239    }
    342240
    343     uint32_t GetJ1(entity_pos_t z)
     241    u32 GetJ1(entity_pos_t z)
    344242    {
    345243        return Clamp((z / m_DivisionSize).ToInt_RoundToNegInfinity(), 0, (int)m_DivisionsH-1);
    346244    }
    347245
    348     uint32_t GetIndex0(CFixedVector2D pos)
     246    u32 GetIndex0(CFixedVector2D pos)
    349247    {
    350248        return GetI0(pos.X) + GetJ0(pos.Y)*m_DivisionsW;
    351249    }
    352250
    353     uint32_t GetIndex1(CFixedVector2D pos)
     251    u32 GetIndex1(CFixedVector2D pos)
    354252    {
    355253        return GetI1(pos.X) + GetJ1(pos.Y)*m_DivisionsW;
    356254    }
     255
     256    entity_pos_t m_DivisionSize;
     257    std::vector<std::vector<T> > m_Divisions;
     258    u32 m_DivisionsW;
     259    u32 m_DivisionsH;
     260
     261    template<typename ELEM> friend struct SerializeSpatialSubdivision;
    357262};
    358263
    359264/**
    360265 * Serialization helper template for SpatialSubdivision
    361266 */
     267template<typename ELEM>
    362268struct SerializeSpatialSubdivision
    363269{
    364     void operator()(ISerializer& serialize, const char* UNUSED(name), SpatialSubdivision& value)
     270    template<typename T>
     271    void operator()(ISerializer& serialize, const char* UNUSED(name), SpatialSubdivision<T>& value)
    365272    {
    366273        serialize.NumberFixed_Unbounded("div size", value.m_DivisionSize);
     274        SerializeVector<SerializeVector<ELEM> >()(serialize, "divs", value.m_Divisions);
    367275        serialize.NumberU32_Unbounded("divs w", value.m_DivisionsW);
    368276        serialize.NumberU32_Unbounded("divs h", value.m_DivisionsH);
    369 
    370         size_t count = value.m_DivisionsH * value.m_DivisionsW;
    371         for (size_t i = 0; i < count; ++i)
    372             SerializeVector<SerializeU32_Unbounded>()(serialize, "subdiv items", value.m_Divisions[i].items);
    373277    }
    374278
    375     void operator()(IDeserializer& serialize, const char* UNUSED(name), SpatialSubdivision& value)
     279    template<typename T>
     280    void operator()(IDeserializer& serialize, const char* UNUSED(name), SpatialSubdivision<T>& value)
    376281    {
    377282        serialize.NumberFixed_Unbounded("div size", value.m_DivisionSize);
    378         serialize.NumberU32_Unbounded("divs w", value.m_DivisionsW);
    379         serialize.NumberU32_Unbounded("divs h", value.m_DivisionsH);
     283        SerializeVector<SerializeVector<ELEM> >()(serialize, "divs", value.m_Divisions);
    380284
    381         size_t count = value.m_DivisionsW * value.m_DivisionsH;
    382         value.Create(count);
    383         for (size_t i = 0; i < count; ++i)
    384             SerializeVector<SerializeU32_Unbounded>()(serialize, "subdiv items", value.m_Divisions[i].items);
     285        u32 w, h;
     286        serialize.NumberU32_Unbounded("divs w", w);
     287        serialize.NumberU32_Unbounded("divs h", h);
     288        value.m_DivisionsW = w;
     289        value.m_DivisionsH = h;
    385290    }
    386291};
    387292
  • deleted file source/simulation2/system/EntityMap.h

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

    diff --git a/source/simulation2/system/SimContext.cpp b/source/simulation2/system/SimContext.cpp
    index 33cbb68..e5a84b2 100644
    a b CSimContext::~CSimContext()  
    3434
    3535CComponentManager& CSimContext::GetComponentManager() const
    3636{
     37    ENSURE(m_ComponentManager);
    3738    return *m_ComponentManager;
    3839}
    3940