Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
Merge pull request #11560 from phire/EventHook_construct_on_first_use
HookableEvent: Switch to construct on first use
  • Loading branch information
AdmiralCurtiss committed Feb 14, 2023
2 parents 34a459b + 05181f6 commit 5f929d0
Showing 1 changed file with 28 additions and 15 deletions.
43 changes: 28 additions & 15 deletions Source/Core/Common/HookableEvent.h
Expand Up @@ -67,36 +67,49 @@ class HookableEvent
std::string m_name;
};

struct Storage
{
std::mutex m_mutex;
std::vector<HookImpl*> m_listeners;
};

// We use the "Construct On First Use" idiom to avoid the static initialization order fiasco.
// https://isocpp.org/wiki/faq/ctors#static-init-order
static Storage& GetStorage()
{
static Storage storage;
return storage;
}

static void Remove(HookImpl* handle)
{
auto& storage = GetStorage();
std::lock_guard lock(storage.m_mutex);

std::erase(storage.m_listeners, handle);
}

public:
// Returns a handle that will unregister the listener when destroyed.
static EventHook Register(CallbackType callback, std::string name)
{
std::lock_guard lock(m_mutex);
auto& storage = GetStorage();
std::lock_guard lock(storage.m_mutex);

DEBUG_LOG_FMT(COMMON, "Registering {} handler at {} event hook", name, EventName.value);
auto handle = std::make_unique<HookImpl>(callback, std::move(name));
m_listeners.push_back(handle.get());
storage.m_listeners.push_back(handle.get());
return handle;
}

static void Trigger(const CallbackArgs&... args)
{
std::lock_guard lock(m_mutex);
auto& storage = GetStorage();
std::lock_guard lock(storage.m_mutex);

for (const auto& handle : m_listeners)
for (const auto& handle : storage.m_listeners)
handle->m_fn(args...);
}

private:
static void Remove(HookImpl* handle)
{
std::lock_guard lock(m_mutex);

std::erase(m_listeners, handle);
}

inline static std::vector<HookImpl*> m_listeners = {};
inline static std::mutex m_mutex;
};

} // namespace Common

0 comments on commit 5f929d0

Please sign in to comment.