Ticket #4347: patch.patch
File patch.patch, 31.0 KB (added by , 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 21 21 22 22 /** 23 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 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) 28 27 */ 29 template<class T> class EntityMap 28 29 template<class V, size_t FIRST_VALID_ENTITY_ID = 1> class EntityMap 30 30 { 31 31 private: 32 friend class TestEntityMap; 33 32 34 EntityMap(const EntityMap&); // non-copyable 33 35 EntityMap& operator=(const EntityMap&); // non-copyable 34 36 35 37 public: 36 38 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; 45 41 46 42 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 43 std::vector<std::pair<entity_id_t, V> > m_Data; 50 44 51 45 size_t m_Count; // number of 'valid' entity id's 52 46 53 47 public: 54 48 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) 66 50 { 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()}); 68 55 } 69 56 70 // Iterators71 57 template<class U> struct _iter : public std::iterator<std::forward_iterator_tag, U> 72 58 { 73 59 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 78 66 { 79 67 ++val; 80 while (val->first == INVALID_ENTITY) ++val; // skip any invalid entities 68 while (val->first == INVALID_ENTITY) 69 ++val; 81 70 return *this; 82 71 } 83 inline _iter&operator++(int) // it++72 _iter operator++(int) // it++ 84 73 { 85 74 U* ptr = val; 86 75 ++val; 87 while (val->first == INVALID_ENTITY) ++val; // skip any invalid entities 76 while (val->first == INVALID_ENTITY) 77 ++val; 88 78 return ptr; 89 79 } 90 inlinebool operator==(_iter other) { return val == other.val; }91 inlinebool operator!=(_iter other) { return val != other.val; }92 inlineoperator _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); } 93 83 }; 94 84 95 85 typedef _iter<value_type> iterator; 96 86 typedef _iter<value_type const> const_iterator; 97 87 98 i nline iterator begin()88 iterator begin() 99 89 { 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; 103 94 } 104 inline iterator end() 95 96 iterator end() 105 97 { 106 return iterator( m_Buffer + m_BufferSize);98 return iterator(&m_Data.back()); 107 99 } 108 inline const_iterator begin() const 100 101 const_iterator begin() const 109 102 { 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; 113 107 } 114 inline const_iterator end() const 108 109 const_iterator end() const 115 110 { 116 return const_iterator( m_Buffer + m_BufferSize);111 return const_iterator(&m_Data.back()); 117 112 } 118 113 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; } 122 116 123 // Modification124 117 void insert(const key_type key, const mapped_type& value) 125 118 { 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) 127 121 { 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; 148 127 } 149 128 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}; 171 133 } 172 134 173 voiderase(iterator it)135 size_t erase(iterator it) 174 136 { 175 value_type* ptr = it.val; 176 if (ptr->first != INVALID_ENTITY) 137 if (it->first != INVALID_ENTITY && it != end()) 177 138 { 178 ptr->first = INVALID_ENTITY;179 ptr->second.~T(); // call dtor139 it->first = INVALID_ENTITY; 140 it->second.~V(); // call dtor 180 141 --m_Count; 142 return 1; 181 143 } 144 return 0; 182 145 } 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) 197 148 { 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; 210 152 } 211 153 212 // Operations 213 inline iterator find(const entity_id_t key) 154 void clear() 214 155 { 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()}); 222 159 } 223 inline const_iterator find(const entity_id_t key) const 160 161 iterator find(const key_type key) 224 162 { 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(); 232 166 } 233 inline size_t count(const entity_id_t key) const 167 168 const_iterator find(const key_type key) const 234 169 { 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(); 241 173 } 242 174 }; 243 175 -
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 */ 29 template<class T> class EntityMap 30 { 31 private: 32 friend class TestEntityMapOld; 33 EntityMap(const EntityMap&); // non-copyable 34 EntityMap& operator=(const EntityMap&); // non-copyable 35 36 public: 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 47 private: 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 54 public: 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 { 144 fill_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 245 template<class VSerializer> 246 struct 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 26 class TestEntityMap : public CxxTest::TestSuite 27 { 28 public: 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 26 class TestEntityMapOld : public CxxTest::TestSuite 27 { 28 public: 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 };