From 29ab00633cf1087124faddf932185b88f65abd04 Mon Sep 17 00:00:00 2001 From: Michael Fabian 'Xaymar' Dirks Date: Wed, 4 Sep 2019 16:36:32 +0200 Subject: [PATCH] utility-event: Safer event handling with proper lifetime The util::event code suffers from the problem that it could call into a class that no longer exists, corrupting memory or even crashing. By tracking lifetime using std::weak_ptr this can be avoided and the dead listeners can be automatically removed. --- source/utility/utility-event.cpp | 86 +++++++++++++++++++++++++++++ source/utility/utility-event.hpp | 94 ++++++++++++++++++++++++++++++++ 2 files changed, 180 insertions(+) create mode 100644 source/utility/utility-event.cpp create mode 100644 source/utility/utility-event.hpp diff --git a/source/utility/utility-event.cpp b/source/utility/utility-event.cpp new file mode 100644 index 0000000..6b8840a --- /dev/null +++ b/source/utility/utility-event.cpp @@ -0,0 +1,86 @@ +/* + * Modern effects for a modern Streamer + * Copyright (C) 2018 Michael Fabian Dirks + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#include "utility-event.hpp" + +size_t utility::event::add(listener_t callback) +{ + _listeners.push_back(callback); + + { + arguments_t args; + args.emplace("event", this); + args.emplace("listener", &callback); + on.add(args); + } + + return _listeners.size(); +} + +size_t utility::event::remove(listener_t callback) +{ + _listeners.remove(callback); + + { + arguments_t args; + args.emplace("event", this); + args.emplace("listener", &callback); + on.remove(args); + } + + if (_listeners.empty()) { + arguments_t args; + args.emplace("event", this); + on.empty(args); + } + + return _listeners.size(); +} + +size_t utility::event::count() +{ + return _listeners.size(); +} + +bool utility::event::empty() +{ + return _listeners.empty(); +} + +void utility::event::clear() +{ + return _listeners.clear(); +} + +size_t utility::event::call(arguments_t& arguments) +{ + size_t idx = 0; + for (auto const& listener : _listeners) { + if (listener.second(listener.first, arguments)) { + break; + } + idx++; + } + return idx; +} + +size_t utility::event::operator()(arguments_t& arguments) +{ + return call(arguments); +} diff --git a/source/utility/utility-event.hpp b/source/utility/utility-event.hpp new file mode 100644 index 0000000..17fe511 --- /dev/null +++ b/source/utility/utility-event.hpp @@ -0,0 +1,94 @@ +/* + * Modern effects for a modern Streamer + * Copyright (C) 2018 Michael Fabian Dirks + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#ifndef OBS_STREAM_EFFECTS_UTILITY_EVENT_CPP +#define OBS_STREAM_EFFECTS_UTILITY_EVENT_CPP +#pragma once + +#include +#include +#include +#include +#include +#include + +namespace utility { + typedef std::map arguments_t; + typedef std::shared_ptr lifeline_t; + typedef std::function callback_t; + typedef std::pair listener_t; + + class event { + std::list _listeners; + + public: + size_t add(listener_t listener); + + inline event operator+=(listener_t listener) + { + add(listener); + return *this; + } + + size_t remove(listener_t listener); + + inline event operator-=(listener_t listener) + { + remove(listener); + return *this; + } + + size_t count(); + + bool empty(); + + inline operator bool() + { + return !this->empty(); + } + + void clear(); + + size_t call(arguments_t& arguments); + + inline size_t operator()(arguments_t& arguments) + { + return call(arguments); + } + + inline size_t call() + { + return call(arguments_t{}); + } + + inline size_t operator()() + { + return call(arguments_t{}); + } + + public: + struct { + utility::event add; + utility::event remove; + utility::event empty; + } on; + }; +} // namespace utility + +#endif OBS_STREAM_EFFECTS_UTILITY_EVENT_CPP