Index: ps/trunk/source/simulation2/tests/test_EntityMap.h
===================================================================
--- ps/trunk/source/simulation2/tests/test_EntityMap.h
+++ ps/trunk/source/simulation2/tests/test_EntityMap.h
@@ -0,0 +1,308 @@
+/* Copyright (C) 2019 Wildfire Games.
+ * This file is part of 0 A.D.
+ *
+ * 0 A.D. is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * 0 A.D. is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with 0 A.D. If not, see .
+ */
+
+#include "lib/self_test.h"
+#include "lib/timer.h"
+
+#include "simulation2/serialization/ISerializer.h"
+#include "simulation2/serialization/IDeserializer.h"
+
+#include "simulation2/system/EntityMap.h"
+
+class TestEntityMap : public CxxTest::TestSuite
+{
+public:
+ void setUp()
+ {
+ }
+
+ void tearDown()
+ {
+ }
+
+ void test_insert()
+ {
+ EntityMap test;
+
+ TS_ASSERT(test.empty());
+
+ test.insert(1,1);
+ test.insert(2,2);
+ test.insert(3,3);
+ test.insert(4,4);
+ test.insert(4,5);
+ test.insert(4,6);
+
+// TS_ASSERT(test.m_Data.size() == 5);
+// TS_ASSERT(test.m_Data.back().first != INVALID_ENTITY);
+ TS_ASSERT(test.size() == 4);
+ TS_ASSERT(test.find(3)->second == 3);
+ TS_ASSERT(test.find(4)->second == 6);
+
+ test.insert(10,7);
+// TS_ASSERT(test.m_Data.size() == 11);
+// TS_ASSERT(test.m_Data.back().first != INVALID_ENTITY);
+ TS_ASSERT(test.size() == 5);
+ TS_ASSERT(test.find(4)->second == 6);
+ TS_ASSERT(test.find(5) == test.end());
+ TS_ASSERT(test.find(6) == test.end());
+ TS_ASSERT(test.find(7) == test.end());
+ TS_ASSERT(test.find(8) == test.end());
+ TS_ASSERT(test.find(9) == test.end());
+ TS_ASSERT(test.find(10)->second == 7);
+
+// EntityMap test2;
+
+// test2.insert(8,5);
+// TS_ASSERT(test2.find(8)->second == 5);
+// TS_ASSERT(test2.m_Data.size() == 5);
+// TS_ASSERT(test2.size() == 1);
+
+ }
+ void test_iterators()
+ {
+ EntityMap test;
+
+ test.insert(1,1);
+ test.insert(2,2);
+ test.insert(3,3);
+ test.insert(4,4);
+
+ EntityMap::iterator it = test.begin();
+ TS_ASSERT(it->first == 1);
+ ++it;
+ TS_ASSERT(it->first == 2);
+ ++it; // it++ incorrectly returns a pointer in svn
+ TS_ASSERT(it->first == 3);
+ it = test.end();
+// TS_ASSERT(it->first == test.m_Data.back().first);
+
+ EntityMap::const_iterator cit = test.begin();
+ TS_ASSERT(cit->first == 1);
+ cit = test.end();
+// TS_ASSERT(cit->first == test.m_Data.back().first);
+
+ size_t iter = 0;
+ for (EntityMap::value_type& v : test)
+ {
+ ++iter;
+ TS_ASSERT(test.find(iter)->second == (int)iter);
+ TS_ASSERT(test.find(iter)->second == v.second);
+ }
+ TS_ASSERT(iter == 4);
+
+ test.clear();
+
+ test.insert(10,1);
+ test.insert(20,2);
+ test.insert(30,3);
+ test.insert(40,4);
+
+ it = test.begin();
+ TS_ASSERT(it->second == 1);
+ ++it; // it++ incorrectly returns a pointer in svn
+ TS_ASSERT(it->second == 2);
+ ++it;
+ TS_ASSERT(it->second == 3);
+ it = test.end();
+// TS_ASSERT(it->first == test.m_Data.back().first);
+
+ }
+
+ void test_erase()
+ {
+ EntityMap test;
+ test.insert(1,1);
+ test.insert(2,2);
+ test.insert(3,3);
+ test.insert(4,4);
+
+ test.erase(2);
+
+// TS_ASSERT(test.m_Data.size() == 5);
+ TS_ASSERT(test.size() == 3);
+ TS_ASSERT(test.find(2) == test.end());
+
+ test.erase(1);
+ test.erase(3);
+ test.erase(4);// TS_ASSERT(test.erase(4) == 1);
+
+// TS_ASSERT(test.m_Data.size() == 5);
+ TS_ASSERT(test.size() == 0);
+
+ test.erase(5);// TS_ASSERT(test.erase(5) == 0);
+
+ test.insert(1,1);
+ test.insert(2,2);
+ test.insert(3,3);
+ test.insert(4,4);
+
+ test.erase(test.begin());
+// TS_ASSERT(test.m_Data.size() == 5);
+ TS_ASSERT(test.size() == 3);
+ TS_ASSERT(test.find(1) == test.end());
+
+// TS_ASSERT(test.erase(test.end()) == 0);
+// TS_ASSERT(test.m_Data.back().first != INVALID_ENTITY);
+ }
+
+ void test_clear()
+ {
+ EntityMap test;
+ test.insert(1,1);
+ test.insert(2,2);
+ test.insert(3,3);
+ test.insert(4,4);
+
+ test.clear();
+
+// TS_ASSERT(test.m_Data.size() == 1);
+ TS_ASSERT(test.size() == 0);
+ }
+
+ void test_find()
+ {
+ EntityMap test;
+ test.insert(1,1);
+ test.insert(2,2);
+ test.insert(3,3);
+ test.insert(40,4);
+
+ TS_ASSERT(test.find(1)->second == 1);
+ TS_ASSERT(test.find(40)->second == 4);
+ TS_ASSERT(test.find(30) == test.end());
+ }
+
+ void test_perf_DISABLED()
+ {
+ EntityMap test;
+ printf("Testing performance of EntityMap\n");
+
+ double t = timer_Time();
+ for (int i = 1; i <= 200000; ++i)
+ test.insert(i,i);
+ double tt = timer_Time() - t;
+ printf("inserting 200K elements in order: %lfs\n", tt);
+
+ t = timer_Time();
+ for (int i = 1; i <= 200000; ++i)
+ test.erase(i);
+ tt = timer_Time() - t;
+ printf("Erasing 200K elements, by key: %lfs\n", tt);
+
+ t = timer_Time();
+ for (int i = 200000; i >= 1; --i)
+ test.insert(i,i);
+ tt = timer_Time() - t;
+ printf("inserting 200K elements in reverse order: %lfs\n", tt);
+
+ t = timer_Time();
+ for (auto i = test.begin(); i != test.end(); ++i)
+ test.erase(i);
+ tt = timer_Time() - t;
+ printf("Erasing 200K elements, by iterator: %lfs\n", tt);
+
+ t = timer_Time();
+ for (int i = 1; i <= 200000; ++i)
+ test.erase(i);
+ tt = timer_Time() - t;
+ printf("Erasing 200K non-existing elements: %lfs\n", tt);
+
+ // prep random vector
+ std::vector vec;
+ for (int i = 1; i <= 200000; ++i)
+ vec.push_back(i);
+ std::random_shuffle(vec.begin(), vec.end());
+
+ for (int i = 1; i <= 200000; ++i)
+ test.insert(i,i);
+
+ t = timer_Time();
+ for (int i = 1; i <= 200000; ++i)
+ test.find(vec[i])->second = 3;
+ tt = timer_Time() - t;
+ printf("200K random lookups in random order: %lfs\n", tt);
+
+ t = timer_Time();
+ for (auto& p : test)
+ p.second = 3;
+ tt = timer_Time() - t;
+ printf("auto iteration on 200K continuous entitymap: %lfs\n", tt);
+
+ test.clear();
+
+ for (int i = 1; i <= 200000; ++i)
+ test.insert(i*5,i);
+
+ t = timer_Time();
+ for (EntityMap::value_type& p : test)
+ p.second = 3;
+ tt = timer_Time() - t;
+ printf("auto iteration on 200K sparse (holes of 5): %lfs\n", tt);
+
+ test.clear();
+
+ for (int i = 1; i <= 4000; ++i)
+ test.insert(i*50,i);
+
+ t = timer_Time();
+ for (EntityMap::value_type& p : test)
+ p.second = 3;
+ tt = timer_Time() - t;
+ printf("auto iteration on 4K sparse (holes of 50): %lfs\n", tt);
+
+ test.clear();
+
+ for (int i = 1; i <= 200000; ++i)
+ test.insert(i*50,i);
+
+ t = timer_Time();
+ for (EntityMap::value_type& p : test)
+ p.second = 3;
+ tt = timer_Time() - t;
+ printf("auto iteration on 200K sparse (holes of 50): %lfs\n", tt);
+
+ test.clear();
+
+ for (int i = 1; i <= 2000000; ++i)
+ test.insert(i*50,i);
+
+ t = timer_Time();
+ for (EntityMap::iterator i = test.begin(); i != test.end(); ++i)
+ i->second = 3;
+ tt = timer_Time() - t;
+ printf("manual ++iteration on 2000K sparse (holes of 50) (warmup 1): %lfs\n", tt);
+
+ t = timer_Time();
+ for (EntityMap::iterator i = test.begin(); i != test.end(); ++i)
+ i->second = 3;
+ tt = timer_Time() - t;
+ printf("manual ++iteration on 2000K sparse (holes of 50) (warmup 2): %lfs\n", tt);
+
+ t = timer_Time();
+ for (EntityMap::iterator i = test.begin(); i != test.end(); ++i)
+ i->second = 3;
+ tt = timer_Time() - t;
+ printf("manual ++iteration on 2000K sparse (holes of 50): %lfs\n", tt);
+
+ t = timer_Time();
+ for (EntityMap::iterator i = test.begin(); i != test.end(); ++i)
+ i->second = 3;
+ tt = timer_Time() - t;
+ printf("manual iteration++ on 2000K sparse (holes of 50): %lfs\n", tt);
+ }
+};