/* * Copyright (C) 2008-2015 TrinityCore * * 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, see . */ #ifndef _WEAK_CALLBACK_CONTAINER_H_ #define _WEAK_CALLBACK_CONTAINER_H_ #include #include #include #include "Callback.h" class WeakCallbackContainer { std::shared_ptr self_reference; typedef std::size_t handle_t; std::size_t _handle; std::unordered_map _container; template struct ProxyFactory; template struct ProxyFactory<_CTy, ::fu::identity> { // Creates a weak proxy callback which prevents invoking to an invalid context. // Removes itself from the owner with the given handler. static callback_of_t<_CTy> CreateProxy(std::weak_ptr const& weak_owner, std::size_t const _handle, weak_callback_of_t<_CTy> const& weak_callback) { return [=](Args&&... args) { // Try to get a pointer to the owner if (auto const owner = weak_owner.lock()) // And to the wrapped functional itself if (auto const callback = weak_callback.lock()) { // Invoke the original callback (*callback)(std::forward(args)...); // Unregister the callback owner->InvalidateCallback(_handle); } }; } }; public: WeakCallbackContainer() : self_reference(this, [](decltype(this)) { }), _handle(0L) { } ~WeakCallbackContainer() = default; WeakCallbackContainer(WeakCallbackContainer const&) = delete; WeakCallbackContainer(WeakCallbackContainer&&) = delete; WeakCallbackContainer& operator= (WeakCallbackContainer const&) = delete; WeakCallbackContainer& operator= (WeakCallbackContainer&&) = delete; WeakCallbackContainer& Clear() { _container.clear(); return *this; } /// Weak wraps the given callable. template auto Wrap(_CTy&& callback) -> callback_of_t<_CTy> { // Create the shared callback shared_callback_of_t<_CTy> shared_callback = make_shared_callback(std::forward<_CTy>(callback)); // Create a weak proxy callback which removes the callback on execute auto const this_handle = _handle++; callback_of_t<_CTy> proxy = ProxyFactory<_CTy, ::fu::argument_type_of_t<_CTy>>:: CreateProxy(self_reference, this_handle, shared_callback); _container.insert(std::make_pair(this_handle, boost::any(std::move(shared_callback)))); return std::move(proxy); } /// Calls ::Wrap on the given callable, template inline auto operator()(_CTy&& callback) -> decltype(Wrap(std::declval<_CTy>())) { return Wrap(std::forward<_CTy>(callback)); } boost::optional GetLastCallbackHandle() const { if (_handle == 0L) return boost::none; else return boost::make_optional(_handle); } WeakCallbackContainer& InvalidateCallback(handle_t const handle) { _container.erase(handle); return *this; } }; #endif // _WEAK_CALLBACK_CONTAINER_H_