/* Copyright (C) 2024 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" #include #include 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 DISABLE_test_perf() { 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::shuffle(vec.begin(), vec.end(), std::mt19937{}); 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); } };