LCOV - code coverage report
Current view: top level - mfbt - ScopeExit.h (source / functions) Hit Total Coverage
Test: output.info Lines: 13 13 100.0 %
Date: 2017-07-14 16:53:18 Functions: 79 255 31.0 %
Legend: Lines: hit not hit

          Line data    Source code
       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 "mozilla/GuardObjects.h"
      84             : #include "mozilla/Move.h"
      85             : 
      86             : namespace mozilla {
      87             : 
      88             : template <typename ExitFunction>
      89             : class MOZ_STACK_CLASS ScopeExit {
      90             :   ExitFunction mExitFunction;
      91             :   bool mExecuteOnDestruction;
      92             :   MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER
      93             : 
      94             : public:
      95       16743 :   explicit ScopeExit(ExitFunction&& cleanup
      96             :                      MOZ_GUARD_OBJECT_NOTIFIER_PARAM)
      97             :    : mExitFunction(cleanup)
      98       16743 :    , mExecuteOnDestruction(true)
      99             :   {
     100       16743 :     MOZ_GUARD_OBJECT_NOTIFIER_INIT;
     101       16743 :   }
     102             : 
     103             :   ScopeExit(ScopeExit&& rhs)
     104             :    : mExitFunction(mozilla::Move(rhs.mExitFunction))
     105             :    , mExecuteOnDestruction(rhs.mExecuteOnDestruction)
     106             :   {
     107             :     rhs.release();
     108             :   }
     109             : 
     110       16705 :   ~ScopeExit() {
     111       16705 :     if (mExecuteOnDestruction) {
     112        3858 :       mExitFunction();
     113             :     }
     114       16705 :   }
     115             : 
     116       12849 :   void release() {
     117       12849 :     mExecuteOnDestruction = false;
     118       12849 :   }
     119             : 
     120             : private:
     121             :   explicit ScopeExit(const ScopeExit&) = delete;
     122             :   ScopeExit& operator=(const ScopeExit&) = delete;
     123             :   ScopeExit& operator=(ScopeExit&&) = delete;
     124             : };
     125             : 
     126             : template <typename ExitFunction>
     127             : ScopeExit<ExitFunction>
     128       16743 : MakeScopeExit(ExitFunction&& exitFunction)
     129             : {
     130       16743 :   return ScopeExit<ExitFunction>(mozilla::Move(exitFunction));
     131             : }
     132             : 
     133             : } /* namespace mozilla */
     134             : 
     135             : #endif /* mozilla_ScopeExit_h */

Generated by: LCOV version 1.13