Ticket #4347: patch.patch

File patch.patch, 31.0 KB (added by wraitii, 7 years ago)
  • source/simulation2/system/EntityMap.h

    diff --git a/source/simulation2/system/EntityMap.h b/source/simulation2/system/EntityMap.h
    index 98b0ebe..4771945 100644
    a b  
    2121
    2222/**
    2323 * 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
     24 * Behaves like a much faster std:map with one key difference:
     25 *  -calling insert on an existing key replaces it instead of returning the original
     26 *  (not that you should be doing that anyways)
    2827 */
    29 template<class T> class EntityMap
     28
     29template<class V, size_t FIRST_VALID_ENTITY_ID = 1> class EntityMap
    3030{
    3131private:
     32    friend class TestEntityMap;
     33   
    3234    EntityMap(const EntityMap&);            // non-copyable
    3335    EntityMap& operator=(const EntityMap&); // non-copyable
    3436
    3537public:
    3638    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;
     39    typedef V mapped_type;
     40    typedef std::pair<entity_id_t, V> value_type;
    4541
    4642private:
    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
     43    std::vector<std::pair<entity_id_t, V> > m_Data;
    5044
    5145    size_t m_Count;             // number of 'valid' entity id's
    5246
    5347public:
    5448
    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()
     49    EntityMap() : m_Count(0)
    6650    {
    67         free(m_Buffer);
     51        ENSURE(FIRST_VALID_ENTITY_ID > INVALID_ENTITY);
     52        m_Data.reserve(4096);
     53        // keep a valid entity ID at the end() so that we know to stop
     54        m_Data.push_back({FIRST_VALID_ENTITY_ID, V()});
    6855    }
    6956
    70     // Iterators
    7157    template<class U> struct _iter : public std::iterator<std::forward_iterator_tag, U>
    7258    {
    7359        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
     60        _iter(U* init) : val(init) {}
     61        _iter(typename std::vector<U>::iterator init) : val(&*init) {}
     62
     63        U& operator*() { return *val; }
     64        U* operator->() { return val; }
     65        _iter& operator++() // ++it
    7866        {
    7967            ++val;
    80             while (val->first == INVALID_ENTITY) ++val; // skip any invalid entities
     68            while (val->first == INVALID_ENTITY)
     69                ++val;
    8170            return *this;
    8271        }
    83         inline _iter& operator++(int) // it++
     72        _iter operator++(int) // it++
    8473        {
    8574            U* ptr = val;
    8675            ++val;
    87             while (val->first == INVALID_ENTITY) ++val; // skip any invalid entities
     76            while (val->first == INVALID_ENTITY)
     77                ++val;
    8878            return ptr;
    8979        }
    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); }
     80        bool operator==(_iter other) { return val == other.val; }
     81        bool operator!=(_iter other) { return val != other.val; }
     82        operator _iter<U const>() const { return _iter<U const>(val); }
    9383    };
    9484   
    9585    typedef _iter<value_type> iterator;
    9686    typedef _iter<value_type const> const_iterator;
    9787
    98     inline iterator begin()
     88    iterator begin()
    9989    {
    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;
     90        iterator it = m_Data.begin();
     91        if (it->first == INVALID_ENTITY)
     92            ++it;
     93        return it;
    10394    }
    104     inline iterator end()
     95
     96    iterator end()
    10597    {
    106         return iterator(m_Buffer + m_BufferSize);
     98        return iterator(&m_Data.back());
    10799    }
    108     inline const_iterator begin() const
     100
     101    const_iterator begin() const
    109102    {
    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;
     103        const_iterator it = m_Data.begin();
     104        if (it->first == INVALID_ENTITY)
     105            ++it;
     106        return it;
    113107    }
    114     inline const_iterator end() const
     108
     109    const_iterator end() const
    115110    {
    116         return const_iterator(m_Buffer + m_BufferSize);
     111        return const_iterator(&m_Data.back());
    117112    }
    118113
    119     // Size
    120     inline bool empty() const { return m_Count == 0; }
    121     inline size_t size() const { return m_Count; }
     114    bool empty() const { return m_Count == 0; }
     115    size_t size() const { return m_Count; }
    122116
    123     // Modification
    124117    void insert(const key_type key, const mapped_type& value)
    125118    {
    126         if (key >= m_BufferCapacity) // do we need to resize buffer?
     119        ENSURE (key >= FIRST_VALID_ENTITY_ID);
     120        if (key-FIRST_VALID_ENTITY_ID >= m_Data.size()-1)
    127121        {
    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
     122            // resize, make sure to keep a valid entity ID at the end
     123            size_t currentEnd = m_Data.size()-1;
     124            m_Data.resize(key-FIRST_VALID_ENTITY_ID+2, {INVALID_ENTITY, V()});
     125            m_Data.back() = std::move(m_Data[currentEnd]);
     126            m_Data[currentEnd].first = INVALID_ENTITY;
    148127        }
    149128
    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         }
     129        if (m_Data[key-FIRST_VALID_ENTITY_ID].first == INVALID_ENTITY)
     130            m_Count++;
     131
     132        m_Data[key-FIRST_VALID_ENTITY_ID] = {key, value};
    171133    }
    172134   
    173     void erase(iterator it)
     135    size_t erase(iterator it)
    174136    {
    175         value_type* ptr = it.val;
    176         if (ptr->first != INVALID_ENTITY)
     137        if (it->first != INVALID_ENTITY && it != end())
    177138        {
    178             ptr->first = INVALID_ENTITY;
    179             ptr->second.~T(); // call dtor
     139            it->first = INVALID_ENTITY;
     140            it->second.~V(); // call dtor
    180141            --m_Count;
     142            return 1;
    181143        }
     144        return 0;
    182145    }
    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()
     146
     147    size_t erase(const key_type key)
    197148    {
    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
     149        if (key-FIRST_VALID_ENTITY_ID < m_Data.size()-1)
     150            return erase(m_Data.begin() + key-FIRST_VALID_ENTITY_ID);
     151        return 0;
    210152    }
    211153
    212     // Operations
    213     inline iterator find(const entity_id_t key)
     154    void clear()
    214155    {
    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()
     156        m_Data.clear();
     157        m_Count = 0;
     158        m_Data.push_back({FIRST_VALID_ENTITY_ID, V()});
    222159    }
    223     inline const_iterator find(const entity_id_t key) const
     160
     161    iterator find(const key_type key)
    224162    {
    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()
     163        if (key-FIRST_VALID_ENTITY_ID < m_Data.size()-1 && m_Data[key-FIRST_VALID_ENTITY_ID].first != INVALID_ENTITY)
     164            return m_Data.begin() + key - FIRST_VALID_ENTITY_ID;
     165        return end();
    232166    }
    233     inline size_t count(const entity_id_t key) const
     167
     168    const_iterator find(const key_type key) const
    234169    {
    235         if (key < m_BufferSize)
    236         {
    237             if (m_Buffer[key].first != INVALID_ENTITY)
    238                 return 1;
    239         }
    240         return 0;
     170        if (key-FIRST_VALID_ENTITY_ID < m_Data.size()-1 && m_Data[key-FIRST_VALID_ENTITY_ID].first != INVALID_ENTITY)
     171            return m_Data.begin() + key - FIRST_VALID_ENTITY_ID;
     172        return end();
    241173    }
    242174};
    243175
  • new file source/simulation2/system/EntityMap_old.h

    diff --git a/source/simulation2/system/EntityMap_old.h b/source/simulation2/system/EntityMap_old.h
    new file mode 100644
    index 0000000..1109bd5
    - +  
     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 */
     29template<class T> class EntityMap
     30{
     31private:
     32    friend class TestEntityMapOld;
     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            size_t newCapacity = m_BufferCapacity + 4096;
     130            while (key >= newCapacity) newCapacity += 4096;
     131            // always allocate +1 behind the scenes, because end() must have a 0xFFFFFFFF key
     132            value_type* mem = (value_type*)realloc(m_Buffer, sizeof(value_type) * (newCapacity + 1));
     133            if (!mem)
     134            {
     135                debug_warn("EntityMap::insert() realloc failed! Out of memory.");
     136                throw std::bad_alloc(); // fail to expand and insert
     137            }
     138            m_BufferCapacity = newCapacity;
     139            m_Buffer = mem;
     140            goto fill_gaps;
     141        }
     142        else if (key > m_BufferSize) // weird insert far beyond the end
     143        {
     144fill_gaps:
     145            // set all entity id's to INVALID_ENTITY inside the new range
     146            for (size_t i = m_BufferSize; i <= key; ++i)
     147                m_Buffer[i].first = INVALID_ENTITY;
     148            m_BufferSize = key; // extend the new size
     149        }
     150
     151        value_type& item = m_Buffer[key];
     152        key_type oldKey = item.first;
     153        item.first = key;
     154        if (key == m_BufferSize) // push_back
     155        {
     156            ++m_BufferSize; // expand
     157            ++m_Count;
     158            new (&item.second) mapped_type(value); // copy ctor to init
     159            m_Buffer[m_BufferSize].first = 0xFFFFFFFF; // ensure end() always has 0xFFFFFFFF
     160        }
     161        else if(!item.first) // insert new to middle
     162        {
     163            ++m_Count;
     164            new (&item.second) mapped_type(value); // copy ctor to init
     165        }
     166        else // set existing value
     167        {
     168            if (oldKey == INVALID_ENTITY)
     169                m_Count++;
     170            item.second = value; // overwrite existing
     171        }
     172    }
     173   
     174    void erase(iterator it)
     175    {
     176        value_type* ptr = it.val;
     177        if (ptr->first != INVALID_ENTITY)
     178        {
     179            ptr->first = INVALID_ENTITY;
     180            ptr->second.~T(); // call dtor
     181            --m_Count;
     182        }
     183    }
     184    void erase(const entity_id_t key)
     185    {
     186        if (key < m_BufferSize)
     187        {
     188            value_type* ptr = m_Buffer + key;
     189            if (ptr->first != INVALID_ENTITY)
     190            {
     191                ptr->first = INVALID_ENTITY;
     192                ptr->second.~T(); // call dtor
     193                --m_Count;
     194            }
     195        }
     196    }
     197    inline void clear()
     198    {
     199        // orphan whole range
     200        value_type* ptr = m_Buffer;
     201        value_type* end = m_Buffer + m_BufferSize;
     202        for (; ptr != end; ++ptr)
     203        {
     204            if (ptr->first != INVALID_ENTITY)
     205            {
     206                ptr->first = INVALID_ENTITY;
     207                ptr->second.~T(); // call dtor
     208            }
     209        }
     210        m_Count = 0; // no more valid entities
     211    }
     212
     213    // Operations
     214    inline iterator find(const entity_id_t key)
     215    {
     216        if (key < m_BufferSize) // is this key in the range of existing entitites?
     217        {
     218            value_type* ptr = m_Buffer + key;
     219            if (ptr->first != INVALID_ENTITY)
     220                return ptr;
     221        }
     222        return m_Buffer + m_BufferSize; // return iterator end()
     223    }
     224    inline const_iterator find(const entity_id_t key) const
     225    {
     226        if (key < m_BufferSize) // is this key in the range of existing entitites?
     227        {
     228            const value_type* ptr = m_Buffer + key;
     229            if (ptr->first != INVALID_ENTITY)
     230                return ptr;
     231        }
     232        return m_Buffer + m_BufferSize; // return iterator end()
     233    }
     234    inline size_t count(const entity_id_t key) const
     235    {
     236        if (key < m_BufferSize)
     237        {
     238            if (m_Buffer[key].first != INVALID_ENTITY)
     239                return 1;
     240        }
     241        return 0;
     242    }
     243};
     244
     245template<class VSerializer>
     246struct SerializeEntityMap
     247{
     248    template<class V>
     249    void operator()(ISerializer& serialize, const char* UNUSED(name), EntityMap<V>& value)
     250    {
     251        size_t len = value.size();
     252        serialize.NumberU32_Unbounded("length", (u32)len);
     253        size_t count = 0;
     254        for (typename EntityMap<V>::iterator it = value.begin(); it != value.end(); ++it)
     255        {
     256            serialize.NumberU32_Unbounded("key", it->first);
     257            VSerializer()(serialize, "value", it->second);
     258            count++;
     259        }
     260        // test to see if the entityMap count wasn't wrong
     261        // (which causes a crashing deserialisation)
     262        ENSURE(count == len);
     263    }
     264
     265    template<class V>
     266    void operator()(IDeserializer& deserialize, const char* UNUSED(name), EntityMap<V>& value)
     267    {
     268        value.clear();
     269        uint32_t len;
     270        deserialize.NumberU32_Unbounded("length", len);
     271        for (size_t i = 0; i < len; ++i)
     272        {
     273            entity_id_t k;
     274            V v;
     275            deserialize.NumberU32_Unbounded("key", k);
     276            VSerializer()(deserialize, "value", v);
     277            value.insert(k, v);
     278        }
     279    }
     280};
     281
     282
     283#endif
  • new file source/simulation2/tests/test_EntityMap.h

    diff --git a/source/simulation2/tests/test_EntityMap.h b/source/simulation2/tests/test_EntityMap.h
    new file mode 100644
    index 0000000..c4c2d64
    - +  
     1/* Copyright (C) 2010 Wildfire Games.
     2 * This file is part of 0 A.D.
     3 *
     4 * 0 A.D. is free software: you can redistribute it and/or modify
     5 * it under the terms of the GNU General Public License as published by
     6 * the Free Software Foundation, either version 2 of the License, or
     7 * (at your option) any later version.
     8 *
     9 * 0 A.D. is distributed in the hope that it will be useful,
     10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
     11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     12 * GNU General Public License for more details.
     13 *
     14 * You should have received a copy of the GNU General Public License
     15 * along with 0 A.D.  If not, see <http://www.gnu.org/licenses/>.
     16 */
     17
     18#include "lib/self_test.h"
     19#include "lib/timer.h"
     20
     21#include "simulation2/serialization/ISerializer.h"
     22#include "simulation2/serialization/IDeserializer.h"
     23
     24#include "simulation2/system/EntityMap.h"
     25
     26class TestEntityMap : public CxxTest::TestSuite
     27{
     28public:
     29    void setUp()
     30    {
     31    }
     32
     33    void tearDown()
     34    {
     35    }
     36
     37    void test_insert()
     38    {
     39        EntityMap<int, 1> test;
     40
     41        TS_ASSERT(test.empty());
     42
     43        test.insert(1,1);
     44        test.insert(2,2);
     45        test.insert(3,3);
     46        test.insert(4,4);
     47        test.insert(4,5);
     48        test.insert(4,6);
     49
     50        TS_ASSERT(test.m_Data.size() == 5);
     51        TS_ASSERT(test.m_Data.back().first != INVALID_ENTITY);
     52        TS_ASSERT(test.size() == 4);
     53        TS_ASSERT(test.find(3)->second == 3);
     54        TS_ASSERT(test.find(4)->second == 6);
     55
     56        test.insert(10,7);
     57        TS_ASSERT(test.m_Data.size() == 11);
     58        TS_ASSERT(test.m_Data.back().first != INVALID_ENTITY);
     59        TS_ASSERT(test.size() == 5);
     60        TS_ASSERT(test.find(4)->second == 6);
     61        TS_ASSERT(test.find(5) == test.end());
     62        TS_ASSERT(test.find(6) == test.end());
     63        TS_ASSERT(test.find(7) == test.end());
     64        TS_ASSERT(test.find(8) == test.end());
     65        TS_ASSERT(test.find(9) == test.end());
     66        TS_ASSERT(test.find(10)->second == 7);
     67
     68        EntityMap<int, 5> test2;
     69
     70        test2.insert(8,5);
     71        TS_ASSERT(test2.find(8)->second == 5);
     72        TS_ASSERT(test2.m_Data.size() == 5);
     73        TS_ASSERT(test2.size() == 1);
     74
     75    }
     76    void test_iterators()
     77    {
     78        EntityMap<int, 1> test;
     79
     80        test.insert(1,1);
     81        test.insert(2,2);
     82        test.insert(3,3);
     83        test.insert(4,4);
     84
     85        EntityMap<int, 1>::iterator it = test.begin();
     86        TS_ASSERT(it->first == 1);
     87        it++;
     88        TS_ASSERT(it->first == 2);
     89        ++it;
     90        TS_ASSERT(it->first == 3);
     91        it = test.end();
     92        TS_ASSERT(it->first == test.m_Data.back().first);
     93
     94        EntityMap<int, 1>::const_iterator cit = test.begin();
     95        TS_ASSERT(cit->first == 1);
     96        cit = test.end();
     97        TS_ASSERT(cit->first == test.m_Data.back().first);
     98
     99        size_t iter = 0;
     100        for (auto& v : test)
     101        {
     102            ++iter;
     103            TS_ASSERT(test.find(iter)->second == (int)iter);
     104            TS_ASSERT(test.find(iter)->second == v.second);
     105        }
     106        TS_ASSERT(iter == 4);
     107
     108        test.clear();
     109
     110        test.insert(10,1);
     111        test.insert(20,2);
     112        test.insert(30,3);
     113        test.insert(40,4);
     114
     115        it = test.begin();
     116        TS_ASSERT(it->second == 1);
     117        it++;
     118        TS_ASSERT(it->second == 2);
     119        ++it;
     120        TS_ASSERT(it->second == 3);
     121        it = test.end();
     122        TS_ASSERT(it->first == test.m_Data.back().first);
     123
     124    }
     125
     126    void test_erase()
     127    {
     128        EntityMap<int> test;
     129        test.insert(1,1);
     130        test.insert(2,2);
     131        test.insert(3,3);
     132        test.insert(4,4);
     133
     134        test.erase(2);
     135
     136        TS_ASSERT(test.m_Data.size() == 5);
     137        TS_ASSERT(test.size() == 3);
     138        TS_ASSERT(test.find(2) == test.end());
     139
     140        test.erase(1);
     141        test.erase(3);
     142        TS_ASSERT(test.erase(4) == 1);
     143
     144        TS_ASSERT(test.m_Data.size() == 5);
     145        TS_ASSERT(test.size() == 0);
     146
     147        TS_ASSERT(test.erase(5) == 0);
     148
     149        test.insert(1,1);
     150        test.insert(2,2);
     151        test.insert(3,3);
     152        test.insert(4,4);
     153
     154        test.erase(test.begin());
     155        TS_ASSERT(test.m_Data.size() == 5);
     156        TS_ASSERT(test.size() == 3);
     157        TS_ASSERT(test.find(1) == test.end());
     158
     159        TS_ASSERT(test.erase(test.end()) == 0);
     160        TS_ASSERT(test.m_Data.back().first != INVALID_ENTITY);
     161    }
     162
     163    void test_clear()
     164    {
     165        EntityMap<int> test;
     166        test.insert(1,1);
     167        test.insert(2,2);
     168        test.insert(3,3);
     169        test.insert(4,4);
     170
     171        test.clear();
     172
     173        TS_ASSERT(test.m_Data.size() == 1);
     174        TS_ASSERT(test.size() == 0);
     175    }
     176
     177    void test_find()
     178    {
     179        EntityMap<int> test;
     180        test.insert(1,1);
     181        test.insert(2,2);
     182        test.insert(3,3);
     183        test.insert(40,4);
     184
     185        TS_ASSERT(test.find(1)->second == 1);
     186        TS_ASSERT(test.find(40)->second == 4);
     187        TS_ASSERT(test.find(30) == test.end());
     188    }
     189
     190    void test_perf()
     191    {
     192        EntityMap<int> test;
     193        std::cout << std::endl << "Testing performance of EntityMap" << std::endl;
     194
     195        double t = timer_Time();
     196        for (int i = 1; i <= 200000; ++i)
     197            test.insert(i,i);
     198        double tt = timer_Time() - t;
     199        std::cout << "Inserting 200K elements in order: " << tt << "s" << std::endl;
     200
     201        t = timer_Time();
     202        for (int i = 1; i <= 200000; ++i)
     203            test.erase(i);
     204        tt = timer_Time() - t;
     205        std::cout << "Erasing 200K elements, by key: " << tt << "s" << std::endl;
     206
     207        t = timer_Time();
     208        for (int i = 200000; i >= 1; --i)
     209            test.insert(i,i);
     210        tt = timer_Time() - t;
     211        std::cout << "Inserting 200K elements in reverse order: " << tt << "s" << std::endl;
     212
     213        t = timer_Time();
     214        for (auto i = test.begin(); i != test.end(); ++i)
     215            test.erase(i);
     216        tt = timer_Time() - t;
     217        std::cout << "Erasing 200K elements, by iterator: " << tt << "s" << std::endl;
     218
     219        t = timer_Time();
     220        for (int i = 1; i <= 200000; ++i)
     221            test.erase(i);
     222        tt = timer_Time() - t;
     223        std::cout << "Erasing 200K non-existing elements: " << tt << "s" << std::endl;
     224
     225        // prep random vector
     226        std::vector<int> vec;
     227        for (int i = 1; i <= 200000; ++i)
     228            vec.push_back(i);
     229        std::random_shuffle(vec.begin(), vec.end());
     230
     231        for (int i = 1; i <= 200000; ++i)
     232            test.insert(i,i);
     233
     234        t = timer_Time();
     235        for (int i = 1; i <= 200000; ++i)
     236            test.find(vec[i])->second = 3;
     237        tt = timer_Time() - t;
     238        std::cout << "200K random lookups in random order: " << tt << "s" << std::endl;
     239
     240        t = timer_Time();
     241        for (auto& p : test)
     242            p.second = 3;
     243        tt = timer_Time() - t;
     244        std::cout << "auto iteration on 200K continuous entitymap: " << tt << "s" << std::endl;
     245
     246        test.clear();
     247
     248        for (int i = 1; i <= 200000; ++i)
     249            test.insert(i*5,i);
     250
     251        t = timer_Time();
     252        for (auto& p : test)
     253            p.second = 3;
     254        tt = timer_Time() - t;
     255        std::cout << "auto iteration on 200K sparse (holes of 5): " << tt << "s" << std::endl;
     256
     257        test.clear();
     258
     259        for (int i = 1; i <= 4000; ++i)
     260            test.insert(i*50,i);
     261
     262        t = timer_Time();
     263        for (auto& p : test)
     264            p.second = 3;
     265        tt = timer_Time() - t;
     266        std::cout << "auto iteration on 4K sparse (holes of 50): " << tt << "s" << std::endl;
     267
     268        test.clear();
     269
     270        for (int i = 1; i <= 200000; ++i)
     271            test.insert(i*50,i);
     272
     273        t = timer_Time();
     274        for (auto& p : test)
     275            p.second = 3;
     276        tt = timer_Time() - t;
     277        std::cout << "auto iteration on 200K sparse (holes of 50): " << tt << "s" << std::endl;
     278
     279        test.clear();
     280
     281        for (int i = 1; i <= 2000000; ++i)
     282            test.insert(i*50,i);
     283
     284        t = timer_Time();
     285        for (auto i = test.begin(); i != test.end(); ++i)
     286            i->second = 3;
     287        tt = timer_Time() - t;
     288        std::cout << "manual ++iteration on 2000K sparse (holes of 50) (warmup 1): " << tt << "s" << std::endl;
     289
     290        t = timer_Time();
     291        for (auto i = test.begin(); i != test.end(); i++)
     292            i->second = 3;
     293        tt = timer_Time() - t;
     294        std::cout << "manual iteration++ on 2000K sparse (holes of 50) (warmup 2): " << tt << "s" << std::endl;
     295
     296        t = timer_Time();
     297        for (auto i = test.begin(); i != test.end(); ++i)
     298            i->second = 3;
     299        tt = timer_Time() - t;
     300        std::cout << "manual ++iteration on 2000K sparse (holes of 50): " << tt << "s" << std::endl;
     301
     302        t = timer_Time();
     303        for (auto i = test.begin(); i != test.end(); i++)
     304            i->second = 3;
     305        tt = timer_Time() - t;
     306        std::cout << "manual iteration++ on 2000K sparse (holes of 50): " << tt << "s" << std::endl;
     307
     308    }
     309};
  • new file source/simulation2/tests/test_EntityMap_old.h

    diff --git a/source/simulation2/tests/test_EntityMap_old.h b/source/simulation2/tests/test_EntityMap_old.h
    new file mode 100644
    index 0000000..d377980
    - +  
     1/* Copyright (C) 2010 Wildfire Games.
     2 * This file is part of 0 A.D.
     3 *
     4 * 0 A.D. is free software: you can redistribute it and/or modify
     5 * it under the terms of the GNU General Public License as published by
     6 * the Free Software Foundation, either version 2 of the License, or
     7 * (at your option) any later version.
     8 *
     9 * 0 A.D. is distributed in the hope that it will be useful,
     10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
     11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     12 * GNU General Public License for more details.
     13 *
     14 * You should have received a copy of the GNU General Public License
     15 * along with 0 A.D.  If not, see <http://www.gnu.org/licenses/>.
     16 */
     17
     18#include "lib/self_test.h"
     19#include "lib/timer.h"
     20
     21#include "simulation2/serialization/ISerializer.h"
     22#include "simulation2/serialization/IDeserializer.h"
     23
     24#include "simulation2/system/EntityMap_old.h"
     25
     26class TestEntityMapOld : public CxxTest::TestSuite
     27{
     28public:
     29    void setUp()
     30    {
     31    }
     32
     33    void tearDown()
     34    {
     35    }
     36
     37    void test_insert()
     38    {
     39        EntityMap<int> test;
     40
     41        TS_ASSERT(test.empty());
     42
     43        test.insert(1,1);
     44        test.insert(2,2);
     45        test.insert(3,3);
     46        test.insert(4,4);
     47        test.insert(4,5);
     48        test.insert(4,6);
     49
     50        TS_ASSERT(test.size() == 4);
     51        TS_ASSERT(test.find(3)->second == 3);
     52        TS_ASSERT(test.find(4)->second == 6);
     53
     54        test.insert(10,7);
     55        TS_ASSERT(test.size() == 5);
     56        TS_ASSERT(test.find(4)->second == 6);
     57        TS_ASSERT(test.find(5) == test.end());
     58        TS_ASSERT(test.find(6) == test.end());
     59        TS_ASSERT(test.find(7) == test.end());
     60        TS_ASSERT(test.find(8) == test.end());
     61        TS_ASSERT(test.find(9) == test.end());
     62        TS_ASSERT(test.find(10)->second == 7);
     63
     64    }
     65    void test_iterators()
     66    {
     67        EntityMap<int> test;
     68
     69        test.insert(1,1);
     70        test.insert(2,2);
     71        test.insert(3,3);
     72        test.insert(4,4);
     73
     74        EntityMap<int>::iterator it = test.begin();
     75        TS_ASSERT(it->first == 1);
     76
     77        EntityMap<int>::const_iterator cit = test.begin();
     78        TS_ASSERT(cit->first == 1);
     79
     80        size_t iter = 0;
     81        for (auto& v : test)
     82        {
     83            ++iter;
     84            TS_ASSERT(test.find(iter)->second == (int)iter);
     85            TS_ASSERT(test.find(iter)->second == v.second);
     86        }
     87        TS_ASSERT(iter == 4);
     88    }
     89
     90    void test_erase()
     91    {
     92        EntityMap<int> test;
     93        test.insert(1,1);
     94        test.insert(2,2);
     95        test.insert(3,3);
     96        test.insert(4,4);
     97
     98        test.erase(2);
     99
     100        TS_ASSERT(test.size() == 3);
     101        TS_ASSERT(test.find(2) == test.end());
     102
     103        test.erase(1);
     104        test.erase(3);
     105        test.erase(4);
     106
     107        TS_ASSERT(test.size() == 0);
     108
     109
     110        test.insert(1,1);
     111        test.insert(2,2);
     112        test.insert(3,3);
     113        test.insert(4,4);
     114
     115        test.erase(test.begin());
     116        TS_ASSERT(test.size() == 3);
     117        TS_ASSERT(test.find(1) == test.end());
     118
     119    }
     120
     121    void test_clear()
     122    {
     123        EntityMap<int> test;
     124        test.insert(1,1);
     125        test.insert(2,2);
     126        test.insert(3,3);
     127        test.insert(4,4);
     128
     129        test.clear();
     130
     131        TS_ASSERT(test.size() == 0);
     132    }
     133
     134    void test_find()
     135    {
     136        EntityMap<int> test;
     137        test.insert(1,1);
     138        test.insert(2,2);
     139        test.insert(3,3);
     140        test.insert(40,4);
     141
     142        TS_ASSERT(test.find(1)->second == 1);
     143        TS_ASSERT(test.find(40)->second == 4);
     144        TS_ASSERT(test.find(30) == test.end());
     145    }
     146
     147    void test_perf()
     148    {
     149        EntityMap<int> test;
     150        std::cout << std::endl << "Testing performance of old EntityMap" << std::endl;
     151
     152        double t = timer_Time();
     153        for (int i = 1; i <= 200000; ++i)
     154            test.insert(i,i);
     155        double tt = timer_Time() - t;
     156        std::cout << "Inserting 200K elements in order: " << tt << "s" << std::endl;
     157
     158        t = timer_Time();
     159        for (int i = 1; i <= 200000; ++i)
     160            test.erase(i);
     161        tt = timer_Time() - t;
     162        std::cout << "Erasing 200K elements, by key: " << tt << "s" << std::endl;
     163
     164        t = timer_Time();
     165        for (int i = 200000; i >= 1; --i)
     166            test.insert(i,i);
     167        tt = timer_Time() - t;
     168        std::cout << "Inserting 200K elements in reverse order: " << tt << "s" << std::endl;
     169
     170        t = timer_Time();
     171        for (auto i = test.begin(); i != test.end(); ++i)
     172            test.erase(i);
     173        tt = timer_Time() - t;
     174        std::cout << "Erasing 200K elements, by iterator: " << tt << "s" << std::endl;
     175
     176        t = timer_Time();
     177        for (int i = 1; i <= 200000; ++i)
     178            test.erase(i);
     179        tt = timer_Time() - t;
     180        std::cout << "Erasing 200K non-existing elements: " << tt << "s" << std::endl;
     181
     182        // prep random vector
     183        std::vector<int> vec;
     184        for (int i = 1; i <= 200000; ++i)
     185            vec.push_back(i);
     186        std::random_shuffle(vec.begin(), vec.end());
     187
     188        for (int i = 1; i <= 200000; ++i)
     189            test.insert(i,i);
     190
     191        t = timer_Time();
     192        for (int i = 1; i <= 200000; ++i)
     193            test.find(vec[i])->second = 3;
     194        tt = timer_Time() - t;
     195        std::cout << "200K random lookups in random order: " << tt << "s" << std::endl;
     196
     197        t = timer_Time();
     198        for (auto& p : test)
     199            p.second = 3;
     200        tt = timer_Time() - t;
     201        std::cout << "auto iteration on 200K continuous entitymap: " << tt << "s" << std::endl;
     202
     203        test.clear();
     204
     205        for (int i = 1; i <= 200000; ++i)
     206            test.insert(i*5,i);
     207
     208        t = timer_Time();
     209        for (auto& p : test)
     210            p.second = 3;
     211        tt = timer_Time() - t;
     212        std::cout << "auto iteration on 200K sparse (holes of 5): " << tt << "s" << std::endl;
     213
     214        test.clear();
     215
     216        for (int i = 1; i <= 4000; ++i)
     217            test.insert(i*50,i);
     218
     219        t = timer_Time();
     220        for (auto& p : test)
     221            p.second = 3;
     222        tt = timer_Time() - t;
     223        std::cout << "auto iteration on 4K sparse (holes of 50): " << tt << "s" << std::endl;
     224
     225        test.clear();
     226
     227        for (int i = 1; i <= 200000; ++i)
     228            test.insert(i*50,i);
     229
     230        t = timer_Time();
     231        for (auto& p : test)
     232            p.second = 3;
     233        tt = timer_Time() - t;
     234        std::cout << "auto iteration on 200K sparse (holes of 50): " << tt << "s" << std::endl;
     235
     236        test.clear();
     237    }
     238};