/** * Copyright 2016 Facebook * @author Tudor Bosman (tudorb@fb.com) */ #pragma once #include #include #include #include #include namespace caffe2 { // Copied from folly/ScopeGuard.h namespace detail { class ScopeGuardImplBase { public: void dismiss() noexcept { dismissed_ = true; } protected: ScopeGuardImplBase() noexcept : dismissed_(false) {} static ScopeGuardImplBase makeEmptyScopeGuard() noexcept { return ScopeGuardImplBase{}; } template static const T& asConst(const T& t) noexcept { return t; } bool dismissed_; }; template class ScopeGuardImpl : public ScopeGuardImplBase { public: explicit ScopeGuardImpl(FunctionType& fn) noexcept( std::is_nothrow_copy_constructible::value) : ScopeGuardImpl( asConst(fn), makeFailsafe(std::is_nothrow_copy_constructible{}, &fn)) {} explicit ScopeGuardImpl(const FunctionType& fn) noexcept( std::is_nothrow_copy_constructible::value) : ScopeGuardImpl( fn, makeFailsafe(std::is_nothrow_copy_constructible{}, &fn)) {} explicit ScopeGuardImpl(FunctionType&& fn) noexcept( std::is_nothrow_move_constructible::value) : ScopeGuardImpl( std::move_if_noexcept(fn), makeFailsafe(std::is_nothrow_move_constructible{}, &fn)) {} ScopeGuardImpl(ScopeGuardImpl&& other) noexcept( std::is_nothrow_move_constructible::value) : function_(std::move_if_noexcept(other.function_)) { // If the above line attempts a copy and the copy throws, other is // left owning the cleanup action and will execute it (or not) depending // on the value of other.dismissed_. The following lines only execute // if the move/copy succeeded, in which case *this assumes ownership of // the cleanup action and dismisses other. dismissed_ = other.dismissed_; other.dismissed_ = true; } ~ScopeGuardImpl() noexcept { if (!dismissed_) { execute(); } } private: static ScopeGuardImplBase makeFailsafe(std::true_type, const void*) noexcept { return makeEmptyScopeGuard(); } template static auto makeFailsafe(std::false_type, Fn* fn) noexcept -> ScopeGuardImpl { return ScopeGuardImpl{std::ref(*fn)}; } template explicit ScopeGuardImpl(Fn&& fn, ScopeGuardImplBase&& failsafe) : ScopeGuardImplBase{}, function_(std::forward(fn)) { failsafe.dismiss(); } void* operator new(std::size_t) = delete; void execute() noexcept { function_(); } FunctionType function_; }; template using ScopeGuardImplDecay = ScopeGuardImpl::type>; } // namespace detail /** * ScopeGuard is a general implementation of the "Initialization is * Resource Acquisition" idiom. Basically, it guarantees that a function * is executed upon leaving the currrent scope unless otherwise told. * * The MakeGuard() function is used to create a new ScopeGuard object. * It can be instantiated with a lambda function, a std::function, * a functor, or a void(*)() function pointer. * * * Usage example: Add a friend to memory iff it is also added to the db. * * void User::addFriend(User& newFriend) { * // add the friend to memory * friends_.push_back(&newFriend); * * // If the db insertion that follows fails, we should * // remove it from memory. * auto guard = MakeGuard([&] { friends_.pop_back(); }); * * // this will throw an exception upon error, which * // makes the ScopeGuard execute UserCont::pop_back() * // once the Guard's destructor is called. * db_->addFriend(GetName(), newFriend.GetName()); * * // an exception was not thrown, so don't execute * // the Guard. * guard.dismiss(); * } * * Examine ScopeGuardTest.cpp for some more sample usage. * * Stolen from: * Andrei's and Petru Marginean's CUJ article: * http://drdobbs.com/184403758 * and the loki library: * http://loki-lib.sourceforge.net/index.php?n=Idioms.ScopeGuardPointer * and triendl.kj article: * http://www.codeproject.com/KB/cpp/scope_guard.aspx */ template detail::ScopeGuardImplDecay MakeGuard(F&& f) noexcept( noexcept(detail::ScopeGuardImplDecay(static_cast(f)))) { return detail::ScopeGuardImplDecay(static_cast(f)); } } // namespaces