Skip to content

Commit

Permalink
Common: Avoid std::function overhead in ScopeGuard
Browse files Browse the repository at this point in the history
So far in all our uses of ScopeGuard, the type of the callable is
usually just a lambda or a function pointer, so there is no need
to rely on std::function's type erasure.

While the cost of using std::function is probably negligible, it still
causes some unnecessary overhead that can be avoided by making
ScopeGuard a templated class. Thanks to class template argument
deduction in C++17 most existing usages do not even need to be changed.

See https://godbolt.org/z/KcoPni for a comparison between
a ScopeGuard that uses std::function and one that doesn't
  • Loading branch information
leoetlino committed Feb 15, 2020
1 parent 62046d9 commit 44b4c2d
Show file tree
Hide file tree
Showing 2 changed files with 10 additions and 12 deletions.
16 changes: 7 additions & 9 deletions Source/Core/Common/ScopeGuard.h
Expand Up @@ -4,31 +4,29 @@

#pragma once

#include <functional>
#include <optional>

namespace Common
{
template <typename Callable>
class ScopeGuard final
{
public:
template <class Callable>
ScopeGuard(Callable&& finalizer) : m_finalizer(std::forward<Callable>(finalizer))
{
}
ScopeGuard(Callable&& finalizer) : m_finalizer(std::forward<Callable>(finalizer)) {}

ScopeGuard(ScopeGuard&& other) : m_finalizer(std::move(other.m_finalizer))
{
other.m_finalizer = nullptr;
}

~ScopeGuard() { Exit(); }
void Dismiss() { m_finalizer = nullptr; }
void Dismiss() { m_finalizer.reset(); }
void Exit()
{
if (m_finalizer)
{
m_finalizer(); // must not throw
m_finalizer = nullptr;
(*m_finalizer)(); // must not throw
m_finalizer.reset();
}
}

Expand All @@ -37,7 +35,7 @@ class ScopeGuard final
void operator=(const ScopeGuard&) = delete;

private:
std::function<void()> m_finalizer;
std::optional<Callable> m_finalizer;
};

} // Namespace Common
6 changes: 3 additions & 3 deletions Source/Core/Core/Core.cpp
Expand Up @@ -434,7 +434,7 @@ static void EmuThread(std::unique_ptr<BootParameters> boot, WindowSystemInfo wsi
s_frame_step = false;

Movie::Init(*boot);
Common::ScopeGuard movie_guard{Movie::Shutdown};
Common::ScopeGuard movie_guard{&Movie::Shutdown};

HW::Init();

Expand Down Expand Up @@ -539,7 +539,7 @@ static void EmuThread(std::unique_ptr<BootParameters> boot, WindowSystemInfo wsi
}};

AudioCommon::InitSoundStream();
Common::ScopeGuard audio_guard{AudioCommon::ShutdownSoundStream};
Common::ScopeGuard audio_guard{&AudioCommon::ShutdownSoundStream};

// The hardware is initialized.
s_hardware_initialized = true;
Expand All @@ -565,7 +565,7 @@ static void EmuThread(std::unique_ptr<BootParameters> boot, WindowSystemInfo wsi
// Initialise Wii filesystem contents.
// This is done here after Boot and not in HW to ensure that we operate
// with the correct title context since save copying requires title directories to exist.
Common::ScopeGuard wiifs_guard{Core::CleanUpWiiFileSystemContents};
Common::ScopeGuard wiifs_guard{&Core::CleanUpWiiFileSystemContents};
if (SConfig::GetInstance().bWii)
Core::InitializeWiiFileSystemContents();
else
Expand Down

0 comments on commit 44b4c2d

Please sign in to comment.