diff options
Diffstat (limited to 'source/blender')
-rw-r--r-- | source/blender/blenlib/BLI_function_ref.hh | 24 | ||||
-rw-r--r-- | source/blender/blenlib/tests/BLI_function_ref_test.cc | 25 |
2 files changed, 49 insertions, 0 deletions
diff --git a/source/blender/blenlib/BLI_function_ref.hh b/source/blender/blenlib/BLI_function_ref.hh index 57fffdc09b4..38e1ba593c5 100644 --- a/source/blender/blenlib/BLI_function_ref.hh +++ b/source/blender/blenlib/BLI_function_ref.hh @@ -16,6 +16,7 @@ #pragma once +#include <optional> #include <type_traits> #include <utility> @@ -139,6 +140,29 @@ template<typename Ret, typename... Params> class FunctionRef<Ret(Params...)> { return callback_(callable_, std::forward<Params>(params)...); } + using OptionalReturnValue = std::conditional_t<std::is_void_v<Ret>, void, std::optional<Ret>>; + + /** + * Calls the referenced function if it is available. + * The return value is of type `std::optional<Ret>` if `Ret` is not `void`. + * Otherwise the return type is `void`. + */ + OptionalReturnValue call_safe(Params... params) const + { + if constexpr (std::is_void_v<Ret>) { + if (callback_ == nullptr) { + return; + } + callback_(callable_, std::forward<Params>(params)...); + } + else { + if (callback_ == nullptr) { + return {}; + } + return callback_(callable_, std::forward<Params>(params)...); + } + } + /** * Returns true, when the `FunctionRef` references a function currently. * If this returns false, the `FunctionRef` must not be called. diff --git a/source/blender/blenlib/tests/BLI_function_ref_test.cc b/source/blender/blenlib/tests/BLI_function_ref_test.cc index cdcbccc72e8..74f5014142c 100644 --- a/source/blender/blenlib/tests/BLI_function_ref_test.cc +++ b/source/blender/blenlib/tests/BLI_function_ref_test.cc @@ -99,4 +99,29 @@ TEST(function_ref, ReferenceAnotherFunctionRef) EXPECT_EQ(y(), 2); } +TEST(function_ref, CallSafe) +{ + FunctionRef<int()> f; + EXPECT_FALSE(f.call_safe().has_value()); + auto func = []() { return 10; }; + f = func; + EXPECT_TRUE(f.call_safe().has_value()); + EXPECT_EQ(*f.call_safe(), 10); + f = {}; + EXPECT_FALSE(f.call_safe().has_value()); + BLI_STATIC_ASSERT((std::is_same_v<decltype(f.call_safe()), std::optional<int>>), ""); +} + +TEST(function_ref, CallSafeVoid) +{ + FunctionRef<void()> f; + BLI_STATIC_ASSERT((std::is_same_v<decltype(f.call_safe()), void>), ""); + f.call_safe(); + int value = 0; + auto func = [&]() { value++; }; + f = func; + f.call_safe(); + EXPECT_EQ(value, 1); +} + } // namespace blender::tests |