1
0
forked from 0ad/0ad

Change internals of EntityMap to use an std::vector

This generally makes this code cleaner and easier to maintain, while
also being more modern and fully tested.

Looked at by: leper
Differential Revision: https://code.wildfiregames.com/D8
This was SVN commit r22029.
This commit is contained in:
wraitii 2019-01-05 18:19:59 +00:00
parent f21d79640c
commit b56f7f39d4
3 changed files with 194 additions and 249 deletions

View File

@ -1,4 +1,4 @@
/* Copyright (C) 2018 Wildfire Games. /* Copyright (C) 2019 Wildfire Games.
* This file is part of 0 A.D. * This file is part of 0 A.D.
* *
* 0 A.D. is free software: you can redistribute it and/or modify * 0 A.D. is free software: you can redistribute it and/or modify
@ -539,7 +539,7 @@ public:
entdata.size = cmpObstruction->GetSize().ToInt_RoundToInfinity(); entdata.size = cmpObstruction->GetSize().ToInt_RoundToInfinity();
// Remember this entity // Remember this entity
m_EntityData.insert(ent, entdata); m_EntityData.insert_or_assign(ent, entdata);
break; break;
} }
case MT_PositionChanged: case MT_PositionChanged:

View File

@ -1,4 +1,4 @@
/* Copyright (C) 2013 Wildfire Games. /* Copyright (C) 2019 Wildfire Games.
* This file is part of 0 A.D. * This file is part of 0 A.D.
* *
* 0 A.D. is free software: you can redistribute it and/or modify * 0 A.D. is free software: you can redistribute it and/or modify
@ -19,226 +19,171 @@
#include "Entity.h" #include "Entity.h"
#include <utility>
static const size_t ENTITYMAP_DEFAULT_SIZE = 4096;
/** /**
* A fast replacement for map<entity_id_t, T>. * A fast replacement for map<entity_id_t, T>.
* We make the following assumptions: * Behaves like a much faster std:map.
* - entity id's (keys) are unique * The drawback is memory usage, as this uses sparse storage.
* - modifications (add / delete) are far less frequent then look-ups * So creating/deleting entities will lead to inefficiency.
* - preformance for iteration is important
*/ */
template<class T> class EntityMap
template<class V, entity_id_t FIRST_VALID_ENTITY_ID = 1, size_t initialSize = ENTITYMAP_DEFAULT_SIZE>
class EntityMap
{ {
static_assert(FIRST_VALID_ENTITY_ID > INVALID_ENTITY, "Entity IDs start at INVALID_ENTITY");
private: private:
EntityMap(const EntityMap&); // non-copyable friend class TestEntityMap;
EntityMap& operator=(const EntityMap&); // non-copyable
EntityMap(const EntityMap&) = delete;
EntityMap& operator=(const EntityMap&) = delete;
public: public:
typedef entity_id_t key_type; typedef entity_id_t key_type;
typedef T mapped_type; typedef V mapped_type;
template<class K, class V> struct key_val { typedef std::pair<entity_id_t, V> value_type;
typedef K first_type;
typedef V second_type;
K first;
V second;
};
typedef key_val<entity_id_t, T> value_type;
private: private:
size_t m_BufferSize; // number of elements in the buffer std::vector<value_type> m_Data;
size_t m_BufferCapacity; // capacity of the buffer
value_type* m_Buffer; // vector with all the mapped key-value pairs
size_t m_Count; // number of 'valid' entity id's // number of 'valid' entity id's
size_t m_Count;
// EntityMap keeps a valid entity ID at the end() so _iter<>::operator++ knows when to stop the loop
// Use FIRST_VALID_ENTITY_ID since we are sure that that is indeed a valid ID.
#define ITERATOR_FENCE {FIRST_VALID_ENTITY_ID, V()}
public: public:
inline EntityMap() : m_BufferSize(1), m_BufferCapacity(4096), m_Count(0) EntityMap()
: m_Count(0)
{ {
// for entitymap we allocate the buffer right away m_Data.reserve(initialSize);
// with first element in buffer being the Invalid Entity m_Data.push_back(ITERATOR_FENCE);
m_Buffer = (value_type*)malloc(sizeof(value_type) * (m_BufferCapacity + 1));
// create the first element:
m_Buffer[0].first = INVALID_ENTITY;
m_Buffer[1].first = 0xFFFFFFFF; // ensure end() always has 0xFFFFFFFF
}
inline ~EntityMap()
{
free(m_Buffer);
} }
// Iterators
template<class U> struct _iter : public std::iterator<std::forward_iterator_tag, U> template<class U> struct _iter : public std::iterator<std::forward_iterator_tag, U>
{ {
U* val; U* val;
inline _iter(U* init) : val(init) {} _iter(U* init) : val(init) {}
inline U& operator*() { return *val; } template<class T>
inline U* operator->() { return val; } _iter(const _iter<T>& it) : val(it.val) {}
inline _iter& operator++() // ++it
U& operator*() { return *val; }
U* operator->() { return val; }
_iter& operator++() // ++it
{ {
++val; do
while (val->first == INVALID_ENTITY) ++val; // skip any invalid entities ++val;
while (val->first == INVALID_ENTITY);
return *this; return *this;
} }
inline _iter& operator++(int) // it++ _iter operator++(int) // it++
{ {
U* ptr = val; _iter orig = *this;
++val; ++(*this);
while (val->first == INVALID_ENTITY) ++val; // skip any invalid entities return orig;
return ptr;
} }
inline bool operator==(_iter other) { return val == other.val; } bool operator==(_iter other) { return val == other.val; }
inline bool operator!=(_iter other) { return val != other.val; } bool operator!=(_iter other) { return val != other.val; }
inline operator _iter<U const>() const { return _iter<U const>(val); }
}; };
typedef _iter<value_type> iterator; typedef _iter<value_type> iterator;
typedef _iter<value_type const> const_iterator; typedef _iter<const value_type> const_iterator;
inline iterator begin() iterator begin()
{ {
value_type* ptr = m_Buffer + 1; // skip the first INVALID_ENTITY iterator it = &m_Data.front();
while (ptr->first == INVALID_ENTITY) ++ptr; // skip any other invalid entities if (it->first == INVALID_ENTITY)
return ptr; ++it; // skip all invalid entities
} return it;
inline iterator end()
{
return iterator(m_Buffer + m_BufferSize);
}
inline const_iterator begin() const
{
value_type* ptr = m_Buffer + 1; // skip the first INVALID_ENTITY
while (ptr->first == INVALID_ENTITY) ++ptr; // skip any other invalid entities
return ptr;
}
inline const_iterator end() const
{
return const_iterator(m_Buffer + m_BufferSize);
} }
// Size const_iterator begin() const
inline bool empty() const { return m_Count == 0; }
inline size_t size() const { return m_Count; }
// Modification
void insert(const key_type key, const mapped_type& value)
{ {
if (key >= m_BufferCapacity) // do we need to resize buffer? const_iterator it = &m_Data.front();
if (it->first == INVALID_ENTITY)
++it;
return it;
}
iterator end()
{
return iterator(&m_Data.back()); // return the ITERATOR_FENCE, see above
}
const_iterator end() const
{
return const_iterator(&m_Data.back()); // return the ITERATOR_FENCE, see above
}
bool empty() const { return m_Count == 0; }
size_t size() const { return m_Count; }
std::pair<iterator, bool> insert_or_assign(const key_type& key, const mapped_type& value)
{
ENSURE(key >= FIRST_VALID_ENTITY_ID);
if (key-FIRST_VALID_ENTITY_ID+1 >= m_Data.size())
{ {
size_t newCapacity = m_BufferCapacity + 4096; // Fill [end(),…,key[ invalid entities, our new key, and then add a new iterator gate at the end;
while (key >= newCapacity) newCapacity += 4096; // resize, make sure to keep a valid entity ID at the end by adding a new ITERATOR_FENCE
// always allocate +1 behind the scenes, because end() must have a 0xFFFFFFFF key m_Data.back().first = INVALID_ENTITY; // reset current iterator gate
value_type* mem = (value_type*)realloc(m_Buffer, sizeof(value_type) * (newCapacity + 1)); m_Data.resize(key-FIRST_VALID_ENTITY_ID+2, {INVALID_ENTITY, V()});
if (!mem) m_Data.back() = ITERATOR_FENCE;
{
debug_warn("EntityMap::insert() realloc failed! Out of memory.");
throw std::bad_alloc(); // fail to expand and insert
}
m_BufferCapacity = newCapacity;
m_Buffer = mem;
goto fill_gaps;
} }
else if (key > m_BufferSize) // weird insert far beyond the end bool inserted = false;
if (m_Data[key-FIRST_VALID_ENTITY_ID].first == INVALID_ENTITY)
{ {
fill_gaps: inserted = true;
// set all entity id's to INVALID_ENTITY inside the new range
for (size_t i = m_BufferSize; i <= key; ++i)
m_Buffer[i].first = INVALID_ENTITY;
m_BufferSize = key; // extend the new size
}
value_type& item = m_Buffer[key];
key_type oldKey = item.first;
item.first = key;
if (key == m_BufferSize) // push_back
{
++m_BufferSize; // expand
++m_Count; ++m_Count;
new (&item.second) mapped_type(value); // copy ctor to init
m_Buffer[m_BufferSize].first = 0xFFFFFFFF; // ensure end() always has 0xFFFFFFFF
}
else if(!item.first) // insert new to middle
{
++m_Count;
new (&item.second) mapped_type(value); // copy ctor to init
}
else // set existing value
{
if (oldKey == INVALID_ENTITY)
m_Count++;
item.second = value; // overwrite existing
} }
m_Data[key-FIRST_VALID_ENTITY_ID] = {key, value};
return {iterator(&m_Data[key-FIRST_VALID_ENTITY_ID]), inserted};
} }
void erase(iterator it) size_t erase(iterator it)
{ {
value_type* ptr = it.val; if (it->first != INVALID_ENTITY && it != end())
if (ptr->first != INVALID_ENTITY)
{ {
ptr->first = INVALID_ENTITY; it->first = INVALID_ENTITY;
ptr->second.~T(); // call dtor it->second.~V(); // call dtor
--m_Count; --m_Count;
} return 1;
}
void erase(const entity_id_t key)
{
if (key < m_BufferSize)
{
value_type* ptr = m_Buffer + key;
if (ptr->first != INVALID_ENTITY)
{
ptr->first = INVALID_ENTITY;
ptr->second.~T(); // call dtor
--m_Count;
}
}
}
inline void clear()
{
// orphan whole range
value_type* ptr = m_Buffer;
value_type* end = m_Buffer + m_BufferSize;
for (; ptr != end; ++ptr)
{
if (ptr->first != INVALID_ENTITY)
{
ptr->first = INVALID_ENTITY;
ptr->second.~T(); // call dtor
}
}
m_Count = 0; // no more valid entities
}
// Operations
inline iterator find(const entity_id_t key)
{
if (key < m_BufferSize) // is this key in the range of existing entitites?
{
value_type* ptr = m_Buffer + key;
if (ptr->first != INVALID_ENTITY)
return ptr;
}
return m_Buffer + m_BufferSize; // return iterator end()
}
inline const_iterator find(const entity_id_t key) const
{
if (key < m_BufferSize) // is this key in the range of existing entitites?
{
const value_type* ptr = m_Buffer + key;
if (ptr->first != INVALID_ENTITY)
return ptr;
}
return m_Buffer + m_BufferSize; // return iterator end()
}
inline size_t count(const entity_id_t key) const
{
if (key < m_BufferSize)
{
if (m_Buffer[key].first != INVALID_ENTITY)
return 1;
} }
return 0; return 0;
} }
size_t erase(const key_type& key)
{
if (key-FIRST_VALID_ENTITY_ID+1 < m_Data.size())
return erase(&m_Data.front() + key - FIRST_VALID_ENTITY_ID);
return 0;
}
void clear()
{
m_Data.clear();
m_Count = 0;
m_Data.push_back(ITERATOR_FENCE);
}
iterator find(const key_type& key)
{
if (key-FIRST_VALID_ENTITY_ID+1 < m_Data.size() && m_Data[key-FIRST_VALID_ENTITY_ID].first != INVALID_ENTITY)
return &m_Data.front() + (key - FIRST_VALID_ENTITY_ID);
return end();
}
const_iterator find(const key_type& key) const
{
if (key-FIRST_VALID_ENTITY_ID+1 < m_Data.size() && m_Data[key-FIRST_VALID_ENTITY_ID].first != INVALID_ENTITY)
return &m_Data.front() + (key - FIRST_VALID_ENTITY_ID);
return end();
}
#undef ITERATOR_FENCE
}; };
template<class VSerializer> template<class VSerializer>
@ -273,7 +218,7 @@ struct SerializeEntityMap
V v; V v;
deserialize.NumberU32_Unbounded("key", k); deserialize.NumberU32_Unbounded("key", k);
VSerializer()(deserialize, "value", v); VSerializer()(deserialize, "value", v);
value.insert(k, v); value.insert_or_assign(k, v);
} }
} }
}; };

View File

@ -34,28 +34,28 @@ public:
{ {
} }
void test_insert() void test_insert_or_assign()
{ {
EntityMap<int> test; EntityMap<int, 1> test;
TS_ASSERT(test.empty()); TS_ASSERT(test.empty());
test.insert(1,1); test.insert_or_assign(1,1);
test.insert(2,2); test.insert_or_assign(2,2);
test.insert(3,3); test.insert_or_assign(3,3);
test.insert(4,4); test.insert_or_assign(4,4);
test.insert(4,5); test.insert_or_assign(4,5);
test.insert(4,6); test.insert_or_assign(4,6);
// TS_ASSERT(test.m_Data.size() == 5); TS_ASSERT(test.m_Data.size() == 5);
// TS_ASSERT(test.m_Data.back().first != INVALID_ENTITY); TS_ASSERT(test.m_Data.back().first != INVALID_ENTITY);
TS_ASSERT(test.size() == 4); TS_ASSERT(test.size() == 4);
TS_ASSERT(test.find(3)->second == 3); TS_ASSERT(test.find(3)->second == 3);
TS_ASSERT(test.find(4)->second == 6); TS_ASSERT(test.find(4)->second == 6);
test.insert(10,7); test.insert_or_assign(10,7);
// TS_ASSERT(test.m_Data.size() == 11); TS_ASSERT(test.m_Data.size() == 11);
// TS_ASSERT(test.m_Data.back().first != INVALID_ENTITY); TS_ASSERT(test.m_Data.back().first != INVALID_ENTITY);
TS_ASSERT(test.size() == 5); TS_ASSERT(test.size() == 5);
TS_ASSERT(test.find(4)->second == 6); TS_ASSERT(test.find(4)->second == 6);
TS_ASSERT(test.find(5) == test.end()); TS_ASSERT(test.find(5) == test.end());
@ -65,39 +65,39 @@ public:
TS_ASSERT(test.find(9) == test.end()); TS_ASSERT(test.find(9) == test.end());
TS_ASSERT(test.find(10)->second == 7); TS_ASSERT(test.find(10)->second == 7);
// EntityMap<int, 5> test2; EntityMap<int, 5> test2;
// test2.insert(8,5); test2.insert_or_assign(8,5);
// TS_ASSERT(test2.find(8)->second == 5); TS_ASSERT(test2.find(8)->second == 5);
// TS_ASSERT(test2.m_Data.size() == 5); TS_ASSERT(test2.m_Data.size() == 5);
// TS_ASSERT(test2.size() == 1); TS_ASSERT(test2.size() == 1);
} }
void test_iterators() void test_iterators()
{ {
EntityMap<int> test; EntityMap<int, 1> test;
test.insert(1,1); test.insert_or_assign(1,1);
test.insert(2,2); test.insert_or_assign(2,2);
test.insert(3,3); test.insert_or_assign(3,3);
test.insert(4,4); test.insert_or_assign(4,4);
EntityMap<int>::iterator it = test.begin(); EntityMap<int, 1>::iterator it = test.begin();
TS_ASSERT(it->first == 1); TS_ASSERT(it->first == 1);
++it; it++;
TS_ASSERT(it->first == 2); TS_ASSERT(it->first == 2);
++it; // it++ incorrectly returns a pointer in svn ++it;
TS_ASSERT(it->first == 3); TS_ASSERT(it->first == 3);
it = test.end(); it = test.end();
// TS_ASSERT(it->first == test.m_Data.back().first); TS_ASSERT(it->first == test.m_Data.back().first);
EntityMap<int>::const_iterator cit = test.begin(); EntityMap<int, 1>::const_iterator cit = test.begin();
TS_ASSERT(cit->first == 1); TS_ASSERT(cit->first == 1);
cit = test.end(); cit = test.end();
// TS_ASSERT(cit->first == test.m_Data.back().first); TS_ASSERT(cit->first == test.m_Data.back().first);
size_t iter = 0; size_t iter = 0;
for (EntityMap<int>::value_type& v : test) for (EntityMap<int, 1>::value_type& v : test)
{ {
++iter; ++iter;
TS_ASSERT(test.find(iter)->second == (int)iter); TS_ASSERT(test.find(iter)->second == (int)iter);
@ -107,80 +107,80 @@ public:
test.clear(); test.clear();
test.insert(10,1); test.insert_or_assign(10,1);
test.insert(20,2); test.insert_or_assign(20,2);
test.insert(30,3); test.insert_or_assign(30,3);
test.insert(40,4); test.insert_or_assign(40,4);
it = test.begin(); it = test.begin();
TS_ASSERT(it->second == 1); TS_ASSERT(it->second == 1);
++it; // it++ incorrectly returns a pointer in svn it++;
TS_ASSERT(it->second == 2); TS_ASSERT(it->second == 2);
++it; ++it;
TS_ASSERT(it->second == 3); TS_ASSERT(it->second == 3);
it = test.end(); it = test.end();
// TS_ASSERT(it->first == test.m_Data.back().first); TS_ASSERT(it->first == test.m_Data.back().first);
} }
void test_erase() void test_erase()
{ {
EntityMap<int> test; EntityMap<int> test;
test.insert(1,1); test.insert_or_assign(1,1);
test.insert(2,2); test.insert_or_assign(2,2);
test.insert(3,3); test.insert_or_assign(3,3);
test.insert(4,4); test.insert_or_assign(4,4);
test.erase(2); test.erase(2);
// TS_ASSERT(test.m_Data.size() == 5); TS_ASSERT(test.m_Data.size() == 5);
TS_ASSERT(test.size() == 3); TS_ASSERT(test.size() == 3);
TS_ASSERT(test.find(2) == test.end()); TS_ASSERT(test.find(2) == test.end());
test.erase(1); test.erase(1);
test.erase(3); test.erase(3);
test.erase(4);// TS_ASSERT(test.erase(4) == 1); TS_ASSERT(test.erase(4) == 1);
// TS_ASSERT(test.m_Data.size() == 5); TS_ASSERT(test.m_Data.size() == 5);
TS_ASSERT(test.size() == 0); TS_ASSERT(test.size() == 0);
test.erase(5);// TS_ASSERT(test.erase(5) == 0); TS_ASSERT(test.erase(5) == 0);
test.insert(1,1); test.insert_or_assign(1,1);
test.insert(2,2); test.insert_or_assign(2,2);
test.insert(3,3); test.insert_or_assign(3,3);
test.insert(4,4); test.insert_or_assign(4,4);
test.erase(test.begin()); test.erase(test.begin());
// TS_ASSERT(test.m_Data.size() == 5); TS_ASSERT(test.m_Data.size() == 5);
TS_ASSERT(test.size() == 3); TS_ASSERT(test.size() == 3);
TS_ASSERT(test.find(1) == test.end()); TS_ASSERT(test.find(1) == test.end());
// TS_ASSERT(test.erase(test.end()) == 0); TS_ASSERT(test.erase(test.end()) == 0);
// TS_ASSERT(test.m_Data.back().first != INVALID_ENTITY); TS_ASSERT(test.m_Data.back().first != INVALID_ENTITY);
} }
void test_clear() void test_clear()
{ {
EntityMap<int> test; EntityMap<int> test;
test.insert(1,1); test.insert_or_assign(1,1);
test.insert(2,2); test.insert_or_assign(2,2);
test.insert(3,3); test.insert_or_assign(3,3);
test.insert(4,4); test.insert_or_assign(4,4);
test.clear(); test.clear();
// TS_ASSERT(test.m_Data.size() == 1); TS_ASSERT(test.m_Data.size() == 1);
TS_ASSERT(test.size() == 0); TS_ASSERT(test.size() == 0);
} }
void test_find() void test_find()
{ {
EntityMap<int> test; EntityMap<int> test;
test.insert(1,1); test.insert_or_assign(1,1);
test.insert(2,2); test.insert_or_assign(2,2);
test.insert(3,3); test.insert_or_assign(3,3);
test.insert(40,4); test.insert_or_assign(40,4);
TS_ASSERT(test.find(1)->second == 1); TS_ASSERT(test.find(1)->second == 1);
TS_ASSERT(test.find(40)->second == 4); TS_ASSERT(test.find(40)->second == 4);
@ -194,9 +194,9 @@ public:
double t = timer_Time(); double t = timer_Time();
for (int i = 1; i <= 200000; ++i) for (int i = 1; i <= 200000; ++i)
test.insert(i,i); test.insert_or_assign(i,i);
double tt = timer_Time() - t; double tt = timer_Time() - t;
printf("inserting 200K elements in order: %lfs\n", tt); printf("insert_or_assigning 200K elements in order: %lfs\n", tt);
t = timer_Time(); t = timer_Time();
for (int i = 1; i <= 200000; ++i) for (int i = 1; i <= 200000; ++i)
@ -206,9 +206,9 @@ public:
t = timer_Time(); t = timer_Time();
for (int i = 200000; i >= 1; --i) for (int i = 200000; i >= 1; --i)
test.insert(i,i); test.insert_or_assign(i,i);
tt = timer_Time() - t; tt = timer_Time() - t;
printf("inserting 200K elements in reverse order: %lfs\n", tt); printf("insert_or_assigning 200K elements in reverse order: %lfs\n", tt);
t = timer_Time(); t = timer_Time();
for (auto i = test.begin(); i != test.end(); ++i) for (auto i = test.begin(); i != test.end(); ++i)
@ -229,7 +229,7 @@ public:
std::random_shuffle(vec.begin(), vec.end()); std::random_shuffle(vec.begin(), vec.end());
for (int i = 1; i <= 200000; ++i) for (int i = 1; i <= 200000; ++i)
test.insert(i,i); test.insert_or_assign(i,i);
t = timer_Time(); t = timer_Time();
for (int i = 1; i <= 200000; ++i) for (int i = 1; i <= 200000; ++i)
@ -246,7 +246,7 @@ public:
test.clear(); test.clear();
for (int i = 1; i <= 200000; ++i) for (int i = 1; i <= 200000; ++i)
test.insert(i*5,i); test.insert_or_assign(i*5,i);
t = timer_Time(); t = timer_Time();
for (EntityMap<int>::value_type& p : test) for (EntityMap<int>::value_type& p : test)
@ -257,7 +257,7 @@ public:
test.clear(); test.clear();
for (int i = 1; i <= 4000; ++i) for (int i = 1; i <= 4000; ++i)
test.insert(i*50,i); test.insert_or_assign(i*50,i);
t = timer_Time(); t = timer_Time();
for (EntityMap<int>::value_type& p : test) for (EntityMap<int>::value_type& p : test)
@ -268,7 +268,7 @@ public:
test.clear(); test.clear();
for (int i = 1; i <= 200000; ++i) for (int i = 1; i <= 200000; ++i)
test.insert(i*50,i); test.insert_or_assign(i*50,i);
t = timer_Time(); t = timer_Time();
for (EntityMap<int>::value_type& p : test) for (EntityMap<int>::value_type& p : test)
@ -279,7 +279,7 @@ public:
test.clear(); test.clear();
for (int i = 1; i <= 2000000; ++i) for (int i = 1; i <= 2000000; ++i)
test.insert(i*50,i); test.insert_or_assign(i*50,i);
t = timer_Time(); t = timer_Time();
for (EntityMap<int>::iterator i = test.begin(); i != test.end(); ++i) for (EntityMap<int>::iterator i = test.begin(); i != test.end(); ++i)
@ -288,7 +288,7 @@ public:
printf("manual ++iteration on 2000K sparse (holes of 50) (warmup 1): %lfs\n", tt); printf("manual ++iteration on 2000K sparse (holes of 50) (warmup 1): %lfs\n", tt);
t = timer_Time(); t = timer_Time();
for (EntityMap<int>::iterator i = test.begin(); i != test.end(); ++i) for (EntityMap<int>::iterator i = test.begin(); i != test.end(); i++)
i->second = 3; i->second = 3;
tt = timer_Time() - t; tt = timer_Time() - t;
printf("manual ++iteration on 2000K sparse (holes of 50) (warmup 2): %lfs\n", tt); printf("manual ++iteration on 2000K sparse (holes of 50) (warmup 2): %lfs\n", tt);
@ -300,7 +300,7 @@ public:
printf("manual ++iteration on 2000K sparse (holes of 50): %lfs\n", tt); printf("manual ++iteration on 2000K sparse (holes of 50): %lfs\n", tt);
t = timer_Time(); t = timer_Time();
for (EntityMap<int>::iterator i = test.begin(); i != test.end(); ++i) for (EntityMap<int>::iterator i = test.begin(); i != test.end(); i++)
i->second = 3; i->second = 3;
tt = timer_Time() - t; tt = timer_Time() - t;
printf("manual iteration++ on 2000K sparse (holes of 50): %lfs\n", tt); printf("manual iteration++ on 2000K sparse (holes of 50): %lfs\n", tt);