mirror of
https://git.wownero.com/wowlet/wowlet.git
synced 2024-08-15 01:03:14 +00:00
206 lines
7.2 KiB
C
206 lines
7.2 KiB
C
|
// Author: ricab
|
||
|
// Source: https://github.com/ricab/scope_guard
|
||
|
//
|
||
|
// This is free and unencumbered software released into the public domain.
|
||
|
//
|
||
|
// Anyone is free to copy, modify, publish, use, compile, sell, or
|
||
|
// distribute this software, either in source code form or as a compiled
|
||
|
// binary, for any purpose, commercial or non-commercial, and by any
|
||
|
// means.
|
||
|
//
|
||
|
// In jurisdictions that recognize copyright laws, the author or authors
|
||
|
// of this software dedicate any and all copyright interest in the
|
||
|
// software to the public domain. We make this dedication for the benefit
|
||
|
// of the public at large and to the detriment of our heirs and
|
||
|
// successors. We intend this dedication to be an overt act of
|
||
|
// relinquishment in perpetuity of all present and future rights to this
|
||
|
// software under copyright law.
|
||
|
//
|
||
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||
|
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||
|
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||
|
// IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
|
||
|
// OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
|
||
|
// ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
||
|
// OTHER DEALINGS IN THE SOFTWARE.
|
||
|
//
|
||
|
// For more information, please refer to <http://unlicense.org>
|
||
|
|
||
|
#ifndef SCOPE_GUARD_HPP_
|
||
|
#define SCOPE_GUARD_HPP_
|
||
|
|
||
|
#include <type_traits>
|
||
|
#include <utility>
|
||
|
|
||
|
#if __cplusplus >= 201703L && defined(SG_REQUIRE_NOEXCEPT_IN_CPP17)
|
||
|
#define SG_REQUIRE_NOEXCEPT
|
||
|
#endif
|
||
|
|
||
|
namespace sg
|
||
|
{
|
||
|
namespace detail
|
||
|
{
|
||
|
/* --- Some custom type traits --- */
|
||
|
|
||
|
// Type trait determining whether a type is callable with no arguments
|
||
|
template<typename T, typename = void>
|
||
|
struct is_noarg_callable_t
|
||
|
: public std::false_type
|
||
|
{}; // in general, false
|
||
|
|
||
|
template<typename T>
|
||
|
struct is_noarg_callable_t<T, decltype(std::declval<T&&>()())>
|
||
|
: public std::true_type
|
||
|
{}; // only true when call expression valid
|
||
|
|
||
|
// Type trait determining whether a no-argument callable returns void
|
||
|
template<typename T>
|
||
|
struct returns_void_t
|
||
|
: public std::is_same<void, decltype(std::declval<T&&>()())>
|
||
|
{};
|
||
|
|
||
|
/* Type trait determining whether a no-arg callable is nothrow invocable if
|
||
|
required. This is where SG_REQUIRE_NOEXCEPT logic is encapsulated. */
|
||
|
template<typename T>
|
||
|
struct is_nothrow_invocable_if_required_t
|
||
|
: public
|
||
|
#ifdef SG_REQUIRE_NOEXCEPT
|
||
|
std::is_nothrow_invocable<T> /* Note: _r variants not enough to
|
||
|
confirm void return: any return can be
|
||
|
discarded so all returns are
|
||
|
compatible with void */
|
||
|
#else
|
||
|
std::true_type
|
||
|
#endif
|
||
|
{};
|
||
|
|
||
|
// logic AND of two or more type traits
|
||
|
template<typename A, typename B, typename... C>
|
||
|
struct and_t : public and_t<A, and_t<B, C...>>
|
||
|
{}; // for more than two arguments
|
||
|
|
||
|
template<typename A, typename B>
|
||
|
struct and_t<A, B> : public std::conditional<A::value, B, A>::type
|
||
|
{}; // for two arguments
|
||
|
|
||
|
// Type trait determining whether a type is a proper scope_guard callback.
|
||
|
template<typename T>
|
||
|
struct is_proper_sg_callback_t
|
||
|
: public and_t<is_noarg_callable_t<T>,
|
||
|
returns_void_t<T>,
|
||
|
is_nothrow_invocable_if_required_t<T>,
|
||
|
std::is_nothrow_destructible<T>>
|
||
|
{};
|
||
|
|
||
|
|
||
|
/* --- The actual scope_guard template --- */
|
||
|
|
||
|
template<typename Callback,
|
||
|
typename = typename std::enable_if<
|
||
|
is_proper_sg_callback_t<Callback>::value>::type>
|
||
|
class scope_guard;
|
||
|
|
||
|
|
||
|
/* --- Now the friend maker --- */
|
||
|
|
||
|
template<typename Callback>
|
||
|
detail::scope_guard<Callback> make_scope_guard(Callback&& callback)
|
||
|
noexcept(std::is_nothrow_constructible<Callback, Callback&&>::value); /*
|
||
|
we need this in the inner namespace due to MSVC bugs preventing
|
||
|
sg::detail::scope_guard from befriending a sg::make_scope_guard
|
||
|
template instance in the parent namespace (see https://is.gd/xFfFhE). */
|
||
|
|
||
|
|
||
|
/* --- The template specialization that actually defines the class --- */
|
||
|
|
||
|
template<typename Callback>
|
||
|
class scope_guard<Callback> final
|
||
|
{
|
||
|
public:
|
||
|
typedef Callback callback_type;
|
||
|
|
||
|
scope_guard(scope_guard&& other)
|
||
|
noexcept(std::is_nothrow_constructible<Callback, Callback&&>::value);
|
||
|
|
||
|
~scope_guard() noexcept; // highlight noexcept dtor
|
||
|
|
||
|
void dismiss() noexcept;
|
||
|
|
||
|
public:
|
||
|
scope_guard() = delete;
|
||
|
scope_guard(const scope_guard&) = delete;
|
||
|
scope_guard& operator=(const scope_guard&) = delete;
|
||
|
scope_guard& operator=(scope_guard&&) = delete;
|
||
|
|
||
|
private:
|
||
|
explicit scope_guard(Callback&& callback)
|
||
|
noexcept(std::is_nothrow_constructible<Callback, Callback&&>::value); /*
|
||
|
meant for friends only */
|
||
|
|
||
|
friend scope_guard<Callback> make_scope_guard<Callback>(Callback&&)
|
||
|
noexcept(std::is_nothrow_constructible<Callback, Callback&&>::value); /*
|
||
|
only make_scope_guard can create scope_guards from scratch (i.e. non-move)
|
||
|
*/
|
||
|
|
||
|
private:
|
||
|
Callback m_callback;
|
||
|
bool m_active;
|
||
|
|
||
|
};
|
||
|
|
||
|
} // namespace detail
|
||
|
|
||
|
|
||
|
/* --- Now the single public maker function --- */
|
||
|
|
||
|
using detail::make_scope_guard; // see comment on declaration above
|
||
|
|
||
|
} // namespace sg
|
||
|
|
||
|
////////////////////////////////////////////////////////////////////////////////
|
||
|
template<typename Callback>
|
||
|
sg::detail::scope_guard<Callback>::scope_guard(Callback&& callback)
|
||
|
noexcept(std::is_nothrow_constructible<Callback, Callback&&>::value)
|
||
|
: m_callback(std::forward<Callback>(callback)) /* use () instead of {} because
|
||
|
of DR 1467 (https://is.gd/WHmWuo), which still impacts older compilers
|
||
|
(e.g. GCC 4.x and clang <=3.6, see https://godbolt.org/g/TE9tPJ and
|
||
|
https://is.gd/Tsmh8G) */
|
||
|
, m_active{true}
|
||
|
{}
|
||
|
|
||
|
////////////////////////////////////////////////////////////////////////////////
|
||
|
template<typename Callback>
|
||
|
sg::detail::scope_guard<Callback>::~scope_guard() noexcept
|
||
|
{
|
||
|
if(m_active)
|
||
|
m_callback();
|
||
|
}
|
||
|
|
||
|
////////////////////////////////////////////////////////////////////////////////
|
||
|
template<typename Callback>
|
||
|
sg::detail::scope_guard<Callback>::scope_guard(scope_guard&& other)
|
||
|
noexcept(std::is_nothrow_constructible<Callback, Callback&&>::value)
|
||
|
: m_callback(std::forward<Callback>(other.m_callback)) // idem
|
||
|
, m_active{std::move(other.m_active)}
|
||
|
{
|
||
|
other.m_active = false;
|
||
|
}
|
||
|
|
||
|
////////////////////////////////////////////////////////////////////////////////
|
||
|
template<typename Callback>
|
||
|
inline void sg::detail::scope_guard<Callback>::dismiss() noexcept
|
||
|
{
|
||
|
m_active = false;
|
||
|
}
|
||
|
|
||
|
////////////////////////////////////////////////////////////////////////////////
|
||
|
template<typename Callback>
|
||
|
inline auto sg::detail::make_scope_guard(Callback&& callback)
|
||
|
noexcept(std::is_nothrow_constructible<Callback, Callback&&>::value)
|
||
|
-> detail::scope_guard<Callback>
|
||
|
{
|
||
|
return detail::scope_guard<Callback>{std::forward<Callback>(callback)};
|
||
|
}
|
||
|
|
||
|
#endif /* SCOPE_GUARD_HPP_ */
|