diff options
Diffstat (limited to 'src/mongo/util/scopeguard.h')
-rw-r--r-- | src/mongo/util/scopeguard.h | 418 |
1 files changed, 56 insertions, 362 deletions
diff --git a/src/mongo/util/scopeguard.h b/src/mongo/util/scopeguard.h index f9b9862c858..144b067b031 100644 --- a/src/mongo/util/scopeguard.h +++ b/src/mongo/util/scopeguard.h @@ -1,379 +1,76 @@ -//////////////////////////////////////////////////////////////////////////////// -// The Loki Library -// Copyright (c) 2000 Andrei Alexandrescu -// Copyright (c) 2000 Petru Marginean -// Copyright (c) 2005 Joshua Lehrer -// -// Permission to use, copy, modify, distribute and sell this software for any -// purpose is hereby granted without fee, provided that the above copyright -// notice appear in all copies and that both that copyright notice and this -// permission notice appear in supporting documentation. -// The author makes no representations about the -// suitability of this software for any purpose. It is provided "as is" -// without express or implied warranty. -//////////////////////////////////////////////////////////////////////////////// +/** + * Copyright (C) 2018-present MongoDB, Inc. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the Server Side Public License, version 1, + * as published by MongoDB, Inc. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * Server Side Public License for more details. + * + * You should have received a copy of the Server Side Public License + * along with this program. If not, see + * <http://www.mongodb.com/licensing/server-side-public-license>. + * + * As a special exception, the copyright holders give permission to link the + * code of portions of this program with the OpenSSL library under certain + * conditions as described in each individual source file and distribute + * linked combinations including the program with the OpenSSL library. You + * must comply with the Server Side Public License in all respects for + * all of the code used other than as permitted herein. If you modify file(s) + * with this exception, you may extend this exception to your version of the + * file(s), but you are not obligated to do so. If you do not wish to do so, + * delete this exception statement from your version. If you delete this + * exception statement from all source files in the program, then also delete + * it in the license file. + */ + #pragma once -#include <exception> +#include <type_traits> #include "mongo/platform/compiler.h" namespace mongo { -//////////////////////////////////////////////////////////////////////////////// -/// \class RefToValue -/// -/// Transports a reference as a value -/// Serves to implement the Colvin/Gibbons trick for SmartPtr/ScopeGuard -//////////////////////////////////////////////////////////////////////////////// - -template <class T> -class RefToValue { -public: - RefToValue(T& ref) : ref_(ref) {} - - RefToValue(const RefToValue& rhs) : ref_(rhs.ref_) {} - - operator T&() const { - return ref_; - } - -private: - // Disable - not implemented - RefToValue(); - RefToValue& operator=(const RefToValue&); - - T& ref_; -}; - - -//////////////////////////////////////////////////////////////////////////////// -/// RefToValue creator. -//////////////////////////////////////////////////////////////////////////////// - -template <class T> -inline RefToValue<T> ByRef(T& t) { - return RefToValue<T>(t); -} - - -//////////////////////////////////////////// -/// ScopeGuard -/* - Trivial example for use: - - FILE* f = fopen("myfile.txt", "w+"); - if (!f) - return error; - ON_BLOCK_EXIT(fclose, f); - - - More complicated example: - - ScopeGuard guard = MakeGuard(my_rollback_func, myparam); - ... - if (successful) { - guard.Dismiss(); - return; - } - // guard is still active here and will fire at scope exit - ... - - -*/ - - -class ScopeGuardImplBase { - ScopeGuardImplBase& operator=(const ScopeGuardImplBase&); - -protected: - ~ScopeGuardImplBase() {} - - ScopeGuardImplBase(const ScopeGuardImplBase& other) throw() : dismissed_(other.dismissed_) { - other.Dismiss(); - } - - template <typename J> - static void SafeExecute(J& j) throw() { - if (!j.dismissed_) - try { - j.Execute(); - } catch (...) { - std::terminate(); - } - } - - mutable bool dismissed_; - -public: - ScopeGuardImplBase() throw() : dismissed_(false) {} - - void Dismiss() const throw() { - dismissed_ = true; - } -}; - -//////////////////////////////////////////////////////////////// -/// -/// \typedef typedef const ScopeGuardImplBase& ScopeGuard -/// -/// See Andrei's and Petru Marginean's CUJ article -/// http://www.cuj.com/documents/s=8000/cujcexp1812alexandr/alexandr.htm -/// -/// Changes to the original code by Joshua Lehrer: -/// http://www.lehrerfamily.com/scopeguard.html -//////////////////////////////////////////////////////////////// - -typedef const ScopeGuardImplBase& ScopeGuard; - template <typename F> -class ScopeGuardImpl0 : public ScopeGuardImplBase { -public: - static ScopeGuardImpl0<F> MakeGuard(F fun) { - return ScopeGuardImpl0<F>(fun); - } - - ~ScopeGuardImpl0() throw() { - SafeExecute(*this); - } - - void Execute() { - fun_(); - } - -protected: - ScopeGuardImpl0(F fun) : fun_(fun) {} - - F fun_; -}; - -template <typename F> -inline ScopeGuardImpl0<F> MakeGuard(F fun) { - return ScopeGuardImpl0<F>::MakeGuard(fun); -} - -template <typename F, typename P1> -class ScopeGuardImpl1 : public ScopeGuardImplBase { -public: - static ScopeGuardImpl1<F, P1> MakeGuard(F fun, P1 p1) { - return ScopeGuardImpl1<F, P1>(fun, p1); - } - - ~ScopeGuardImpl1() throw() { - SafeExecute(*this); - } - - void Execute() { - fun_(p1_); - } - -protected: - ScopeGuardImpl1(F fun, P1 p1) : fun_(fun), p1_(p1) {} - - F fun_; - const P1 p1_; -}; - -template <typename F, typename P1> -inline ScopeGuardImpl1<F, P1> MakeGuard(F fun, P1 p1) { - return ScopeGuardImpl1<F, P1>::MakeGuard(fun, p1); -} - -template <typename F, typename P1, typename P2> -class ScopeGuardImpl2 : public ScopeGuardImplBase { +class ScopeGuard { public: - static ScopeGuardImpl2<F, P1, P2> MakeGuard(F fun, P1 p1, P2 p2) { - return ScopeGuardImpl2<F, P1, P2>(fun, p1, p2); - } - - ~ScopeGuardImpl2() throw() { - SafeExecute(*this); - } - - void Execute() { - fun_(p1_, p2_); - } - -protected: - ScopeGuardImpl2(F fun, P1 p1, P2 p2) : fun_(fun), p1_(p1), p2_(p2) {} - - F fun_; - const P1 p1_; - const P2 p2_; -}; - -template <typename F, typename P1, typename P2> -inline ScopeGuardImpl2<F, P1, P2> MakeGuard(F fun, P1 p1, P2 p2) { - return ScopeGuardImpl2<F, P1, P2>::MakeGuard(fun, p1, p2); -} - -template <typename F, typename P1, typename P2, typename P3> -class ScopeGuardImpl3 : public ScopeGuardImplBase { -public: - static ScopeGuardImpl3<F, P1, P2, P3> MakeGuard(F fun, P1 p1, P2 p2, P3 p3) { - return ScopeGuardImpl3<F, P1, P2, P3>(fun, p1, p2, p3); - } - - ~ScopeGuardImpl3() throw() { - SafeExecute(*this); - } - - void Execute() { - fun_(p1_, p2_, p3_); - } - -protected: - ScopeGuardImpl3(F fun, P1 p1, P2 p2, P3 p3) : fun_(fun), p1_(p1), p2_(p2), p3_(p3) {} - - F fun_; - const P1 p1_; - const P2 p2_; - const P3 p3_; -}; + explicit ScopeGuard(const F& f) : _func(f) {} + explicit ScopeGuard(F&& f) : _func(std::move(f)) {} -template <typename F, typename P1, typename P2, typename P3> -inline ScopeGuardImpl3<F, P1, P2, P3> MakeGuard(F fun, P1 p1, P2 p2, P3 p3) { - return ScopeGuardImpl3<F, P1, P2, P3>::MakeGuard(fun, p1, p2, p3); -} - -//************************************************************ - -template <class Obj, typename MemFun> -class ObjScopeGuardImpl0 : public ScopeGuardImplBase { -public: - static ObjScopeGuardImpl0<Obj, MemFun> MakeObjGuard(Obj& obj, MemFun memFun) { - return ObjScopeGuardImpl0<Obj, MemFun>(obj, memFun); + // Can only be move-constructed, to support being returned from a function. + ScopeGuard(const ScopeGuard&) = delete; + ScopeGuard(ScopeGuard&& o) : _func(std::move(o._func)), _dismissed(o._dismissed) { + o._dismissed = true; } + ScopeGuard& operator=(const ScopeGuard&) = delete; + ScopeGuard& operator=(ScopeGuard&&) = delete; - ~ObjScopeGuardImpl0() throw() { - SafeExecute(*this); + ~ScopeGuard() { + if (_dismissed) + return; + try { + _func(); + } catch (...) { + std::terminate(); + } } - void Execute() { - (obj_.*memFun_)(); + void dismiss() noexcept { + _dismissed = true; } -protected: - ObjScopeGuardImpl0(Obj& obj, MemFun memFun) : obj_(obj), memFun_(memFun) {} - - Obj& obj_; - MemFun memFun_; -}; - -template <class Obj, typename MemFun> -inline ObjScopeGuardImpl0<Obj, MemFun> MakeObjGuard(Obj& obj, MemFun memFun) { - return ObjScopeGuardImpl0<Obj, MemFun>::MakeObjGuard(obj, memFun); -} - -template <typename Ret, class Obj1, class Obj2> -inline ObjScopeGuardImpl0<Obj1, Ret (Obj2::*)()> MakeGuard(Ret (Obj2::*memFun)(), Obj1& obj) { - return ObjScopeGuardImpl0<Obj1, Ret (Obj2::*)()>::MakeObjGuard(obj, memFun); -} - -template <typename Ret, class Obj1, class Obj2> -inline ObjScopeGuardImpl0<Obj1, Ret (Obj2::*)()> MakeGuard(Ret (Obj2::*memFun)(), Obj1* obj) { - return ObjScopeGuardImpl0<Obj1, Ret (Obj2::*)()>::MakeObjGuard(*obj, memFun); -} - -template <class Obj, typename MemFun, typename P1> -class ObjScopeGuardImpl1 : public ScopeGuardImplBase { -public: - static ObjScopeGuardImpl1<Obj, MemFun, P1> MakeObjGuard(Obj& obj, MemFun memFun, P1 p1) { - return ObjScopeGuardImpl1<Obj, MemFun, P1>(obj, memFun, p1); - } - - ~ObjScopeGuardImpl1() throw() { - SafeExecute(*this); - } - - void Execute() { - (obj_.*memFun_)(p1_); - } - -protected: - ObjScopeGuardImpl1(Obj& obj, MemFun memFun, P1 p1) : obj_(obj), memFun_(memFun), p1_(p1) {} - - Obj& obj_; - MemFun memFun_; - const P1 p1_; -}; - -template <class Obj, typename MemFun, typename P1> -inline ObjScopeGuardImpl1<Obj, MemFun, P1> MakeObjGuard(Obj& obj, MemFun memFun, P1 p1) { - return ObjScopeGuardImpl1<Obj, MemFun, P1>::MakeObjGuard(obj, memFun, p1); -} - -template <typename Ret, class Obj1, class Obj2, typename P1a, typename P1b> -inline ObjScopeGuardImpl1<Obj1, Ret (Obj2::*)(P1a), P1b> MakeGuard(Ret (Obj2::*memFun)(P1a), - Obj1& obj, - P1b p1) { - return ObjScopeGuardImpl1<Obj1, Ret (Obj2::*)(P1a), P1b>::MakeObjGuard(obj, memFun, p1); -} - -template <typename Ret, class Obj1, class Obj2, typename P1a, typename P1b> -inline ObjScopeGuardImpl1<Obj1, Ret (Obj2::*)(P1a), P1b> MakeGuard(Ret (Obj2::*memFun)(P1a), - Obj1* obj, - P1b p1) { - return ObjScopeGuardImpl1<Obj1, Ret (Obj2::*)(P1a), P1b>::MakeObjGuard(*obj, memFun, p1); -} - -template <class Obj, typename MemFun, typename P1, typename P2> -class ObjScopeGuardImpl2 : public ScopeGuardImplBase { -public: - static ObjScopeGuardImpl2<Obj, MemFun, P1, P2> MakeObjGuard(Obj& obj, - MemFun memFun, - P1 p1, - P2 p2) { - return ObjScopeGuardImpl2<Obj, MemFun, P1, P2>(obj, memFun, p1, p2); - } - - ~ObjScopeGuardImpl2() throw() { - SafeExecute(*this); - } - - void Execute() { - (obj_.*memFun_)(p1_, p2_); - } - -protected: - ObjScopeGuardImpl2(Obj& obj, MemFun memFun, P1 p1, P2 p2) - : obj_(obj), memFun_(memFun), p1_(p1), p2_(p2) {} - - Obj& obj_; - MemFun memFun_; - const P1 p1_; - const P2 p2_; +private: + F _func; + bool _dismissed = false; }; -template <class Obj, typename MemFun, typename P1, typename P2> -inline ObjScopeGuardImpl2<Obj, MemFun, P1, P2> MakeObjGuard(Obj& obj, MemFun memFun, P1 p1, P2 p2) { - return ObjScopeGuardImpl2<Obj, MemFun, P1, P2>::MakeObjGuard(obj, memFun, p1, p2); -} - -template <typename Ret, - class Obj1, - class Obj2, - typename P1a, - typename P1b, - typename P2a, - typename P2b> -inline ObjScopeGuardImpl2<Obj1, Ret (Obj2::*)(P1a, P2a), P1b, P2b> MakeGuard( - Ret (Obj2::*memFun)(P1a, P2a), Obj1& obj, P1b p1, P2b p2) { - return ObjScopeGuardImpl2<Obj1, Ret (Obj2::*)(P1a, P2a), P1b, P2b>::MakeObjGuard( - obj, memFun, p1, p2); -} - -template <typename Ret, - class Obj1, - class Obj2, - typename P1a, - typename P1b, - typename P2a, - typename P2b> -inline ObjScopeGuardImpl2<Obj1, Ret (Obj2::*)(P1a, P2a), P1b, P2b> MakeGuard( - Ret (Obj2::*memFun)(P1a, P2a), Obj1* obj, P1b p1, P2b p2) { - return ObjScopeGuardImpl2<Obj1, Ret (Obj2::*)(P1a, P2a), P1b, P2b>::MakeObjGuard( - *obj, memFun, p1, p2); +template <typename F> +auto makeGuard(F&& fun) { + return ScopeGuard<std::decay_t<F>>(std::forward<F>(fun)); } } // namespace mongo @@ -382,7 +79,4 @@ inline ObjScopeGuardImpl2<Obj1, Ret (Obj2::*)(P1a, P2a), P1b, P2b> MakeGuard( #define MONGO_SCOPEGUARD_CAT(s1, s2) MONGO_SCOPEGUARD_CAT2(s1, s2) #define MONGO_SCOPEGUARD_ANON(str) MONGO_SCOPEGUARD_CAT(str, __LINE__) -#define ON_BLOCK_EXIT \ - MONGO_COMPILER_VARIABLE_UNUSED ScopeGuard MONGO_SCOPEGUARD_ANON(scopeGuard) = MakeGuard -#define ON_BLOCK_EXIT_OBJ \ - MONGO_COMPILER_VARIABLE_UNUSED ScopeGuard MONGO_SCOPEGUARD_ANON(scopeGuard) = MakeObjGuard +#define ON_BLOCK_EXIT(...) auto MONGO_SCOPEGUARD_ANON(onBlockExit) = makeGuard(__VA_ARGS__) |