//============================================================================== ANKI_TEST(Resource, ResourceFilesystem) { printf("Test requires the data dir\n"); HeapAllocator<U8> alloc(allocAligned, nullptr); ResourceFilesystem fs(alloc); { ANKI_TEST_EXPECT_NO_ERR(fs.addNewPath("data/dir/../dir/")); ResourceFilePtr file; ANKI_TEST_EXPECT_NO_ERR(fs.openFile("subdir0/hello.txt", file)); StringAuto txt(alloc); ANKI_TEST_EXPECT_NO_ERR(file->readAllText(alloc, txt)); ANKI_TEST_EXPECT_EQ(txt, "hello\n"); } { ANKI_TEST_EXPECT_NO_ERR(fs.addNewPath("./data/dir.ankizip")); ResourceFilePtr file; ANKI_TEST_EXPECT_NO_ERR(fs.openFile("subdir0/hello.txt", file)); StringAuto txt(alloc); ANKI_TEST_EXPECT_NO_ERR(file->readAllText(alloc, txt)); ANKI_TEST_EXPECT_EQ(txt, "hell\n"); } }
//============================================================================== ANKI_TEST(Util, Thread) { static const char* THREAD_NAME = "name"; Thread t(THREAD_NAME); static const U64 NUMBER = 0xFAFAFAFABABABA; U64 u = NUMBER; t.start(&u, [](Thread::Info& info) -> Error { Bool check = true; // Check name check = check && (std::strcmp(info.m_threadName, THREAD_NAME) == 0); // Check user value U64& num = *reinterpret_cast<U64*>(info.m_userData); check = check && (num == NUMBER); // Change number num = 0xF00; HighRezTimer::sleep(1.0); return (check != true) ? ErrorCode::FUNCTION_FAILED : ErrorCode::NONE; }); Error err = t.join(); ANKI_TEST_EXPECT_EQ(err, 0); ANKI_TEST_EXPECT_EQ(u, 0xF00); }
ANKI_TEST(Memory, ChainMemoryPool) { // Basic test { const U size = 8; ChainMemoryPool pool; Error error = pool.create( allocAligned, nullptr, size, size + 1, ChainMemoryPool::ChunkGrowMethod::MULTIPLY, 2, 1); ANKI_TEST_EXPECT_EQ(error, ErrorCode::NONE); void* mem = pool.allocate(5, 1); ANKI_TEST_EXPECT_NEQ(mem, nullptr); void* mem1 = pool.allocate(5, 1); ANKI_TEST_EXPECT_NEQ(mem1, nullptr); pool.free(mem1); pool.free(mem); ANKI_TEST_EXPECT_EQ(pool.getChunksCount(), 0); } // Basic test 2 { const U size = sizeof(PtrSize) + 10; ChainMemoryPool pool; Error error = pool.create( allocAligned, nullptr, size, size * 2, ChainMemoryPool::ChunkGrowMethod::MULTIPLY, 2, 1); ANKI_TEST_EXPECT_EQ(error, ErrorCode::NONE); void* mem = pool.allocate(size, 1); ANKI_TEST_EXPECT_NEQ(mem, nullptr); void* mem1 = pool.allocate(size, 1); ANKI_TEST_EXPECT_NEQ(mem1, nullptr); void* mem3 = pool.allocate(size, 1); ANKI_TEST_EXPECT_NEQ(mem1, nullptr); pool.free(mem1); mem1 = pool.allocate(size, 1); ANKI_TEST_EXPECT_NEQ(mem1, nullptr); pool.free(mem3); pool.free(mem1); pool.free(mem); ANKI_TEST_EXPECT_EQ(pool.getChunksCount(), 0); } }
ANKI_TEST(Allocators, StackAllocator) { Foo::reset(); // With simple string { StackAllocator<char, false> alloc( StackMemoryPool(allocAligned, nullptr, 128)); typedef std::basic_string<char, std::char_traits<char>, StackAllocator<char, false>> Str; Str str(alloc); str = "lalala"; str = "lalalalo"; } // With vector { typedef StackAllocator<Foo, false> All; All alloc(StackMemoryPool(allocAligned, nullptr, (sizeof(Foo) + 1) * 10, 1)); std::vector<Foo, All> vec(alloc); vec.reserve(10); U sumi = 0; for(U i = 0; i < 10; i++) { std::cout << "pushing" << std::endl; vec.push_back(Foo(10 * i)); sumi += 10 * i; } U sum = 0; for(const Foo& foo : vec) { sum += foo.x; } ANKI_TEST_EXPECT_EQ(sum, sumi); } ANKI_TEST_EXPECT_EQ(Foo::constructorCallCount, Foo::destructorCallCount); // End Foo::reset(); }
ANKI_TEST(Util, Threadpool) { const U32 threadsCount = 4; const U32 repeat = 5; Threadpool* tp = new Threadpool(threadsCount); TestJobTP jobs[threadsCount]; for(U32 i = 1; i < repeat; i++) { U32 iterations = rand() % 100000; for(U32 j = 0; j < threadsCount; j++) { jobs[j].in = i; jobs[j].iterations = iterations; tp->assignNewTask(j, &jobs[j]); } ANKI_TEST_EXPECT_NO_ERR(tp->waitForAllThreadsToFinish()); for(U32 j = 0; j < threadsCount; j++) { ANKI_TEST_EXPECT_EQ(jobs[j].in, i + iterations); } } delete tp; }
//============================================================================== ANKI_TEST(Util, Mutex) { Thread t0(nullptr), t1(nullptr); Mutex mtx; static const U ITERATIONS = 1000000; class In { public: I64 m_num = ITERATIONS; Mutex* m_mtx; }; In in; in.m_mtx = &mtx; t0.start(&in, [](Thread::Info& info) -> Error { In& in = *reinterpret_cast<In*>(info.m_userData); I64& num = in.m_num; Mutex& mtx = *in.m_mtx; for(U i = 0; i < ITERATIONS; i++) { mtx.lock(); num += 2; mtx.unlock(); } return ErrorCode::NONE; }); t1.start(&in, [](Thread::Info& info) -> Error { In& in = *reinterpret_cast<In*>(info.m_userData); I64& num = in.m_num; Mutex& mtx = *in.m_mtx; for(U i = 0; i < ITERATIONS; i++) { mtx.lock(); --num; mtx.unlock(); } return ErrorCode::NONE; }); ANKI_TEST_EXPECT_NO_ERR(t0.join()); ANKI_TEST_EXPECT_NO_ERR(t1.join()); ANKI_TEST_EXPECT_EQ(in.m_num, ITERATIONS * 2); }
ANKI_TEST(Gr, Buffer) { COMMON_BEGIN() BufferPtr a = gr->newInstance<Buffer>(512, BufferUsageBit::UNIFORM_ALL, BufferMapAccessBit::NONE); BufferPtr b = gr->newInstance<Buffer>(64, BufferUsageBit::STORAGE_ALL, BufferMapAccessBit::WRITE | BufferMapAccessBit::READ); void* ptr = b->map(0, 64, BufferMapAccessBit::WRITE); ANKI_TEST_EXPECT_NEQ(ptr, nullptr); U8 ptr2[64]; memset(ptr, 0xCC, 64); memset(ptr2, 0xCC, 64); b->unmap(); ptr = b->map(0, 64, BufferMapAccessBit::READ); ANKI_TEST_EXPECT_NEQ(ptr, nullptr); ANKI_TEST_EXPECT_EQ(memcmp(ptr, ptr2, 64), 0); b->unmap(); COMMON_END() }
ANKI_TEST(Resource, ResourceManager) { // Create Config config; HeapAllocator<U8> alloc(allocAligned, nullptr); ResourceManagerInitInfo rinit; rinit.m_gr = nullptr; rinit.m_config = &config; rinit.m_cacheDir = "/tmp/"; rinit.m_allocCallback = allocAligned; rinit.m_allocCallbackData = nullptr; ResourceManager* resources = alloc.newInstance<ResourceManager>(); ANKI_TEST_EXPECT_NO_ERR(resources->create(rinit)); // Very simple { DummyResourcePtr a; ANKI_TEST_EXPECT_NO_ERR(resources->loadResource("blah", a)); } // Load a resource { DummyResourcePtr a; ANKI_TEST_EXPECT_NO_ERR(resources->loadResource("blah", a)); { DummyResourcePtr b = a; a = b; b = a; } } // Load and load again { DummyResourcePtr a; ANKI_TEST_EXPECT_NO_ERR(resources->loadResource("blah", a)); auto refcount = a->getRefcount().load(); DummyResourcePtr b; ANKI_TEST_EXPECT_NO_ERR(resources->loadResource("blah", b)); ANKI_TEST_EXPECT_EQ(b->getRefcount().load(), a->getRefcount().load()); ANKI_TEST_EXPECT_EQ(a->getRefcount().load(), refcount + 1); ANKI_TEST_EXPECT_EQ(b.get(), a.get()); // Again DummyResourcePtr c; ANKI_TEST_EXPECT_NO_ERR(resources->loadResource("blah", c)); ANKI_TEST_EXPECT_EQ(a->getRefcount().load(), refcount + 2); // Load something else DummyResourcePtr d; ANKI_TEST_EXPECT_NO_ERR(resources->loadResource("blih", d)); ANKI_TEST_EXPECT_EQ(a->getRefcount().load(), refcount + 2); } // Error { { DummyResourcePtr a; ANKI_TEST_EXPECT_EQ(resources->loadResource("error", a), ErrorCode::USER_DATA); } { DummyResourcePtr a; ANKI_TEST_EXPECT_EQ(resources->loadResource("error", a), ErrorCode::USER_DATA); } } // Delete alloc.deleteInstance(resources); }
ANKI_TEST(Util, DynamicArray) { { HeapAllocator<U8> alloc(allocAligned, nullptr); DynamicArrayAuto<DynamicArrayFoo> arr(alloc); arr.resize(0); arr.resize(2, 1); arr.resize(3, 2); arr.resize(4, 3); ANKI_TEST_EXPECT_EQ(arr.getSize(), 4); ANKI_TEST_EXPECT_EQ(arr[0].m_x, 1); ANKI_TEST_EXPECT_EQ(arr[1].m_x, 1); ANKI_TEST_EXPECT_EQ(arr[2].m_x, 2); ANKI_TEST_EXPECT_EQ(arr[3].m_x, 3); arr.emplaceBack(4); ANKI_TEST_EXPECT_EQ(arr.getSize(), 5); ANKI_TEST_EXPECT_EQ(arr[4].m_x, 4); arr.resize(1); arr.resize(0); } // Fuzzy { srand(time(nullptr)); HeapAllocator<U8> alloc(allocAligned, nullptr); DynamicArrayAuto<DynamicArrayFoo> arr(alloc); std::vector<DynamicArrayFoo> vec; const U ITERATIONS = 1000000; for(U i = 0; i < ITERATIONS; ++i) { const Bool grow = arr.getSize() > 0 && (rand() & 1); PtrSize newSize; U32 value = rand(); if(grow) { newSize = vec.size() * randRange(1.0, 4.0); } else { newSize = vec.size() * randRange(0.0, 0.9); } vec.resize(newSize, value); arr.resize(newSize, value); // Validate ANKI_TEST_EXPECT_EQ(arr.getSize(), vec.size()); for(U i = 0; i < arr.getSize(); ++i) { ANKI_TEST_EXPECT_EQ(arr[i].m_x, vec[i].m_x); } arr.validate(); } arr = DynamicArrayAuto<DynamicArrayFoo>(alloc); vec = std::vector<DynamicArrayFoo>(); ANKI_TEST_EXPECT_GT(destructorCount, 0); ANKI_TEST_EXPECT_EQ( constructor0Count + constructor1Count + constructor2Count + constructor3Count, destructorCount); } }
ANKI_TEST(Util, DynamicArrayEmplaceAt) { HeapAllocator<U8> alloc(allocAligned, nullptr); // Empty & add to the end { DynamicArrayAuto<DynamicArrayFoo> arr(alloc); arr.emplaceAt(arr.getEnd(), 12); ANKI_TEST_EXPECT_EQ(arr[0].m_x, 12); } // 1 element & add to he end { DynamicArrayAuto<DynamicArrayFoo> arr(alloc); arr.emplaceBack(12); arr.emplaceAt(arr.getEnd(), 34); ANKI_TEST_EXPECT_EQ(arr[0].m_x, 12); ANKI_TEST_EXPECT_EQ(arr[1].m_x, 34); } // 1 element & add to 0 { DynamicArrayAuto<DynamicArrayFoo> arr(alloc); arr.emplaceBack(12); arr.emplaceAt(arr.getBegin(), 34); ANKI_TEST_EXPECT_EQ(arr[0].m_x, 34); ANKI_TEST_EXPECT_EQ(arr[1].m_x, 12); } // A bit more complex { DynamicArrayAuto<DynamicArrayFoo> arr(alloc); for(U i = 0; i < 10; ++i) { arr.emplaceBack(i); } arr.emplaceAt(arr.getBegin() + 4, 666); for(I i = 0; i < 10 + 1; ++i) { if(i < 4) { ANKI_TEST_EXPECT_EQ(arr[i].m_x, i); } else if(i == 4) { ANKI_TEST_EXPECT_EQ(arr[i].m_x, 666); } else { ANKI_TEST_EXPECT_EQ(arr[i].m_x, i - 1); } } } // Fuzzy { srand(time(nullptr)); DynamicArrayAuto<DynamicArrayFoo> arr(alloc); std::vector<DynamicArrayFoo> vec; const I ITERATIONS = 10000; for(I i = 0; i < ITERATIONS; ++i) { I randNum = rand(); I op = rand() % 3; switch(op) { case 0: // Push back arr.emplaceBack(randNum); vec.emplace_back(randNum); break; case 1: // Insert somewhere if(!arr.isEmpty()) { I pos = rand() % arr.getSize(); arr.emplaceAt(arr.getBegin() + pos, randNum); vec.emplace(vec.begin() + pos, randNum); } break; default: // Insert at the end arr.emplaceAt(arr.getEnd(), randNum); vec.emplace(vec.end(), randNum); break; } } // Check ANKI_TEST_EXPECT_EQ(arr.getSize(), vec.size()); for(PtrSize i = 0; i < arr.getSize(); ++i) { ANKI_TEST_EXPECT_EQ(arr[i].m_x, vec[i].m_x); } arr.destroy(); vec.resize(0); ANKI_TEST_EXPECT_EQ( constructor0Count + constructor1Count + constructor2Count + constructor3Count, destructorCount); } }
//============================================================================== ANKI_TEST(Resource, AsyncLoader) { HeapAllocator<U8> alloc(allocAligned, nullptr); // Simple create destroy { AsyncLoader a; a.init(alloc); } // Simple task that will finish { AsyncLoader a; a.init(alloc); Barrier barrier(2); a.submitNewTask<Task>(0.0, &barrier, nullptr); barrier.wait(); } // Many tasks that will finish { AsyncLoader a; a.init(alloc); Barrier barrier(2); Atomic<U32> counter = {0}; const U COUNT = 100; for(U i = 0; i < COUNT; i++) { Barrier* pbarrier = nullptr; if(i == COUNT - 1) { pbarrier = &barrier; } a.submitNewTask<Task>(0.01, pbarrier, &counter); } barrier.wait(); ANKI_TEST_EXPECT_EQ(counter.load(), COUNT); } // Many tasks that will _not_ finish { AsyncLoader a; a.init(alloc); for(U i = 0; i < 100; i++) { a.submitNewTask<Task>(0.0, nullptr, nullptr); } } // Tasks that allocate { AsyncLoader a; a.init(alloc); Barrier barrier(2); for(U i = 0; i < 10; i++) { Barrier* pbarrier = nullptr; if(i == 9) { pbarrier = &barrier; } a.submitNewTask<MemTask>(alloc, pbarrier); } barrier.wait(); } // Tasks that allocate and never finished { AsyncLoader a; a.init(alloc); for(U i = 0; i < 10; i++) { a.submitNewTask<MemTask>(alloc, nullptr); } } // Pause/resume { AsyncLoader a; a.init(alloc); Atomic<U32> counter(0); Barrier barrier(2); // Check if the pause will sync a.submitNewTask<Task>(0.5, nullptr, &counter, 0); HighRezTimer::sleep(0.25); // Wait for the thread to pick the task... a.pause(); /// ...and then sync ANKI_TEST_EXPECT_EQ(counter.load(), 1); // Test resume a.submitNewTask<Task>(0.1, nullptr, &counter, 1); HighRezTimer::sleep(1.0); ANKI_TEST_EXPECT_EQ(counter.load(), 1); a.resume(); // Sync a.submitNewTask<Task>(0.1, &barrier, &counter, 2); barrier.wait(); ANKI_TEST_EXPECT_EQ(counter.load(), 3); } // Pause/resume { AsyncLoader a; a.init(alloc); Atomic<U32> counter(0); Barrier barrier(2); // Check task resubmit a.submitNewTask<Task>(0.0, &barrier, &counter, -1, false, true); barrier.wait(); barrier.wait(); ANKI_TEST_EXPECT_EQ(counter.load(), 2); // Check task pause a.submitNewTask<Task>(0.0, nullptr, &counter, -1, true, false); a.submitNewTask<Task>(0.0, nullptr, &counter, -1, false, false); HighRezTimer::sleep(1.0); ANKI_TEST_EXPECT_EQ(counter.load(), 3); a.resume(); HighRezTimer::sleep(1.0); ANKI_TEST_EXPECT_EQ(counter.load(), 4); // Check both counter.set(0); a.submitNewTask<Task>(0.0, nullptr, &counter, 0, false, false); a.submitNewTask<Task>(0.0, nullptr, &counter, -1, true, true); a.submitNewTask<Task>(0.0, nullptr, &counter, 2, false, false); HighRezTimer::sleep(1.0); ANKI_TEST_EXPECT_EQ(counter.load(), 2); a.resume(); HighRezTimer::sleep(1.0); ANKI_TEST_EXPECT_EQ(counter.load(), 4); } // Fuzzy test { AsyncLoader a; a.init(alloc); Barrier barrier(2); Atomic<U32> counter = {0}; for(U i = 0; i < 10; i++) { Barrier* pbarrier = nullptr; if(i == 9) { pbarrier = &barrier; } a.submitNewTask<Task>(randRange(0.0, 0.5), pbarrier, &counter, i); } barrier.wait(); ANKI_TEST_EXPECT_EQ(counter.load(), 10); } }
ANKI_TEST(Util, String) { HeapAllocator<U8> alloc(allocAligned, nullptr); // Copy { String a, b; a.create(alloc, "123"); b.create(alloc, a); ANKI_TEST_EXPECT_EQ(a, b); ANKI_TEST_EXPECT_EQ(b, "123"); b.destroy(alloc); a.destroy(alloc); b.create(alloc, "321"); a.create(alloc, b); ANKI_TEST_EXPECT_EQ(a, b); ANKI_TEST_EXPECT_EQ(a, "321"); b.destroy(alloc); a.destroy(alloc); } // Move { String a; a.create(alloc, "123"); String b(std::move(a)); ANKI_TEST_EXPECT_EQ(a.isEmpty(), true); ANKI_TEST_EXPECT_EQ(b, "123"); b.destroy(alloc); b.create(alloc, "321"); a = std::move(b); ANKI_TEST_EXPECT_EQ(a, "321"); ANKI_TEST_EXPECT_EQ(b.isEmpty(), true); a.destroy(alloc); } // Accessors { const char* s = "123"; String a; a.create(alloc, s); ANKI_TEST_EXPECT_EQ(a[0], '1'); ANKI_TEST_EXPECT_EQ(a[1], '2'); ANKI_TEST_EXPECT_EQ(a[2], '3'); U count = 0; for(char& c : a) { ++c; ++count; } ANKI_TEST_EXPECT_EQ(a, "234"); ANKI_TEST_EXPECT_EQ(count, 3); ANKI_TEST_EXPECT_EQ(a.begin(), &a[0]); ANKI_TEST_EXPECT_EQ(a.end(), &a[0] + 3); a.destroy(alloc); } // Append { String a, b; b.create(alloc, "123"); a.append(alloc, b); ANKI_TEST_EXPECT_EQ(a, "123"); a.append(alloc, "456789"); a.append(alloc, String()); a.append(alloc, ""); a.append(alloc, "0"); ANKI_TEST_EXPECT_EQ(a, "1234567890"); a.destroy(alloc); b.destroy(alloc); } // Compare { #define COMPARE(x_, y_, op_) \ a.append(alloc, x_); \ b.append(alloc, y_); \ ANKI_TEST_EXPECT_EQ(a op_ b, std::string(x_) op_ std::string(y_)) \ a.destroy(alloc); \ b.destroy(alloc); String a, b; COMPARE("123", "1233", <); COMPARE("0123", "1233", <=); COMPARE("ASDFA", "asdf90f", >); COMPARE(" %^*^^&", "aslkdfjb", >=); #undef COMPARE } // sprintf { String a; // Simple a.sprintf(alloc, "12%c %d", '3', 123); ANKI_TEST_EXPECT_EQ(a, "123 123"); a.destroy(alloc); // Extreme const char* s = "1234567890ABCDEF!@#$%^&*()_+asfghjkl:,.;ljk\"><{}[]/"; a.sprintf(alloc, "%s%s%s%s%s%s%s%s%s%s%s %d", s, s, s, s, s, s, s, s, s, s, s, 88); String b; for(U i = 0; i < 11; i++) { b.append(alloc, s); } b.append(alloc, " 88"); ANKI_TEST_EXPECT_EQ(a, b); ANKI_TEST_EXPECT_EQ(a.getLength(), b.getLength()); a.destroy(alloc); b.destroy(alloc); } // sprintf #2: Smaller result (will trigger another path) { String a; // Simple a.sprintf(alloc, "12%c %d", '3', 123); ANKI_TEST_EXPECT_EQ(a, "123 123"); a.destroy(alloc); // Extreme const char* s = "12345"; a.sprintf(alloc, "%s%s %d", s, s, 88); String b; for(U i = 0; i < 2; i++) { b.append(alloc, s); } b.append(alloc, " 88"); ANKI_TEST_EXPECT_EQ(a, b); ANKI_TEST_EXPECT_EQ(a.getLength(), b.getLength()); a.destroy(alloc); b.destroy(alloc); } // Other create { String a; a.create(alloc, '1', 3); ANKI_TEST_EXPECT_EQ(a, "111"); ANKI_TEST_EXPECT_EQ(a.getLength(), 3); a.destroy(alloc); } // toString { String a; a.toString(alloc, 123); ANKI_TEST_EXPECT_EQ(a, "123"); a.destroy(alloc); a.toString(alloc, 123.123); ANKI_TEST_EXPECT_EQ(a, "123.123000"); a.destroy(alloc); } // To number { I64 i; String a; a.create(alloc, "123456789"); ANKI_TEST_EXPECT_NO_ERR(a.toI64(i)); ANKI_TEST_EXPECT_EQ(i, 123456789); a.destroy(alloc); a.create(alloc, "-9223372036854775807"); ANKI_TEST_EXPECT_NO_ERR(a.toI64(i)); ANKI_TEST_EXPECT_EQ(i, -9223372036854775807); a.destroy(alloc); F64 f; a.create(alloc, "123456789.145"); ANKI_TEST_EXPECT_NO_ERR(a.toF64(f)); ANKI_TEST_EXPECT_EQ(f, 123456789.145); a.destroy(alloc); } }
ANKI_TEST(Util, StackAllocator) { Foo::reset(); // With simple string { StackAllocator<char> alloc(allocAligned, nullptr, 128); using Str = std::basic_string<char, std::char_traits<char>, StackAllocator<char>>; Str str(alloc); str = "lalala"; str = "lalalalo"; } // With vector { using All = StackAllocator<Foo>; All alloc(allocAligned, nullptr, (sizeof(Foo) + 1) * 10, alignof(Foo)); std::vector<Foo, All> vec(alloc); vec.reserve(10); U sumi = 0; for(U i = 0; i < 10; i++) { std::cout << "pushing" << std::endl; vec.push_back(Foo(10 * i)); sumi += 10 * i; } U sum = 0; for(const Foo& foo : vec) { sum += foo.x; } ANKI_TEST_EXPECT_EQ(sum, sumi); } // Copy around { typedef StackAllocator<Foo> Alloc; Alloc a(allocAligned, nullptr, (sizeof(Foo) + 1) * 10, alignof(Foo)); Alloc b(allocAligned, nullptr, (sizeof(Foo) + 1) * 10, alignof(Foo)); a = b; ANKI_TEST_EXPECT_EQ(a.getMemoryPool().getUsersCount(), 2); b = a; ANKI_TEST_EXPECT_EQ(&a.getMemoryPool(), &b.getMemoryPool()); ANKI_TEST_EXPECT_EQ(a.getMemoryPool().getUsersCount(), 2); } ANKI_TEST_EXPECT_EQ(Foo::constructorCallCount, Foo::destructorCallCount); // End Foo::reset(); }
ANKI_TEST(Util, List) { HeapAllocator<U8> alloc(allocAligned, nullptr); // Simple { List<Foo> a; Error err = ErrorCode::NONE; a.emplaceBack(alloc, 10); a.emplaceBack(alloc, 11); U sum = 0; err = a.iterateForward([&](const Foo& f) -> Error { sum += f.x; return ErrorCode::NONE; }); ANKI_TEST_EXPECT_EQ(err, ErrorCode::NONE); ANKI_TEST_EXPECT_EQ(sum, 21); a.destroy(alloc); } // Sort { List<I> a; Error err = ErrorCode::NONE; a.emplaceBack(alloc, 10); a.emplaceBack(alloc, 9); a.emplaceBack(alloc, 11); a.emplaceBack(alloc, 2); a.sort(); Array<I, 4> arr = {{2, 9, 10, 11}}; U u = 0; err = a.iterateForward([&](const I& i) -> Error { if(arr[u++] == i) { return ErrorCode::NONE; } else { return ErrorCode::UNKNOWN; } }); ANKI_TEST_EXPECT_EQ(err, ErrorCode::NONE); a.sort([](I& a, I& b) -> Bool { return a > b; }); Array<I, 4> arr2 = {{11, 10, 9, 2}}; u = 0; err = a.iterateForward([&](const I& i) -> Error { if(arr2[u++] == i) { return ErrorCode::NONE; } else { return ErrorCode::UNKNOWN; } }); ANKI_TEST_EXPECT_EQ(err, ErrorCode::NONE); a.destroy(alloc); } // Extreme sort { const U COUNT = 10000; List<Foo> a; std::list<Foo> b; for(U i = 0; i < COUNT; i++) { I randVal = rand(); Foo f(randVal); a.pushBack(alloc, f); b.push_back(f); } //auto ta = HighRezTimer::getCurrentTime(); b.sort([](const Foo& a, const Foo& b){return a.x < b.x;}); //auto tb = HighRezTimer::getCurrentTime(); a.sort([](const Foo& a, const Foo& b){return a.x < b.x;}); //auto tc = HighRezTimer::getCurrentTime(); //printf("%f %f\n", tb - ta, tc - tb); auto ait = a.getBegin(); auto bit = b.begin(); auto aend = a.getEnd(); auto bend = b.end(); while(ait != aend && bit != bend) { const Foo& afoo = *ait; const Foo& bfoo = *bit; ANKI_TEST_EXPECT_EQ(afoo, bfoo); ++ait; ++bit; } ANKI_TEST_EXPECT_EQ(ait, aend); ANKI_TEST_EXPECT_EQ(bit, bend); a.destroy(alloc); } // Iterate { List<I> a; Error err = ErrorCode::NONE; a.emplaceBack(alloc, 10); a.emplaceBack(alloc, 9); a.emplaceBack(alloc, 11); a.emplaceBack(alloc, 2); Array<I, 4> arr = {{10, 9, 11, 2}}; U count = 0; // Forward List<I>::ConstIterator it = a.getBegin(); for(; it != a.getEnd() && !err; ++it) { if(*it != arr[count++]) { err = ErrorCode::UNKNOWN; } } ANKI_TEST_EXPECT_EQ(err, ErrorCode::NONE); // Backwards --it; for(; it != a.getBegin() && !err; --it) { if(*it != arr[--count]) { err = ErrorCode::UNKNOWN; } } ANKI_TEST_EXPECT_EQ(err, ErrorCode::NONE); a.destroy(alloc); } // Erase { List<I> a; a.emplaceBack(alloc, 10); a.erase(alloc, a.getBegin()); ANKI_TEST_EXPECT_EQ(a.isEmpty(), true); a.emplaceBack(alloc, 10); a.emplaceBack(alloc, 20); a.erase(alloc, a.getBegin() + 1); ANKI_TEST_EXPECT_EQ(10, *a.getBegin()); a.emplaceFront(alloc, 5); a.emplaceBack(alloc, 30); ANKI_TEST_EXPECT_EQ(5, *(a.getBegin())); ANKI_TEST_EXPECT_EQ(10, *(a.getEnd() - 2)); ANKI_TEST_EXPECT_EQ(30, *(a.getEnd() - 1)); a.erase(alloc, a.getEnd() - 2); ANKI_TEST_EXPECT_EQ(5, *(a.getBegin())); ANKI_TEST_EXPECT_EQ(30, *(a.getEnd() - 1)); a.erase(alloc, a.getBegin()); a.erase(alloc, a.getBegin()); } }