/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ /* vim: set ts=8 sts=2 et sw=2 tw=80: */ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this file, * You can obtain one at http://mozilla.org/MPL/2.0/. */ #include "mozilla/Assertions.h" #include "mozilla/FunctionRef.h" #include "mozilla/UniquePtr.h" using mozilla::FunctionRef; #define CHECK(c) \ do { \ bool cond = !!(c); \ MOZ_RELEASE_ASSERT(cond, "Failed assertion: " #c); \ } while (false) int addConstRefs(const int& arg1, const int& arg2) { return arg1 + arg2; } void incrementPointer(int* arg) { (*arg)++; } int increment(int arg) { return arg + 1; } int incrementUnique(mozilla::UniquePtr ptr) { return *ptr + 1; } static bool helloWorldCalled = false; void helloWorld() { helloWorldCalled = true; } struct S { static int increment(int arg) { return arg + 1; } }; struct Incrementor { int operator()(int arg) { return arg + 1; } }; template struct Caller; template std::invoke_result_t CallFunctionRef(FunctionRef aRef, Params... aParams) { return aRef(std::forward(aParams)...); } static void TestNonmemberFunction() { CHECK(CallFunctionRef(increment, 42) == 43); } static void TestStaticMemberFunction() { CHECK(CallFunctionRef(&S::increment, 42) == 43); } static void TestFunctionObject() { auto incrementor = Incrementor(); CHECK(CallFunctionRef(incrementor, 42) == 43); } static void TestFunctionObjectTemporary() { CHECK(CallFunctionRef(Incrementor(), 42) == 43); } static void TestLambda() { // Test non-capturing lambda auto lambda1 = [](int arg) { return arg + 1; }; CHECK(CallFunctionRef(lambda1, 42) == 43); // Test capturing lambda int one = 1; auto lambda2 = [one](int arg) { return arg + one; }; CHECK(CallFunctionRef(lambda2, 42) == 43); CHECK(CallFunctionRef([](int arg) { return arg + 1; }, 42) == 43); } static void TestOperatorBool() { auto ToBool = [](FunctionRef aRef) { return static_cast(aRef); }; CHECK(!ToBool({})); CHECK(ToBool(increment)); CHECK(!ToBool(nullptr)); } static void TestReferenceParameters() { int x = 1; int y = 2; CHECK(CallFunctionRef(addConstRefs, x, y) == 3); } static void TestVoidNoParameters() { CHECK(!helloWorldCalled); CallFunctionRef(helloWorld); CHECK(helloWorldCalled); } static void TestPointerParameters() { int x = 1; CallFunctionRef(incrementPointer, &x); CHECK(x == 2); } static void TestImplicitFunctorTypeConversion() { auto incrementor = Incrementor(); short x = 1; CHECK(CallFunctionRef(incrementor, x) == 2); } static void TestImplicitLambdaTypeConversion() { short x = 1; CHECK(CallFunctionRef([](short arg) { return arg + 1; }, x) == 2); } static void TestImplicitFunctionPointerTypeConversion() { short x = 1; CHECK(CallFunctionRef(&increment, x) == 2); } static void TestMoveOnlyArguments() { CHECK(CallFunctionRef)>( &incrementUnique, mozilla::MakeUnique(5)) == 6); } int main() { TestNonmemberFunction(); TestStaticMemberFunction(); TestFunctionObject(); TestFunctionObjectTemporary(); TestLambda(); TestOperatorBool(); TestReferenceParameters(); TestPointerParameters(); TestVoidNoParameters(); TestImplicitFunctorTypeConversion(); TestImplicitLambdaTypeConversion(); TestImplicitFunctionPointerTypeConversion(); TestMoveOnlyArguments(); printf("TestFunctionRef OK!\n"); return 0; }