// 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 #ifndef SCOPE_GUARD_HPP_ #define SCOPE_GUARD_HPP_ #include #include #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 struct is_noarg_callable_t : public std::false_type {}; // in general, false template struct is_noarg_callable_t()())> : public std::true_type {}; // only true when call expression valid // Type trait determining whether a no-argument callable returns void template struct returns_void_t : public std::is_same()())> {}; /* Type trait determining whether a no-arg callable is nothrow invocable if required. This is where SG_REQUIRE_NOEXCEPT logic is encapsulated. */ template struct is_nothrow_invocable_if_required_t : public #ifdef SG_REQUIRE_NOEXCEPT std::is_nothrow_invocable /* 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 struct and_t : public and_t> {}; // for more than two arguments template struct and_t : public std::conditional::type {}; // for two arguments // Type trait determining whether a type is a proper scope_guard callback. template struct is_proper_sg_callback_t : public and_t, returns_void_t, is_nothrow_invocable_if_required_t, std::is_nothrow_destructible> {}; /* --- The actual scope_guard template --- */ template::value>::type> class scope_guard; /* --- Now the friend maker --- */ template detail::scope_guard make_scope_guard(Callback&& callback) noexcept(std::is_nothrow_constructible::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 class scope_guard final { public: typedef Callback callback_type; scope_guard(scope_guard&& other) noexcept(std::is_nothrow_constructible::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::value); /* meant for friends only */ friend scope_guard make_scope_guard(Callback&&) noexcept(std::is_nothrow_constructible::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 sg::detail::scope_guard::scope_guard(Callback&& callback) noexcept(std::is_nothrow_constructible::value) : m_callback(std::forward(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 sg::detail::scope_guard::~scope_guard() noexcept { if(m_active) m_callback(); } //////////////////////////////////////////////////////////////////////////////// template sg::detail::scope_guard::scope_guard(scope_guard&& other) noexcept(std::is_nothrow_constructible::value) : m_callback(std::forward(other.m_callback)) // idem , m_active{std::move(other.m_active)} { other.m_active = false; } //////////////////////////////////////////////////////////////////////////////// template inline void sg::detail::scope_guard::dismiss() noexcept { m_active = false; } //////////////////////////////////////////////////////////////////////////////// template inline auto sg::detail::make_scope_guard(Callback&& callback) noexcept(std::is_nothrow_constructible::value) -> detail::scope_guard { return detail::scope_guard{std::forward(callback)}; } #endif /* SCOPE_GUARD_HPP_ */