Bug 718938 - Add RAII helper to mfbt. r=waldo,luke,cjones
authorDavid Rajchenbach-Teller <dteller@mozilla.com>
Fri, 06 Apr 2012 11:16:33 +0200
changeset 94502 5cc8dc1f19ec562ff36c25bb09488478c3f71cf5
parent 94501 11b6ea48df175e1217cb358f43077417f71e3c17
child 94503 a82e8c2edb2957b5cd6418b5d198e87c0ad80d1b
push id886
push userlsblakk@mozilla.com
push dateMon, 04 Jun 2012 19:57:52 +0000
treeherdermozilla-beta@bbd8d5efd6d1 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerswaldo, luke, cjones
bugs718938
milestone14.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 718938 - Add RAII helper to mfbt. r=waldo,luke,cjones
mfbt/Scoped.h
mfbt/exported_headers.mk
new file mode 100644
--- /dev/null
+++ b/mfbt/Scoped.h
@@ -0,0 +1,224 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this file,
+ * You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+/* A number of structures to simplify scope-based RAII management. */
+
+#ifndef mozilla_Scoped_h_
+#define mozilla_Scoped_h_
+
+/*
+ * Resource Acquisition Is Initialization is a programming idiom used
+ * to write robust code that is able to deallocate resources properly,
+ * even in presence of execution errors or exceptions that need to be
+ * propagated.  The Scoped* classes defined in this header perform the
+ * deallocation of the resource they hold once program execution
+ * reaches the end of the scope for which they have been defined.
+ *
+ * This header provides the following RAII classes:
+ *
+ * - |ScopedFreePtr| - a container for a pointer, that automatically calls
+ *   |free()| at the end of the scope;
+ * - |ScopedDeletePtr| - a container for a pointer, that automatically calls
+ *   |delete| at the end of the scope;
+ * - |ScopedDeleteArray| - a container for a pointer to an array, that
+ *   automatically calls |delete[]| at the end of the scope.
+ *
+ * The general scenario for each of the RAII classes is the following:
+ *
+ * ScopedClass foo(create_value());
+ * // ... In this scope, |foo| is defined. Use |foo.get()| or |foo.rwget()|
+ *        to access the value.
+ * // ... In case of |return| or |throw|, |foo| is deallocated automatically.
+ * // ... If |foo| needs to be returned or stored, use |foo.forget()|
+ *
+ * Note that the RAII classes defined in this header do _not_ perform any form
+ * of reference-counting or garbage-collection. These classes have exactly two
+ * behaviors:
+ * - if |forget()| has not been called, the resource is always deallocated at
+ *   the end of the scope;
+ * - if |forget()| has been called, any control on the resource is unbound
+ *   and the resource is not deallocated by the class.
+ *
+ *
+ * Extension:
+ *
+ * In addition, this header provides class |Scoped| and macro |SCOPED_TEMPLATE|
+ * to simplify the definition of RAII classes for other scenarios. These macros
+ * have been used to automatically close file descriptors/file handles when
+ * reaching the end of the scope, graphics contexts, etc.
+ */
+
+#include "mozilla/Attributes.h"
+#include "mozilla/GuardObjects.h"
+
+/*
+ * Scoped is a helper to create RAII wrappers
+ * Type argument |Traits| is expected to have the following structure:
+ *
+ *   struct Traits {
+ *     // Define the type of the value stored in the wrapper
+ *     typedef value_type type;
+ *     // Returns the value corresponding to the uninitialized or freed state
+ *     const static type empty();
+ *     // Release resources corresponding to the wrapped value
+ *     // This function is responsible for not releasing an |empty| value
+ *     const static void release(type);
+ *   }
+ */
+template <typename Traits>
+class Scoped
+{
+public:
+  typedef typename Traits::type Resource;
+
+  explicit Scoped(MOZ_GUARD_OBJECT_NOTIFIER_ONLY_PARAM)
+    : value(Traits::empty())
+  {
+    MOZ_GUARD_OBJECT_NOTIFIER_INIT;
+  }
+  explicit Scoped(const Resource& value
+                  MOZ_GUARD_OBJECT_NOTIFIER_PARAM)
+    : value(value)
+  {
+    MOZ_GUARD_OBJECT_NOTIFIER_INIT;
+  }
+  ~Scoped() {
+    Traits::release(value);
+  }
+
+  // Constant getter
+  operator const Resource&() const { return value; }
+  const Resource& operator->() const { return value; }
+  const Resource& get() const { return value; }
+  // Non-constant getter.
+  Resource& rwget() { return value; }
+
+  /*
+   * Forget the resource.
+   *
+   * Once |forget| has been called, the |Scoped| is neutralized, i.e. it will
+   * have no effect at destruction (unless it is reset to another resource by
+   * |operator=|).
+   *
+   * @return The original resource.
+   */
+  Resource forget() {
+    Resource tmp = value;
+    value = Traits::empty();
+    return tmp;
+  }
+
+  /*
+   * Perform immediate clean-up of this |Scoped|.
+   *
+   * If this |Scoped| is currently empty, this method has no effect.
+   */
+  void dispose() {
+    Traits::release(value);
+    value = Traits::empty();
+  }
+
+  bool operator==(const Resource& other) const {
+    return value == other;
+  }
+
+  /*
+   * Replace the resource with another resource.
+   *
+   * Calling |operator=| has the side-effect of triggering clean-up. If you do
+   * not want to trigger clean-up, you should first invoke |forget|.
+   *
+   * @return this
+   */
+  Scoped<Traits>& operator=(const Resource& other) {
+    return reset(other);
+  }
+  Scoped<Traits>& reset(const Resource& other) {
+    Traits::release(value);
+    value = other;
+    return *this;
+  }
+
+private:
+  explicit Scoped(const Scoped<Traits>& value) MOZ_DELETE;
+  Scoped<Traits>& operator=(const Scoped<Traits>& value) MOZ_DELETE;
+
+private:
+  Resource value;
+  MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER
+};
+
+/*
+ * SCOPED_TEMPLATE defines a templated class derived from Scoped
+ * This allows to implement templates such as ScopedFreePtr.
+ *
+ * @param name The name of the class to define.
+ * @param Traits A struct implementing clean-up. See the implementations
+ * for more details.
+ */
+#define SCOPED_TEMPLATE(name, Traits)                          \
+template <typename Type>                                       \
+struct name : public Scoped<Traits<Type> >                     \
+{                                                              \
+  typedef Scoped<Traits<Type> > Super;                         \
+  typedef typename Super::Resource Resource;                   \
+  name& operator=(Resource ptr) {                              \
+    Super::operator=(ptr);                                     \
+    return *this;                                              \
+  }                                                            \
+  explicit name(MOZ_GUARD_OBJECT_NOTIFIER_ONLY_PARAM)          \
+    : Super(MOZ_GUARD_OBJECT_NOTIFIER_ONLY_PARAM_TO_PARENT)    \
+  {}                                                           \
+  explicit name(Resource ptr                                   \
+                MOZ_GUARD_OBJECT_NOTIFIER_PARAM)               \
+    : Super(ptr MOZ_GUARD_OBJECT_NOTIFIER_PARAM_TO_PARENT)     \
+  {}                                                           \
+private:                                                       \
+  explicit name(name& source) MOZ_DELETE;                      \
+  name& operator=(name& source) MOZ_DELETE;                    \
+};
+
+/*
+ * ScopedFreePtr is a RAII wrapper for pointers that need to be free()d.
+ *
+ *   struct S { ... };
+ *   ScopedFreePtr<S> foo = malloc(sizeof(S));
+ *   ScopedFreePtr<char> bar = strdup(str);
+ */
+template <typename T>
+struct ScopedFreePtrTraits
+{
+  typedef T* type;
+  static T* empty() { return NULL; }
+  static void release(T* ptr) { free(ptr); }
+};
+SCOPED_TEMPLATE(ScopedFreePtr, ScopedFreePtrTraits)
+
+/*
+ * ScopedDeletePtr is a RAII wrapper for pointers that need to be deleted.
+ *
+ *   struct S { ... };
+ *   ScopedDeletePtr<S> foo = new S();
+ */
+template <typename T>
+struct ScopedDeletePtrTraits : public ScopedFreePtrTraits<T> {
+  static void release(T* ptr) { delete ptr; }
+};
+SCOPED_TEMPLATE(ScopedDeletePtr, ScopedDeletePtrTraits)
+
+/*
+ * ScopedDeleteArray is a RAII wrapper for pointers that need to be delete[]ed.
+ *
+ *   struct S { ... };
+ *   ScopedDeleteArray<S> foo = new S[42];
+ */
+template <typename T>
+struct ScopedDeleteArrayTraits : public ScopedFreePtrTraits<T>
+{
+  static void release(T* ptr) { delete [] ptr; }
+};
+SCOPED_TEMPLATE(ScopedDeleteArray, ScopedDeleteArrayTraits)
+
+
+#endif // mozilla_Scoped_h_
--- a/mfbt/exported_headers.mk
+++ b/mfbt/exported_headers.mk
@@ -47,12 +47,13 @@ EXPORTS_mozilla += \
   BloomFilter.h \
   GuardObjects.h \
   HashFunctions.h \
   Likely.h \
   LinkedList.h \
   MSStdInt.h \
   RangedPtr.h \
   RefPtr.h \
+  Scoped.h \
   StandardInteger.h \
   Types.h \
   Util.h \
   $(NULL)