summaryrefslogtreecommitdiff
path: root/src/mongo/util/scopeguard.h
diff options
context:
space:
mode:
Diffstat (limited to 'src/mongo/util/scopeguard.h')
-rw-r--r--src/mongo/util/scopeguard.h418
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__)