// Copyright (C) 2023 Davis E. King (davis@dlib.net) // License: Boost Software License See LICENSE.txt for the full license. #ifndef DLIB_SCOPE_H_ #define DLIB_SCOPE_H_ #include <utility> #include <functional> #include <type_traits> namespace dlib { // ---------------------------------------------------------------------------------------- template<class Fn> class scope_exit { /*! WHAT THIS OBJECT REPRESENTS This is a standard's compliant backport of std::experimental::scope_exit that works with C++14. Therefore, refer to https://en.cppreference.com/w/cpp/experimental/scope_exit for docs on the interface of scope_exit. !*/ private: Fn f_; bool active_{true}; public: constexpr scope_exit() = delete; constexpr scope_exit(const scope_exit &) = delete; constexpr scope_exit &operator=(const scope_exit &) = delete; constexpr scope_exit &operator=(scope_exit &&) = delete; constexpr scope_exit(scope_exit &&other) noexcept(std::is_nothrow_move_constructible<Fn>::value) : f_{std::move(other.f_)}, active_{std::exchange(other.active_, false)} {} template< class F, std::enable_if_t<!std::is_same<std::decay_t<F>, scope_exit>::value, bool> = true > explicit scope_exit(F&& f) noexcept(std::is_nothrow_constructible<Fn,F>::value) : f_{std::forward<F>(f)}, active_{true} {} ~scope_exit() noexcept { if (active_) f_(); } void release() noexcept { active_ = false; } }; template<class Fn> auto make_scope_exit(Fn&& f) /*! ensures: - This is factory function that wraps the callback in a scope_exit object. !*/ { return scope_exit<std::decay_t<Fn>>(std::forward<Fn>(f)); } #ifdef __cpp_deduction_guides template<class Fn> scope_exit(Fn) -> scope_exit<Fn>; #endif // ---------------------------------------------------------------------------------------- using scope_exit_erased = scope_exit<std::function<void()>>; /*! WHAT THIS OBJECT REPRESENTS This is a type erased version of scope_exit. I.e. there is no template parameter. Use this object if you wish to hide the exact function signature, for example if splitting a declaration and definition across a header file and cpp file. This does come at a slight performance penalty since it may incur a heap allocation and due to a pointer indirection, the compiler may not inline your callback. !*/ // ---------------------------------------------------------------------------------------- } #endif //DLIB_SCOPE_H_