tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

ScopeExit.h (3331B)


      1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
      2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
      3 /* This Source Code Form is subject to the terms of the Mozilla Public
      4 * License, v. 2.0. If a copy of the MPL was not distributed with this
      5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
      6 
      7 /* RAII class for executing arbitrary actions at scope end. */
      8 
      9 #ifndef mozilla_ScopeExit_h
     10 #define mozilla_ScopeExit_h
     11 
     12 /*
     13 * See http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2014/n4189.pdf for a
     14 * standards-track version of this.
     15 *
     16 * Error handling can be complex when various actions need to be performed that
     17 * need to be undone if an error occurs midway. This can be handled with a
     18 * collection of boolean state variables and gotos, which can get clunky and
     19 * error-prone:
     20 *
     21 * {
     22 *   if (!a.setup())
     23 *       goto fail;
     24 *   isASetup = true;
     25 *
     26 *   if (!b.setup())
     27 *       goto fail;
     28 *   isBSetup = true;
     29 *
     30 *   ...
     31 *   return true;
     32 *
     33 *   fail:
     34 *     if (isASetup)
     35 *         a.teardown();
     36 *     if (isBSetup)
     37 *         b.teardown();
     38 *     return false;
     39 *  }
     40 *
     41 * ScopeExit is a mechanism to simplify this pattern by keeping an RAII guard
     42 * class that will perform the teardown on destruction, unless released. So the
     43 * above would become:
     44 *
     45 * {
     46 *   if (!a.setup()) {
     47 *       return false;
     48 *   }
     49 *   auto guardA = MakeScopeExit([&] {
     50 *       a.teardown();
     51 *   });
     52 *
     53 *   if (!b.setup()) {
     54 *       return false;
     55 *   }
     56 *   auto guardB = MakeScopeExit([&] {
     57 *       b.teardown();
     58 *   });
     59 *
     60 *   ...
     61 *   guardA.release();
     62 *   guardB.release();
     63 *   return true;
     64 * }
     65 *
     66 * This header provides:
     67 *
     68 * - |ScopeExit| - a container for a cleanup call, automically called at the
     69 *   end of the scope;
     70 * - |MakeScopeExit| - a convenience function for constructing a |ScopeExit|
     71 *   with a given cleanup routine, commonly used with a lambda function.
     72 *
     73 * Note that the RAII classes defined in this header do _not_ perform any form
     74 * of reference-counting or garbage-collection. These classes have exactly two
     75 * behaviors:
     76 *
     77 * - if |release()| has not been called, the cleanup is always performed at
     78 *   the end of the scope;
     79 * - if |release()| has been called, nothing will happen at the end of the
     80 *   scope.
     81 */
     82 
     83 #include <utility>
     84 
     85 #include "mozilla/Attributes.h"
     86 
     87 namespace mozilla {
     88 
     89 template <typename ExitFunction>
     90 class MOZ_STACK_CLASS ScopeExit {
     91  ExitFunction mExitFunction;
     92  bool mExecuteOnDestruction;
     93 
     94 public:
     95  explicit ScopeExit(ExitFunction&& cleanup)
     96      : mExitFunction(std::move(cleanup)), mExecuteOnDestruction(true) {}
     97 
     98  ScopeExit(ScopeExit&& rhs)
     99      : mExitFunction(std::move(rhs.mExitFunction)),
    100        mExecuteOnDestruction(rhs.mExecuteOnDestruction) {
    101    rhs.release();
    102  }
    103 
    104  ~ScopeExit() {
    105    if (mExecuteOnDestruction) {
    106      mExitFunction();
    107    }
    108  }
    109 
    110  void release() { mExecuteOnDestruction = false; }
    111 
    112 private:
    113  explicit ScopeExit(const ScopeExit&) = delete;
    114  ScopeExit& operator=(const ScopeExit&) = delete;
    115  ScopeExit& operator=(ScopeExit&&) = delete;
    116 };
    117 
    118 template <typename ExitFunction>
    119 [[nodiscard]] ScopeExit<ExitFunction> MakeScopeExit(
    120    ExitFunction&& exitFunction) {
    121  return ScopeExit<ExitFunction>(std::move(exitFunction));
    122 }
    123 
    124 } /* namespace mozilla */
    125 
    126 #endif /* mozilla_ScopeExit_h */