Skip to content

Commit

Permalink
Fixed possible infinite recursion in listen overloads.
Browse files Browse the repository at this point in the history
  • Loading branch information
5cript committed Feb 5, 2025
1 parent 53cb956 commit 0482b96
Show file tree
Hide file tree
Showing 2 changed files with 88 additions and 9 deletions.
95 changes: 87 additions & 8 deletions nui/include/nui/event_system/listen.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,20 @@
#include <utility>
#include <memory>
#include <functional>
#include <type_traits>

namespace Nui
{
namespace Detail
{
template <typename>
struct IsStdFunction : std::false_type
{};
template <typename RetT, typename... ArgsT>
struct IsStdFunction<std::function<RetT(ArgsT...)>> : std::true_type
{};
}

template <typename ValueT>
void listen(EventContext& eventContext, Observed<ValueT> const& obs, std::function<bool(ValueT const&)> onEvent)
{
Expand All @@ -22,6 +33,20 @@ namespace Nui
obs.attachEvent(eventId);
}

template <typename ValueT>
requires std::is_scalar_v<ValueT>
void listen(EventContext& eventContext, Observed<ValueT> const& obs, std::function<bool(ValueT)> onEvent)
{
const auto eventId = eventContext.registerEvent(Event{
[obs = Detail::CopyableObservedWrap{obs}, onEvent = std::move(onEvent)](auto) {
return onEvent(obs.value());
},
[]() {
return true;
}});
obs.attachEvent(eventId);
}

template <typename ValueT>
void listen(EventContext& eventContext, Observed<ValueT> const& obs, std::function<void(ValueT const&)> onEvent)
{
Expand All @@ -31,10 +56,23 @@ namespace Nui
});
}

template <typename ValueT>
requires std::is_scalar_v<ValueT>
void listen(EventContext& eventContext, Observed<ValueT> const& obs, std::function<void(ValueT)> onEvent)
{
return listen(eventContext, obs, [onEvent = std::move(onEvent)](ValueT value) {
onEvent(value);
return true;
});
}

template <typename ValueT, typename FunctionT>
void listen(EventContext& eventContext, Observed<ValueT> const& obs, FunctionT onEvent)
requires(
(std::invocable<FunctionT, ValueT const&> || std::invocable<FunctionT, ValueT>) &&
!Detail::IsStdFunction<FunctionT>::value)
void listen(EventContext& eventContext, Observed<ValueT> const& obs, FunctionT&& onEvent)
{
return listen(eventContext, obs, std::function(std::move(onEvent)));
return listen(eventContext, obs, std::function(std::forward<FunctionT>(onEvent)));
}

template <typename ValueT>
Expand All @@ -55,6 +93,25 @@ namespace Nui
obs->attachEvent(eventId);
}

template <typename ValueT>
requires std::is_scalar_v<ValueT>
void listen(
EventContext& eventContext,
std::shared_ptr<Observed<ValueT>> const& obs,
std::function<bool(ValueT)> onEvent)
{
const auto eventId = eventContext.registerEvent(Event{
[weak = std::weak_ptr<Observed<ValueT>>{obs}, onEvent = std::move(onEvent)](auto) {
if (auto obs = weak.lock(); obs)
return onEvent(obs->value());
return false;
},
[weak = std::weak_ptr<Observed<ValueT>>{obs}]() {
return !weak.expired();
}});
obs->attachEvent(eventId);
}

template <typename ValueT>
void listen(
EventContext& eventContext,
Expand All @@ -67,21 +124,43 @@ namespace Nui
});
}

template <typename ValueT>
requires std::is_scalar_v<ValueT>
void listen(
EventContext& eventContext,
std::shared_ptr<Observed<ValueT>> const& obs,
std::function<void(ValueT)> onEvent)
{
return listen(eventContext, obs, [onEvent = std::move(onEvent)](ValueT value) {
onEvent(value);
return true;
});
}

template <typename ValueT, typename FunctionT>
void listen(EventContext& eventContext, std::shared_ptr<Observed<ValueT>> const& obs, FunctionT onEvent)
requires(
(std::invocable<FunctionT, ValueT const&> || std::invocable<FunctionT, ValueT>) &&
!Detail::IsStdFunction<FunctionT>::value)
void listen(EventContext& eventContext, std::shared_ptr<Observed<ValueT>> const& obs, FunctionT&& onEvent)
{
return listen(eventContext, obs, std::function(std::move(onEvent)));
return listen(eventContext, obs, std::function(std::forward<FunctionT>(onEvent)));
}

template <typename ValueT, typename FunctionT>
void listen(std::shared_ptr<Observed<ValueT>> const& obs, FunctionT onEvent)
requires(
(std::invocable<FunctionT, ValueT const&> || std::invocable<FunctionT, ValueT>) &&
!Detail::IsStdFunction<FunctionT>::value)
void listen(std::shared_ptr<Observed<ValueT>> const& obs, FunctionT&& onEvent)
{
return listen(globalEventContext, obs, std::function(std::move(onEvent)));
return listen(globalEventContext, obs, std::function(std::forward<FunctionT>(onEvent)));
}

template <typename ValueT, typename FunctionT>
void listen(Observed<ValueT> const& obs, FunctionT onEvent)
requires(
(std::invocable<FunctionT, ValueT const&> || std::invocable<FunctionT, ValueT>) &&
!Detail::IsStdFunction<FunctionT>::value)
void listen(Observed<ValueT> const& obs, FunctionT&& onEvent)
{
return listen(globalEventContext, obs, std::function(std::move(onEvent)));
return listen(globalEventContext, obs, std::function(std::forward<FunctionT>(onEvent)));
}
}
2 changes: 1 addition & 1 deletion tools/inline_parser/test/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
include(GoogleTest)

find_package(Boost REQUIRED)
find_package(Boost CONFIG REQUIRED)

add_executable(inline_parser-tests
tests.cpp
Expand Down

0 comments on commit 0482b96

Please sign in to comment.