@@ 0,0 1,203 @@
+// Copyright (c) 2017-2021, Mudita Sp. z.o.o. All rights reserved.
+// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md
+
+#define CATCH_CONFIG_MAIN
+#include <catch2/catch.hpp>
+
+#include <module-utils/utility/Utility.hpp>
+
+struct SomeStruct
+{
+ int value;
+};
+
+class ExampleClass
+{
+ public:
+ int function1(int x, const SomeStruct &s)
+ {
+ return x + s.value;
+ }
+
+ void function2()
+ {}
+
+ int function3(int x, SomeStruct &s)
+ {
+ return x + s.value;
+ }
+
+ static int static_function1(int x, const SomeStruct &s)
+ {
+ return x + s.value;
+ }
+
+ static void static_function2()
+ {}
+
+ static int static_function3(int x, SomeStruct &s)
+ {
+ return x + s.value;
+ }
+};
+
+int global_function1(int x, const SomeStruct &s)
+{
+ return x + s.value;
+}
+
+void global_function2()
+{}
+
+int global_function3(int x, SomeStruct &s)
+{
+ return x + s.value;
+}
+
+TEST_CASE("Successful global function call")
+{
+ const auto guard = []() { return true; };
+
+ const auto [called1, ret1] = utility::conditionally_invoke(guard, &global_function1, 10, SomeStruct{5});
+ REQUIRE(called1 == true);
+ REQUIRE(ret1 == 15);
+
+ int x = 10;
+ SomeStruct s1{10};
+ const auto [called2, ret2] = utility::conditionally_invoke(guard, &global_function1, x, s1);
+ REQUIRE(called2 == true);
+ REQUIRE(ret2 == 20);
+
+ const auto called3 = utility::conditionally_invoke(guard, &global_function2);
+ REQUIRE(called3 == true);
+
+ SomeStruct s2{15};
+ const auto [called4, ret4] = utility::conditionally_invoke(guard, &global_function3, 10, std::ref(s2));
+ REQUIRE(called4 == true);
+ REQUIRE(ret4 == 25);
+}
+
+TEST_CASE("Failed global function call")
+{
+ const auto guard = []() { return false; };
+
+ const auto [called1, ret1] = utility::conditionally_invoke(guard, &global_function1, 10, SomeStruct{5});
+ REQUIRE(called1 == false);
+ REQUIRE(ret1 == 0);
+
+ int x = 10;
+ SomeStruct s1{10};
+ const auto [called2, ret2] = utility::conditionally_invoke(guard, &global_function1, x, s1);
+ REQUIRE(called2 == false);
+ REQUIRE(ret2 == 0);
+
+ const auto called3 = utility::conditionally_invoke(guard, &global_function2);
+ REQUIRE(called3 == false);
+
+ SomeStruct s2{15};
+ const auto [called4, ret4] = utility::conditionally_invoke(guard, &global_function3, 10, std::ref(s2));
+ REQUIRE(called4 == false);
+ REQUIRE(ret4 == 0);
+}
+
+TEST_CASE("Successful class static function call")
+{
+ const auto guard = []() { return true; };
+
+ const auto [called1, ret1] =
+ utility::conditionally_invoke(guard, &ExampleClass::static_function1, 10, SomeStruct{5});
+ REQUIRE(called1 == true);
+ REQUIRE(ret1 == 15);
+
+ int x = 10;
+ SomeStruct s1{10};
+ const auto [called2, ret2] = utility::conditionally_invoke(guard, &ExampleClass::static_function1, x, s1);
+ REQUIRE(called2 == true);
+ REQUIRE(ret2 == 20);
+
+ const auto called3 = utility::conditionally_invoke(guard, &ExampleClass::static_function2);
+ REQUIRE(called3 == true);
+
+ SomeStruct s2{15};
+ const auto [called4, ret4] =
+ utility::conditionally_invoke(guard, &ExampleClass::static_function3, 10, std::ref(s2));
+ REQUIRE(called4 == true);
+ REQUIRE(ret4 == 25);
+}
+
+TEST_CASE("Failed class static function call")
+{
+ const auto guard = []() { return false; };
+
+ const auto [called1, ret1] =
+ utility::conditionally_invoke(guard, &ExampleClass::static_function1, 10, SomeStruct{5});
+ REQUIRE(called1 == false);
+ REQUIRE(ret1 == 0);
+
+ int x = 10;
+ SomeStruct s1{10};
+ const auto [called2, ret2] = utility::conditionally_invoke(guard, &ExampleClass::static_function1, x, s1);
+ REQUIRE(called2 == false);
+ REQUIRE(ret2 == 0);
+
+ const auto called3 = utility::conditionally_invoke(guard, &ExampleClass::static_function2);
+ REQUIRE(called3 == false);
+
+ SomeStruct s2{15};
+ const auto [called4, ret4] =
+ utility::conditionally_invoke(guard, &ExampleClass::static_function3, 10, std::ref(s2));
+ REQUIRE(called4 == false);
+ REQUIRE(ret4 == 0);
+}
+
+TEST_CASE("Successful class member function call")
+{
+ ExampleClass instance;
+ const auto guard = []() { return true; };
+
+ const auto [called1, ret1] =
+ utility::conditionally_invoke(guard, instance, &ExampleClass::function1, 10, SomeStruct{5});
+ REQUIRE(called1 == true);
+ REQUIRE(ret1 == 15);
+
+ int x = 10;
+ SomeStruct s1{10};
+ const auto [called2, ret2] = utility::conditionally_invoke(guard, instance, &ExampleClass::function1, x, s1);
+ REQUIRE(called2 == true);
+ REQUIRE(ret2 == 20);
+
+ const auto called3 = utility::conditionally_invoke(guard, instance, &ExampleClass::function2);
+ REQUIRE(called3 == true);
+
+ SomeStruct s2{15};
+ const auto [called4, ret4] =
+ utility::conditionally_invoke(guard, instance, &ExampleClass::function3, 10, std::ref(s2));
+ REQUIRE(called4 == true);
+ REQUIRE(ret4 == 25);
+}
+
+TEST_CASE("Failed class member function call")
+{
+ ExampleClass instance;
+ const auto guard = []() { return false; };
+
+ const auto [called1, ret1] =
+ utility::conditionally_invoke(guard, instance, &ExampleClass::function1, 10, SomeStruct{5});
+ REQUIRE(called1 == false);
+ REQUIRE(ret1 == 0);
+
+ int x = 10;
+ SomeStruct s1{10};
+ const auto [called2, ret2] = utility::conditionally_invoke(guard, instance, &ExampleClass::function1, x, s1);
+ REQUIRE(called2 == false);
+ REQUIRE(ret2 == 0);
+
+ const auto called3 = utility::conditionally_invoke(guard, instance, &ExampleClass::function2);
+ REQUIRE(called3 == false);
+
+ SomeStruct s2{15};
+ const auto [called4, ret4] =
+ utility::conditionally_invoke(guard, instance, &ExampleClass::function3, 10, std::ref(s2));
+ REQUIRE(called4 == false);
+ REQUIRE(ret4 == 0);
+}
@@ 0,0 1,87 @@
+// Copyright (c) 2017-2021, Mudita Sp. z.o.o. All rights reserved.
+// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md
+
+#pragma once
+
+#include <functional>
+#include <utility>
+#include <type_traits>
+
+namespace utility
+{
+ using Guard = std::function<bool()>;
+
+ /// Invokes a function if specified conditions are met.
+ /// \tparam F Function signature
+ /// \tparam Args Function arguments
+ /// \param guard Conditions to be met
+ /// \param func Callable object
+ /// \param args Function arguments
+ /// \return If the function returns void - a flag indicating whether the conditions were met and the function has
+ /// been called. If the function returns a type - a pair of: a flag indicating whether the conditions were met, and
+ /// a function's return value.
+ template <typename F, typename... Args>
+ auto conditionally_invoke(const Guard &guard,
+ const F &func,
+ Args... args) noexcept(std::is_nothrow_invocable_v<F, Args...>)
+ {
+ using ResultType = typename std::invoke_result_t<F, Args...>;
+ constexpr auto isVoidFunction = std::is_void_v<ResultType>;
+ if (!guard()) {
+ if constexpr (isVoidFunction) {
+ return false;
+ }
+ else {
+ return std::pair(false, ResultType{});
+ }
+ }
+
+ if constexpr (isVoidFunction) {
+ std::invoke(func, std::forward<Args>(args)...);
+ return true;
+ }
+ else {
+ return std::pair(true, std::invoke(func, std::forward<Args>(args)...));
+ }
+ }
+
+ /// Invokes a member function if specified conditions are met.
+ /// \tparam T Class which contains the member function F
+ /// \tparam F Function signature
+ /// \tparam Args Function arguments
+ /// \param guard Conditions to be met
+ /// \param self Pointer to the class T instance
+ /// \param func Callable object
+ /// \param args Function arguments
+ /// \return If the function returns void - a flag indicating whether the conditions were met and the function has
+ /// been called. If the function returns a type - a pair of: a flag indicating whether the conditions were met, and
+ /// a function's return value.
+ template <class T,
+ typename F,
+ typename... Args,
+ typename std::enable_if_t<std::is_invocable_v<F, T, Args...>, bool> = false>
+ auto conditionally_invoke(const Guard &guard,
+ T &&self,
+ const F &func,
+ Args... args) noexcept(std::is_nothrow_invocable_v<F, T, Args...>)
+ {
+ using ResultType = typename std::invoke_result_t<F, T, Args...>;
+ constexpr auto isVoidFunction = std::is_void_v<ResultType>;
+ if (!guard()) {
+ if constexpr (isVoidFunction) {
+ return false;
+ }
+ else {
+ return std::pair(false, ResultType{});
+ }
+ }
+
+ if constexpr (isVoidFunction) {
+ std::invoke(func, std::forward<T>(self), std::forward<Args>(args)...);
+ return true;
+ }
+ else {
+ return std::pair(true, std::invoke(func, std::forward<T>(self), std::forward<Args>(args)...));
+ }
+ }
+} // namespace utility