///////////////////////////////////////////////////////////////////////////// // Copyright (c) Electronic Arts Inc. All rights reserved. ///////////////////////////////////////////////////////////////////////////// #include #include #include "EASTLTest.h" #include #include #include #include #include #include EA_DISABLE_ALL_VC_WARNINGS() #include EA_RESTORE_ALL_VC_WARNINGS() namespace { // Used for eastl::function tests static int TestIntRet(int* p) { int ret = *p; *p += 1; return ret; } // Used for str_less tests below. template struct Results { const T* p1; const T* p2; bool expectedResult; // The expected result of the expression (p1 < p2) }; // Used for const_mem_fun_t below. struct X { X() { } void DoNothing() const { } }; template void foo(typename T::argument_type arg) { typename T::result_type (T::*pFunction)(typename T::argument_type) const = &T::operator(); T t(&X::DoNothing); (t.*pFunction)(arg); } // Used for equal_to_2 tests below. struct N1{ N1(int x) : mX(x) { } int mX; }; struct N2{ N2(int x) : mX(x) { } int mX; }; bool operator==(const N1& n1, const N1& n1a){ return (n1.mX == n1a.mX); } bool operator==(const N1& n1, const N2& n2) { return (n1.mX == n2.mX); } bool operator==(const N2& n2, const N1& n1) { return (n2.mX == n1.mX); } bool operator!=(const N1& n1, const N1& n1a){ return (n1.mX != n1a.mX); } bool operator!=(const N1& n1, const N2& n2) { return (n1.mX != n2.mX); } bool operator!=(const N2& n2, const N1& n1) { return (n2.mX != n1.mX); } bool operator< (const N1& n1, const N1& n1a){ return (n1.mX < n1a.mX); } bool operator< (const N1& n1, const N2& n2) { return (n1.mX < n2.mX); } bool operator< (const N2& n2, const N1& n1) { return (n2.mX < n1.mX); } // Used for mem_fun tests below. struct TestClass { mutable int mX; TestClass() : mX(37) { } void Increment() { mX++; } void IncrementConst() const { mX++; } int MultiplyBy(int x) { return mX * x; } int MultiplyByConst(int x) const { return mX * x; } }; } // Template instantations. // These tell the compiler to compile all the functions for the given class. typedef eastl::basic_string String8MA; typedef eastl::basic_string String16MA; template struct eastl::string_hash; template struct eastl::string_hash; template class eastl::hash_set >; template class eastl::hash_set >; // Helper function for testing our default hash implementations for pod types which // simply returns the static_cast of the val passed in template int TestHashHelper(T val) { int nErrorCount = 0; EATEST_VERIFY(eastl::hash()(val) == static_cast(val)); return nErrorCount; } /////////////////////////////////////////////////////////////////////////////// // TestFunctional // int TestFunctional() { using namespace eastl; int nErrorCount = 0; { // str_equal_to char p0[] = ""; char p1[] = "hello"; char p2[] = "world"; char p3[] = "helllllo"; char p4[] = "hello"; // Intentionally the same value as p1. // str_equal_to typedef hash_set, str_equal_to > StringHashSet; StringHashSet shs; shs.insert(p1); shs.insert(p2); shs.insert(p3); StringHashSet::iterator it = shs.find(p0); EATEST_VERIFY(it == shs.end()); it = shs.find(p1); EATEST_VERIFY(it != shs.end()); it = shs.find(p2); EATEST_VERIFY(it != shs.end()); it = shs.find(p4); EATEST_VERIFY(it != shs.end()); } { // str_less Results results8[] = { { "", "", false }, { "", "a", true }, { "a", "", false }, { "a", "a", false }, { "a", "b", true }, { "____a", "____a", false }, { "____a", "____b", true }, { "____b", "____a", false }, { "_\xff", "_a", false }, // Test high values, which exercises the signed/unsiged comparison behavior. { "_a", "_\xff", true } }; str_less sl8; for(size_t i = 0; i < EAArrayCount(results8); i++) { // Verify that our test is in line with the strcmp function. bool bResult = (EA::StdC::Strcmp(results8[i].p1, results8[i].p2) < 0); EATEST_VERIFY_F(bResult == results8[i].expectedResult, "Strcmp failure, test %zu. Expected \"%s\" to be %sless than \"%s\"", i, results8[i].p1, results8[i].expectedResult ? "" : "not ", results8[i].p2); // Verify that str_less achieves the expected results. bResult = sl8(results8[i].p1, results8[i].p2); EATEST_VERIFY_F(bResult == results8[i].expectedResult, "str_less test failure, test %zu. Expected \"%s\" to be %sless than \"%s\"", i, results8[i].p1, results8[i].expectedResult ? "" : "not ", results8[i].p2); } // str_less Results resultsW[] = { { L"", L"", false }, { L"", L"a", true }, { L"a", L"", false }, { L"a", L"a", false }, { L"a", L"b", true }, { L"____a", L"____a", false }, { L"____a", L"____b", true }, { L"____b", L"____a", false }, { L"_\xffff", L"_a", false }, // Test high values, which exercises the signed/unsiged comparison behavior. { L"_a", L"_\xffff", true } }; str_less slW; for(size_t i = 0; i < EAArrayCount(resultsW); i++) { // Verify that our test is in line with the strcmp function. bool bResult = (EA::StdC::Strcmp(resultsW[i].p1, resultsW[i].p2) < 0); EATEST_VERIFY_F(bResult == resultsW[i].expectedResult, "Strcmp failure, test %zu. Expected \"%s\" to be %sless than \"%s\"", i, results8[i].p1, results8[i].expectedResult ? "" : "not ", results8[i].p2); // Verify that str_less achieves the expected results. bResult = slW(resultsW[i].p1, resultsW[i].p2); EATEST_VERIFY_F(bResult == resultsW[i].expectedResult, "str_less test failure, test %zu. Expected \"%ls\" to be %sless than \"%ls\"", i, resultsW[i].p1, resultsW[i].expectedResult ? "" : "not ", resultsW[i].p2); } } { // str_less char p0[] = ""; char p1[] = "hello"; char p2[] = "world"; char p3[] = "helllllo"; char p4[] = "hello"; // Intentionally the same value as p1. typedef set > StringSet; StringSet ss; ss.insert(p1); ss.insert(p2); ss.insert(p3); StringSet::iterator it = ss.find(p0); EATEST_VERIFY(it == ss.end()); it = ss.find(p1); EATEST_VERIFY(it != ss.end()); it = ss.find(p2); EATEST_VERIFY(it != ss.end()); it = ss.find(p4); EATEST_VERIFY(it != ss.end()); } { // equal_to_2 N1 n11(1); N1 n13(3); N2 n21(1); N2 n22(2); //const N1 cn11(1); //const N1 cn13(3); equal_to_2 e; EATEST_VERIFY(e(n11, n21)); EATEST_VERIFY(e(n21, n11)); equal_to_2 es; EATEST_VERIFY(es(n11, n11)); //equal_to_2 ec; // To do: Make this case work. //EATEST_VERIFY(e(cn11, n11)); // not_equal_to_2 not_equal_to_2 n; EATEST_VERIFY(n(n11, n22)); EATEST_VERIFY(n(n22, n11)); not_equal_to_2 ns; EATEST_VERIFY(ns(n11, n13)); // less_2 less_2 le; EATEST_VERIFY(le(n11, n22)); EATEST_VERIFY(le(n22, n13)); less_2 les; EATEST_VERIFY(les(n11, n13)); } { // Test defect report entry #297. const X x; foo< const_mem_fun_t >(&x); } { // mem_fun (no argument version) TestClass tc0, tc1, tc2; TestClass* tcArray[3] = { &tc0, &tc1, &tc2 }; for_each(tcArray, tcArray + 3, mem_fun(&TestClass::Increment)); EATEST_VERIFY((tc0.mX == 38) && (tc1.mX == 38) && (tc2.mX == 38)); for_each(tcArray, tcArray + 3, mem_fun(&TestClass::IncrementConst)); EATEST_VERIFY((tc0.mX == 39) && (tc1.mX == 39) && (tc2.mX == 39)); } { // mem_fun (one argument version) TestClass tc0, tc1, tc2; TestClass* tcArray[3] = { &tc0, &tc1, &tc2 }; int intArray1[3] = { -1, 0, 2 }; int intArray2[3] = { -9, -9, -9 }; transform(tcArray, tcArray + 3, intArray1, intArray2, mem_fun(&TestClass::MultiplyBy)); EATEST_VERIFY((intArray2[0] == -37) && (intArray2[1] == 0) && (intArray2[2] == 74)); intArray2[0] = intArray2[1] = intArray2[2] = -9; transform(tcArray, tcArray + 3, intArray1, intArray2, mem_fun(&TestClass::MultiplyByConst)); EATEST_VERIFY((intArray2[0] == -37) && (intArray2[1] == 0) && (intArray2[2] == 74)); } { // mem_fun_ref (no argument version) TestClass tcArray[3]; for_each(tcArray, tcArray + 3, mem_fun_ref(&TestClass::Increment)); EATEST_VERIFY((tcArray[0].mX == 38) && (tcArray[1].mX == 38) && (tcArray[2].mX == 38)); for_each(tcArray, tcArray + 3, mem_fun_ref(&TestClass::IncrementConst)); EATEST_VERIFY((tcArray[0].mX == 39) && (tcArray[1].mX == 39) && (tcArray[2].mX == 39)); } { // mem_fun_ref (one argument version) TestClass tcArray[3]; int intArray1[3] = { -1, 0, 2 }; int intArray2[3] = { -9, -9, -9 }; transform(tcArray, tcArray + 3, intArray1, intArray2, mem_fun_ref(&TestClass::MultiplyBy)); EATEST_VERIFY((intArray2[0] == -37) && (intArray2[1] == 0) && (intArray2[2] == 74)); intArray2[0] = intArray2[1] = intArray2[2] = -9; transform(tcArray, tcArray + 3, intArray1, intArray2, mem_fun_ref(&TestClass::MultiplyByConst)); EATEST_VERIFY((intArray2[0] == -37) && (intArray2[1] == 0) && (intArray2[2] == 74)); } { // Template instantations. // These tell the compiler to compile all the functions for the given class. eastl::hash_set > hs8; eastl::hash_set > hs16; EATEST_VERIFY(hs8.empty()); EATEST_VERIFY(hs16.empty()); } { // unary_compose /* eastl::vector angles; eastl::vector sines; eastl::transform(angles.begin(), angles.end(), sines.begin(), eastl::compose1(eastl::negate(), eastl::compose1(eastl::ptr_fun(sin), eastl::bind2nd(eastl::multiplies(), 3.14159 / 180.0)))); */ // binary_compose list L; eastl::list::iterator in_range = eastl::find_if(L.begin(), L.end(), eastl::compose2(eastl::logical_and(), eastl::bind2nd(eastl::greater_equal(), 1), eastl::bind2nd(eastl::less_equal(), 10))); EATEST_VERIFY(in_range == L.end()); } { nErrorCount += TestHashHelper(4330); nErrorCount += TestHashHelper(true); nErrorCount += TestHashHelper('E'); nErrorCount += TestHashHelper('E'); nErrorCount += TestHashHelper('E'); nErrorCount += TestHashHelper('E'); nErrorCount += TestHashHelper(0xEAEA); nErrorCount += TestHashHelper(0x00EA4330); #if !defined(EA_WCHAR_T_NON_NATIVE) nErrorCount += TestHashHelper(L'E'); #endif nErrorCount += TestHashHelper(4330); nErrorCount += TestHashHelper(4330u); nErrorCount += TestHashHelper(4330); nErrorCount += TestHashHelper(4330u); nErrorCount += TestHashHelper(4330l); nErrorCount += TestHashHelper(4330ul); nErrorCount += TestHashHelper(4330ll); nErrorCount += TestHashHelper(4330ll); nErrorCount += TestHashHelper(4330.099999f); nErrorCount += TestHashHelper(4330.055); nErrorCount += TestHashHelper(4330.0654l); { enum hash_enum_test { e1, e2, e3 }; nErrorCount += TestHashHelper(e1); nErrorCount += TestHashHelper(e2); nErrorCount += TestHashHelper(e3); } } #if defined(EA_COMPILER_CPP11_ENABLED) && EASTL_VARIADIC_TEMPLATES_ENABLED // On platforms do not support variadic templates the eastl::invoke (eastl::mem_fn is built on eastl::invoke) // implementation is extremely basic and does not hold up. A significant amount of code would have to be written // and I don't believe the investment is justified at this point. If you require this functionality on older // compilers please contact us. // // eastl::invoke { struct TestStruct { TestStruct(int inValue) : value(inValue) {} void Add(int addAmount) { value += addAmount; } int GetValue() { return value; } int& GetValueReference() { return value; } int value; }; struct TestFunctor { void operator()() { called = true; } bool called = false; }; struct TestFunctorArguments { void operator()(int i) { value = i; } int value = 0; }; { TestStruct a(42); eastl::invoke(&TestStruct::Add, a, 10); EATEST_VERIFY(a.value == 52); static_assert(eastl::is_same::type, void>::value, "incorrect type for invoke_result"); static_assert(eastl::is_invocable::value, "incorrect value for is_invocable"); } { TestStruct a(42); eastl::invoke(&TestStruct::Add, &a, 10); EATEST_VERIFY(a.value == 52); static_assert(eastl::is_same::type, void>::value, "incorrect type for invoke_result"); static_assert(eastl::is_invocable::value, "incorrect value for is_invocable"); } { TestStruct a(42); eastl::reference_wrapper r(a); eastl::invoke(&TestStruct::Add, r, 10); EATEST_VERIFY(a.value == 52); static_assert(eastl::is_same, int>::type, void>::value, "incorrect type for invoke_result"); static_assert(eastl::is_invocable, int>::value, "incorrect value for is_invocable"); } { TestStruct a(42); eastl::invoke(&TestStruct::GetValueReference, a) = 43; EATEST_VERIFY(a.value == 43); static_assert(eastl::is_same::type, int &>::value, "incorrect type for invoke_result"); static_assert(eastl::is_invocable::value, "incorrect value for is_invocable"); } { TestStruct a(42); EATEST_VERIFY(eastl::invoke(&TestStruct::value, a) == 42); static_assert(eastl::is_same::type, int &>::value, "incorrect type for invoke_result"); static_assert(eastl::is_invocable::value, "incorrect value for is_invocable"); } { TestStruct a(42); eastl::invoke(&TestStruct::value, a) = 43; EATEST_VERIFY(a.value == 43); static_assert(eastl::is_same::type, int &>::value, "incorrect type for invoke_result"); static_assert(eastl::is_invocable::value, "incorrect value for is_invocable"); } { TestStruct a(42); eastl::invoke(&TestStruct::value, &a) = 43; EATEST_VERIFY(a.value == 43); static_assert(eastl::is_same::type, int &>::value, "incorrect type for invoke_result"); static_assert(eastl::is_invocable::value, "incorrect value for is_invocable"); } { TestStruct a(42); eastl::reference_wrapper r(a); eastl::invoke(&TestStruct::value, r) = 43; EATEST_VERIFY(a.value == 43); static_assert(eastl::is_same>::type, int &>::value, "incorrect type for invoke_result"); static_assert(eastl::is_invocable>::value, "incorrect value for is_invocable"); } #ifndef EA_COMPILER_GNUC { TestStruct a(42); EATEST_VERIFY(eastl::invoke(&TestStruct::GetValue, a) == 42); static_assert( eastl::is_same::type, int>::value, "incorrect type for invoke_result"); static_assert(eastl::is_invocable::value, "incorrect value for is_invocable"); } #endif { TestFunctor f; eastl::invoke(f); EATEST_VERIFY(f.called); static_assert(eastl::is_same::type, void>::value, "incorrect type for invoke_result"); static_assert(eastl::is_invocable::value, "incorrect value for is_invocable"); } { TestFunctorArguments f; eastl::invoke(f, 42); EATEST_VERIFY(f.value == 42); static_assert(eastl::is_same::type, void>::value, "incorrect type for invoke_result"); static_assert(eastl::is_invocable::value, "incorrect value for is_invocable"); } { static bool called = false; auto f = [] {called = true;}; eastl::invoke(f); EATEST_VERIFY(called); static_assert(eastl::is_same::type, void>::value, "incorrect type for invoke_result"); static_assert(eastl::is_invocable::value, "incorrect value for is_invocable"); } { static int value = 0; auto f = [](int i) {value = i;}; eastl::invoke(f, 42); EATEST_VERIFY(value == 42); static_assert(eastl::is_same::type, void>::value, "incorrect type for invoke_result"); static_assert(eastl::is_invocable::value, "incorrect value for is_invocable"); } { struct A {}; struct B : public A {}; struct TestStruct { A a() { return A(); }; B b() { return B(); }; }; static_assert(!eastl::is_invocable_r::value, "incorrect value for is_invocable_r"); static_assert(eastl::is_invocable_r::value, "incorrect value for is_invocable_r"); static_assert(eastl::is_invocable_r::value, "incorrect value for is_invocable_r"); } } // eastl::mem_fn { struct AddingStruct { AddingStruct(int inValue) : value(inValue) {} void Add(int addAmount) { value += addAmount; } void Add2(int add1, int add2) { value += (add1 + add2); } int value; }; struct OverloadedStruct { OverloadedStruct(int inValue) : value(inValue) {} int &Value() { return value; } const int &Value() const { return value; } int value; }; { AddingStruct a(42); eastl::mem_fn(&AddingStruct::Add)(a, 6); EATEST_VERIFY(a.value == 48); } { AddingStruct a(42); eastl::mem_fn(&AddingStruct::Add2)(a, 3, 3); EATEST_VERIFY(a.value == 48); } { AddingStruct a(42); auto fStructAdd = eastl::mem_fn(&AddingStruct::Add); fStructAdd(a,6); EATEST_VERIFY(a.value == 48); } { OverloadedStruct a(42); EATEST_VERIFY(eastl::mem_fn(&OverloadedStruct::Value)(a) == 42); EATEST_VERIFY(eastl::mem_fn(&OverloadedStruct::Value)(a) == 42); } } #endif // eastl::function { { { struct Functor { int operator()() { return 42; } }; eastl::function fn = Functor(); EATEST_VERIFY(fn() == 42); } { struct Functor { int operator()(int in) { return in; } }; eastl::function fn = Functor(); EATEST_VERIFY(fn(24) == 24); } } { int val = 0; auto lambda = [&val] { ++val; }; { eastl::function ff = std::bind(lambda); ff(); VERIFY(val == 1); } { eastl::function ff = nullptr; ff = std::bind(lambda); ff(); VERIFY(val == 2); } } { int val = 0; { eastl::function ff = &TestIntRet; int ret = ff(&val); EATEST_VERIFY(ret == 0); EATEST_VERIFY(val == 1); } { eastl::function ff; ff = &TestIntRet; int ret = ff(&val); EATEST_VERIFY(ret == 1); EATEST_VERIFY(val == 2); } } { struct Test { int x = 1; }; Test t; const Test ct; { eastl::function ff = &Test::x; int ret = ff(t); EATEST_VERIFY(ret == 1); } { eastl::function ff = &Test::x; int ret = ff(ct); EATEST_VERIFY(ret == 1); } { eastl::function ff; ff = &Test::x; int ret = ff(t); EATEST_VERIFY(ret == 1); } { eastl::function ff; ff = &Test::x; int ret = ff(ct); EATEST_VERIFY(ret == 1); } } { struct TestVoidRet { void IncX() const { ++x; } void IncX() { ++x; } mutable int x = 0; }; TestVoidRet voidRet; const TestVoidRet cvoidRet; { eastl::function ff = static_cast(&TestVoidRet::IncX); ff(cvoidRet); VERIFY(cvoidRet.x == 1); } { eastl::function ff = static_cast(&TestVoidRet::IncX); ff(voidRet); VERIFY(voidRet.x == 1); } { eastl::function ff = static_cast(&TestVoidRet::IncX); ff(voidRet); VERIFY(voidRet.x == 2); } } { int val = 0; struct Functor { void operator()(int* p) { *p += 1; } }; Functor functor; { eastl::function ff = eastl::reference_wrapper(functor); ff(&val); EATEST_VERIFY(val == 1); } { eastl::function ff; ff = eastl::reference_wrapper(functor); ff(&val); EATEST_VERIFY(val == 2); } } { { auto lambda = []{}; EA_UNUSED(lambda); static_assert(internal::is_functor_inplace_allocatable::value == true, "lambda equivalent to function pointer does not fit in eastl::function local memory."); } { eastl::function fn; EATEST_VERIFY(!fn); fn = [] {}; EATEST_VERIFY(!!fn); } { eastl::function fn = [](int param) { return param; }; EATEST_VERIFY(fn(42) == 42); } { eastl::function fn = ReturnVal; EATEST_VERIFY(fn(42) == 42); } { eastl::function fn0 = ReturnZero; eastl::function fn1 = ReturnOne; EATEST_VERIFY(fn0() == 0 && fn1() == 1); swap(fn0, fn1); EATEST_VERIFY(fn0() == 1 && fn1() == 0); } { eastl::function fn0 = ReturnZero; eastl::function fn1 = ReturnOne; EATEST_VERIFY(fn0() == 0 && fn1() == 1); fn0 = fn1; EATEST_VERIFY(fn0() == 1 && fn1() == 1); } { eastl::function fn0 = ReturnZero; eastl::function fn1 = ReturnOne; EATEST_VERIFY(fn0() == 0 && fn1() == 1); fn0 = eastl::move(fn1); EATEST_VERIFY(fn0() == 1 && fn1 == nullptr); } { eastl::function f1(nullptr); EATEST_VERIFY(!f1); eastl::function f2 = nullptr; EATEST_VERIFY(!f2); } } { // test the default allocator path by using a lambda capture too large to fit into the eastl::function local // storage. uint64_t a = 1, b = 2, c = 3, d = 4, e = 5, f = 6; eastl::function fn = [=] { return a + b + c + d + e + f; }; auto result = fn(); EATEST_VERIFY(result == 21); } { struct Functor { void operator()() { return; } }; eastl::function fn; eastl::function fn2 = nullptr; EATEST_VERIFY(!fn); EATEST_VERIFY(!fn2); EATEST_VERIFY(fn == nullptr); EATEST_VERIFY(fn2 == nullptr); EATEST_VERIFY(nullptr == fn); EATEST_VERIFY(nullptr == fn2); fn = Functor(); fn2 = Functor(); EATEST_VERIFY(!!fn); EATEST_VERIFY(!!fn2); EATEST_VERIFY(fn != nullptr); EATEST_VERIFY(fn2 != nullptr); EATEST_VERIFY(nullptr != fn); EATEST_VERIFY(nullptr != fn2); fn = nullptr; fn2 = fn; EATEST_VERIFY(!fn); EATEST_VERIFY(!fn2); EATEST_VERIFY(fn == nullptr); EATEST_VERIFY(fn2 == nullptr); EATEST_VERIFY(nullptr == fn); EATEST_VERIFY(nullptr == fn2); } { using eastl::swap; struct Functor { int operator()() { return 5; } }; eastl::function fn = Functor(); eastl::function fn2; EATEST_VERIFY(fn() == 5); EATEST_VERIFY(!fn2); fn.swap(fn2); EATEST_VERIFY(!fn); EATEST_VERIFY(fn2() == 5); swap(fn, fn2); EATEST_VERIFY(fn() == 5); EATEST_VERIFY(!fn2); } { uint64_t a = 1, b = 2, c = 3, d = 4, e = 5, f = 6; eastl::function fn([=] { return a + b + c + d + e + f; }); auto result = fn(); EATEST_VERIFY(result == 21); } // user regression "self assigment" tests { eastl::function fn = [cache = 0] () mutable { return cache++; }; EATEST_VERIFY(fn() == 0); EATEST_VERIFY(fn() == 1); EATEST_VERIFY(fn() == 2); EA_DISABLE_CLANG_WARNING(-Wunknown-pragmas) EA_DISABLE_CLANG_WARNING(-Wunknown-warning-option) EA_DISABLE_CLANG_WARNING(-Wself-assign-overloaded) fn = fn; EA_RESTORE_CLANG_WARNING() EA_RESTORE_CLANG_WARNING() EA_RESTORE_CLANG_WARNING() EATEST_VERIFY(fn() == 3); EATEST_VERIFY(fn() == 4); EATEST_VERIFY(fn() == 5); fn = eastl::move(fn); EATEST_VERIFY(fn() == 6); EATEST_VERIFY(fn() == 7); EATEST_VERIFY(fn() == 8); } // user regression for memory leak when re-assigning an eastl::function which already holds a large closure. { static int sCtorCount = 0; static int sDtorCount = 0; { struct local { local() { sCtorCount++; } local(const local&) { sCtorCount++; } local(local&&) { sCtorCount++; } ~local() { sDtorCount++; } void operator=(const local&) = delete; // suppress msvc warning } l; eastl::function f; f = [l]() { return false; }; // ensure closure resources are cleaned up when assigning to a non-null eastl::function. f = [l]() { return true; }; } EATEST_VERIFY(sCtorCount == sDtorCount); } } // Checking _MSC_EXTENSIONS is required because the Microsoft calling convention classifiers are only available when // compiler specific C/C++ language extensions are enabled. #if defined(EA_PLATFORM_MICROSOFT) && defined(_MSC_EXTENSIONS) { // no arguments typedef void(__stdcall * StdCallFunction)(); typedef void(__cdecl * CDeclFunction)(); // only varargs typedef void(__stdcall * StdCallFunctionWithVarargs)(...); typedef void(__cdecl * CDeclFunctionWithVarargs)(...); // arguments and varargs typedef void(__stdcall * StdCallFunctionWithVarargsAtEnd)(int, int, int, ...); typedef void(__cdecl * CDeclFunctionWithVarargsAtEnd)(int, short, long, ...); static_assert(!eastl::is_function::value, "is_function failure"); static_assert(!eastl::is_function::value, "is_function failure"); static_assert(eastl::is_function::type>::value, "is_function failure"); static_assert(eastl::is_function::type>::value, "is_function failure"); static_assert(eastl::is_function::type>::value, "is_function failure"); static_assert(eastl::is_function::type>::value, "is_function failure"); static_assert(eastl::is_function::type>::value, "is_function failure"); static_assert(eastl::is_function::type>::value, "is_function failure"); } #endif // Test Function Objects #if defined(EA_COMPILER_CPP14_ENABLED) { // eastl::plus { { auto result = eastl::plus<>{}(40, 2); EA_UNUSED(result); EATEST_VERIFY(result == 42); } { auto result = eastl::plus<>{}(40.0, 2.0); EA_UNUSED(result); EATEST_VERIFY(result == 42.0); } { auto result = eastl::plus<>{}(eastl::string("4"), "2"); EA_UNUSED(result); EATEST_VERIFY(result == "42"); } } // eastl::minus { { auto result = eastl::minus<>{}(6, 2); EA_UNUSED(result); EATEST_VERIFY(result == 4); } { auto result = eastl::minus<>{}(6.0, 2.0); EA_UNUSED(result); EATEST_VERIFY(result == 4.0); } } // eastl::multiplies { { auto result = eastl::multiplies<>{}(6, 2); EA_UNUSED(result); EATEST_VERIFY(result == 12); } { auto result = eastl::multiplies<>{}(6.0, 2.0); EA_UNUSED(result); EATEST_VERIFY(result == 12.0); } } // eastl::divides { { auto result = eastl::divides<>{}(6, 2); EA_UNUSED(result); EATEST_VERIFY(result == 3); } { auto result = eastl::divides<>{}(6.0, 2.0); EA_UNUSED(result); EATEST_VERIFY(result == 3.0); } } // eastl::modulus { { auto result = eastl::modulus<>{}(6, 2); EA_UNUSED(result); EATEST_VERIFY(result == 0); } { auto result = eastl::modulus<>{}(7, 2); EA_UNUSED(result); EATEST_VERIFY(result == 1); } } // eastl::negate { { auto result = eastl::negate<>{}(42); EA_UNUSED(result); EATEST_VERIFY(result == -42); } { auto result = eastl::negate<>{}(42.0); EA_UNUSED(result); EATEST_VERIFY(result == -42.0); } } // eastl::equal_to { { auto result = eastl::equal_to<>{}(40, 2); EA_UNUSED(result); EATEST_VERIFY(!result); } { auto result = eastl::equal_to<>{}(40, 40); EA_UNUSED(result); EATEST_VERIFY(result); } } // eastl::not_equal_to { { auto result = eastl::not_equal_to<>{}(40, 2); EA_UNUSED(result); EATEST_VERIFY(result); } { auto result = eastl::not_equal_to<>{}(40, 40); EA_UNUSED(result); EATEST_VERIFY(!result); } } // eastl::greater { { auto result = eastl::greater<>{}(40, 2); EA_UNUSED(result); EATEST_VERIFY(result); } { auto result = eastl::greater<>{}(1, 2); EA_UNUSED(result); EATEST_VERIFY(!result); } { auto result = eastl::greater<>{}(eastl::string("4"), "2"); EA_UNUSED(result); EATEST_VERIFY(result); } } // eastl::less { { auto result = eastl::less<>{}(40, 2); EA_UNUSED(result); EATEST_VERIFY(!result); } { auto result = eastl::less<>{}(1, 2); EA_UNUSED(result); EATEST_VERIFY(result); } { auto result = eastl::less<>{}(eastl::string("4"), "2"); EA_UNUSED(result); EATEST_VERIFY(!result); } } // eastl::greater_equal { { auto result = eastl::greater_equal<>{}(40, 2); EA_UNUSED(result); EATEST_VERIFY(result); } { auto result = eastl::greater_equal<>{}(40, 40); EA_UNUSED(result); EATEST_VERIFY(result); } { auto result = eastl::greater_equal<>{}(40, 43); EA_UNUSED(result); EATEST_VERIFY(!result); } } // eastl::less_equal { { auto result = eastl::less_equal<>{}(40, 2); EA_UNUSED(result); EATEST_VERIFY(!result); } { auto result = eastl::less_equal<>{}(40, 40); EA_UNUSED(result); EATEST_VERIFY(result); } { auto result = eastl::less_equal<>{}(40, 43); EA_UNUSED(result); EATEST_VERIFY(result); } } // eastl::logical_and { auto result = eastl::logical_and<>{}(true, true); EATEST_VERIFY(result); result = eastl::logical_and<>{}(true, false); EATEST_VERIFY(!result); result = eastl::logical_and<>{}(false, true); EATEST_VERIFY(!result); result = eastl::logical_and<>{}(false, false); EATEST_VERIFY(!result); bool b = false; result = eastl::logical_and<>{}(b, false); EATEST_VERIFY(!result); } // eastl::logical_or { auto result = eastl::logical_or<>{}(true, true); EATEST_VERIFY(result); result = eastl::logical_or<>{}(true, false); EATEST_VERIFY(result); result = eastl::logical_or<>{}(false, true); EATEST_VERIFY(result); result = eastl::logical_or<>{}(false, false); EATEST_VERIFY(!result); bool b = false; result = eastl::logical_or<>{}(b, false); EATEST_VERIFY(!result); result = eastl::logical_or<>{}(b, true); EATEST_VERIFY(result); } // eastl::logical_not { auto result = eastl::logical_not<>{}(true); EATEST_VERIFY(!result); result = eastl::logical_not<>{}(result); EATEST_VERIFY(result); result = eastl::logical_not<>{}(false); EATEST_VERIFY(result); } } #endif // not_fn { { auto ft = eastl::not_fn([] { return true; }); auto ff = eastl::not_fn([] { return false; }); EATEST_VERIFY(ft() == false); EATEST_VERIFY(ff() == true); } } // reference_wrapper { // operator T& { int i = 0; eastl::reference_wrapper r(i); int &j = r; j = 42; EATEST_VERIFY(i == 42); } // get { int i = 0; eastl::reference_wrapper r(i); r.get() = 42; EATEST_VERIFY(i == 42); } // copy constructor { int i = 0; eastl::reference_wrapper r(i); eastl::reference_wrapper copy(r); copy.get() = 42; EATEST_VERIFY(i == 42); } // assignment { int i = 0; int j = 0; eastl::reference_wrapper r1(i); eastl::reference_wrapper r2(j); r2 = r1; // rebind r2 to refer to i r2.get() = 42; EATEST_VERIFY(i == 42); EATEST_VERIFY(j == 0); } // invoke { struct Functor { bool called = false; void operator()() {called = true;} }; Functor f; eastl::reference_wrapper r(f); r(); EATEST_VERIFY(f.called == true); } // ref/cref { { int i = 0; eastl::reference_wrapper r1 = eastl::ref(i); r1.get() = 42; eastl::reference_wrapper r2 = eastl::ref(r1); EATEST_VERIFY(i == 42); EATEST_VERIFY(r2 == 42); } { int i = 1337; eastl::reference_wrapper r1 = eastl::cref(i); EATEST_VERIFY(r1 == 1337); eastl::reference_wrapper r2 = eastl::cref(r1); EATEST_VERIFY(r2 == 1337); } } } return nErrorCount; } // Test that we can instantiate invoke_result with incorrect argument types. // This should be instantiable, but should not have a `type` typedef. struct TestInvokeResult { int f(int i) {return i;} }; template struct eastl::invoke_result; static_assert(!eastl::is_invocable::value, "incorrect value for is_invocable"); static_assert(eastl::is_invocable::value, "incorrect value for is_invocable");