mfbt/Scoped.h

changeset 0
6474c204b198
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/mfbt/Scoped.h	Wed Dec 31 06:09:35 2014 +0100
     1.3 @@ -0,0 +1,305 @@
     1.4 +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
     1.5 +/* vim: set ts=8 sts=2 et sw=2 tw=80: */
     1.6 +/* This Source Code Form is subject to the terms of the Mozilla Public
     1.7 + * License, v. 2.0. If a copy of the MPL was not distributed with this
     1.8 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     1.9 +
    1.10 +/* A number of structures to simplify scope-based RAII management. */
    1.11 +
    1.12 +#ifndef mozilla_Scoped_h
    1.13 +#define mozilla_Scoped_h
    1.14 +
    1.15 +/*
    1.16 + * Resource Acquisition Is Initialization is a programming idiom used
    1.17 + * to write robust code that is able to deallocate resources properly,
    1.18 + * even in presence of execution errors or exceptions that need to be
    1.19 + * propagated.  The Scoped* classes defined in this header perform the
    1.20 + * deallocation of the resource they hold once program execution
    1.21 + * reaches the end of the scope for which they have been defined.
    1.22 + *
    1.23 + * This header provides the following RAII classes:
    1.24 + *
    1.25 + * - |ScopedFreePtr| - a container for a pointer, that automatically calls
    1.26 + *   |free()| at the end of the scope;
    1.27 + * - |ScopedDeletePtr| - a container for a pointer, that automatically calls
    1.28 + *   |delete| at the end of the scope;
    1.29 + * - |ScopedDeleteArray| - a container for a pointer to an array, that
    1.30 + *   automatically calls |delete[]| at the end of the scope.
    1.31 + *
    1.32 + * The general scenario for each of the RAII classes is the following:
    1.33 + *
    1.34 + * ScopedClass foo(create_value());
    1.35 + * // ... In this scope, |foo| is defined. Use |foo.get()| or |foo.rwget()|
    1.36 + *        to access the value.
    1.37 + * // ... In case of |return| or |throw|, |foo| is deallocated automatically.
    1.38 + * // ... If |foo| needs to be returned or stored, use |foo.forget()|
    1.39 + *
    1.40 + * Note that the RAII classes defined in this header do _not_ perform any form
    1.41 + * of reference-counting or garbage-collection. These classes have exactly two
    1.42 + * behaviors:
    1.43 + *
    1.44 + * - if |forget()| has not been called, the resource is always deallocated at
    1.45 + *   the end of the scope;
    1.46 + * - if |forget()| has been called, any control on the resource is unbound
    1.47 + *   and the resource is not deallocated by the class.
    1.48 + *
    1.49 + * Extension:
    1.50 + *
    1.51 + * In addition, this header provides class |Scoped| and macros |SCOPED_TEMPLATE|
    1.52 + * and |MOZ_TYPE_SPECIFIC_SCOPED_POINTER_TEMPLATE|  to simplify the definition
    1.53 + * of RAII classes for other scenarios. These macros have been used to
    1.54 + * automatically close file descriptors/file handles when reaching the end of
    1.55 + * the scope, graphics contexts, etc.
    1.56 + */
    1.57 +
    1.58 +#include "mozilla/Assertions.h"
    1.59 +#include "mozilla/Attributes.h"
    1.60 +#include "mozilla/GuardObjects.h"
    1.61 +#include "mozilla/Move.h"
    1.62 +#include "mozilla/NullPtr.h"
    1.63 +
    1.64 +namespace mozilla {
    1.65 +
    1.66 +/*
    1.67 + * Scoped is a helper to create RAII wrappers
    1.68 + * Type argument |Traits| is expected to have the following structure:
    1.69 + *
    1.70 + *   struct Traits {
    1.71 + *     // Define the type of the value stored in the wrapper
    1.72 + *     typedef value_type type;
    1.73 + *     // Returns the value corresponding to the uninitialized or freed state
    1.74 + *     const static type empty();
    1.75 + *     // Release resources corresponding to the wrapped value
    1.76 + *     // This function is responsible for not releasing an |empty| value
    1.77 + *     const static void release(type);
    1.78 + *   }
    1.79 + */
    1.80 +template<typename Traits>
    1.81 +class Scoped
    1.82 +{
    1.83 +  public:
    1.84 +    typedef typename Traits::type Resource;
    1.85 +
    1.86 +    explicit Scoped(MOZ_GUARD_OBJECT_NOTIFIER_ONLY_PARAM)
    1.87 +      : value(Traits::empty())
    1.88 +    {
    1.89 +      MOZ_GUARD_OBJECT_NOTIFIER_INIT;
    1.90 +    }
    1.91 +
    1.92 +    explicit Scoped(const Resource& v
    1.93 +                    MOZ_GUARD_OBJECT_NOTIFIER_PARAM)
    1.94 +      : value(v)
    1.95 +    {
    1.96 +      MOZ_GUARD_OBJECT_NOTIFIER_INIT;
    1.97 +    }
    1.98 +
    1.99 +    /* Move constructor. */
   1.100 +    explicit Scoped(Scoped&& v
   1.101 +                    MOZ_GUARD_OBJECT_NOTIFIER_PARAM)
   1.102 +      : value(Move(v.value))
   1.103 +    {
   1.104 +      MOZ_GUARD_OBJECT_NOTIFIER_INIT;
   1.105 +      v.value = Traits::empty();
   1.106 +    }
   1.107 +
   1.108 +    ~Scoped() {
   1.109 +      Traits::release(value);
   1.110 +    }
   1.111 +
   1.112 +    // Constant getter
   1.113 +    operator const Resource&() const { return value; }
   1.114 +    const Resource& operator->() const { return value; }
   1.115 +    const Resource& get() const { return value; }
   1.116 +    // Non-constant getter.
   1.117 +    Resource& rwget() { return value; }
   1.118 +
   1.119 +    /*
   1.120 +     * Forget the resource.
   1.121 +     *
   1.122 +     * Once |forget| has been called, the |Scoped| is neutralized, i.e. it will
   1.123 +     * have no effect at destruction (unless it is reset to another resource by
   1.124 +     * |operator=|).
   1.125 +     *
   1.126 +     * @return The original resource.
   1.127 +     */
   1.128 +    Resource forget() {
   1.129 +      Resource tmp = value;
   1.130 +      value = Traits::empty();
   1.131 +      return tmp;
   1.132 +    }
   1.133 +
   1.134 +    /*
   1.135 +     * Perform immediate clean-up of this |Scoped|.
   1.136 +     *
   1.137 +     * If this |Scoped| is currently empty, this method has no effect.
   1.138 +     */
   1.139 +    void dispose() {
   1.140 +      Traits::release(value);
   1.141 +      value = Traits::empty();
   1.142 +    }
   1.143 +
   1.144 +    bool operator==(const Resource& other) const {
   1.145 +      return value == other;
   1.146 +    }
   1.147 +
   1.148 +    /*
   1.149 +     * Replace the resource with another resource.
   1.150 +     *
   1.151 +     * Calling |operator=| has the side-effect of triggering clean-up. If you do
   1.152 +     * not want to trigger clean-up, you should first invoke |forget|.
   1.153 +     *
   1.154 +     * @return this
   1.155 +     */
   1.156 +    Scoped& operator=(const Resource& other) {
   1.157 +      return reset(other);
   1.158 +    }
   1.159 +    Scoped& reset(const Resource& other) {
   1.160 +      Traits::release(value);
   1.161 +      value = other;
   1.162 +      return *this;
   1.163 +    }
   1.164 +
   1.165 +    /* Move assignment operator. */
   1.166 +    Scoped& operator=(Scoped&& rhs) {
   1.167 +      MOZ_ASSERT(&rhs != this, "self-move-assignment not allowed");
   1.168 +      this->~Scoped();
   1.169 +      new(this) Scoped(Move(rhs));
   1.170 +      return *this;
   1.171 +    }
   1.172 +
   1.173 +  private:
   1.174 +    explicit Scoped(const Scoped& value) MOZ_DELETE;
   1.175 +    Scoped& operator=(const Scoped& value) MOZ_DELETE;
   1.176 +
   1.177 +  private:
   1.178 +    Resource value;
   1.179 +    MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER
   1.180 +};
   1.181 +
   1.182 +/*
   1.183 + * SCOPED_TEMPLATE defines a templated class derived from Scoped
   1.184 + * This allows to implement templates such as ScopedFreePtr.
   1.185 + *
   1.186 + * @param name The name of the class to define.
   1.187 + * @param Traits A struct implementing clean-up. See the implementations
   1.188 + * for more details.
   1.189 + */
   1.190 +#define SCOPED_TEMPLATE(name, Traits)                          \
   1.191 +template<typename Type>                                        \
   1.192 +struct name : public mozilla::Scoped<Traits<Type> >            \
   1.193 +{                                                              \
   1.194 +    typedef mozilla::Scoped<Traits<Type> > Super;              \
   1.195 +    typedef typename Super::Resource Resource;                 \
   1.196 +    name& operator=(Resource rhs) {                            \
   1.197 +      Super::operator=(rhs);                                   \
   1.198 +      return *this;                                            \
   1.199 +    }                                                          \
   1.200 +    name& operator=(name&& rhs) {                              \
   1.201 +      Super::operator=(Move(rhs));                             \
   1.202 +      return *this;                                            \
   1.203 +    }                                                          \
   1.204 +    explicit name(MOZ_GUARD_OBJECT_NOTIFIER_ONLY_PARAM)        \
   1.205 +      : Super(MOZ_GUARD_OBJECT_NOTIFIER_ONLY_PARAM_TO_PARENT)  \
   1.206 +    {}                                                         \
   1.207 +    explicit name(Resource rhs                                 \
   1.208 +                  MOZ_GUARD_OBJECT_NOTIFIER_PARAM)             \
   1.209 +      : Super(rhs                                              \
   1.210 +              MOZ_GUARD_OBJECT_NOTIFIER_PARAM_TO_PARENT)       \
   1.211 +    {}                                                         \
   1.212 +    explicit name(name&& rhs                                   \
   1.213 +                  MOZ_GUARD_OBJECT_NOTIFIER_PARAM)             \
   1.214 +      : Super(Move(rhs)                                        \
   1.215 +              MOZ_GUARD_OBJECT_NOTIFIER_PARAM_TO_PARENT)       \
   1.216 +    {}                                                         \
   1.217 +  private:                                                     \
   1.218 +    explicit name(name&) MOZ_DELETE;                           \
   1.219 +    name& operator=(name&) MOZ_DELETE;                         \
   1.220 +};
   1.221 +
   1.222 +/*
   1.223 + * ScopedFreePtr is a RAII wrapper for pointers that need to be free()d.
   1.224 + *
   1.225 + *   struct S { ... };
   1.226 + *   ScopedFreePtr<S> foo = malloc(sizeof(S));
   1.227 + *   ScopedFreePtr<char> bar = strdup(str);
   1.228 + */
   1.229 +template<typename T>
   1.230 +struct ScopedFreePtrTraits
   1.231 +{
   1.232 +    typedef T* type;
   1.233 +    static T* empty() { return nullptr; }
   1.234 +    static void release(T* ptr) { free(ptr); }
   1.235 +};
   1.236 +SCOPED_TEMPLATE(ScopedFreePtr, ScopedFreePtrTraits)
   1.237 +
   1.238 +/*
   1.239 + * ScopedDeletePtr is a RAII wrapper for pointers that need to be deleted.
   1.240 + *
   1.241 + *   struct S { ... };
   1.242 + *   ScopedDeletePtr<S> foo = new S();
   1.243 + */
   1.244 +template<typename T>
   1.245 +struct ScopedDeletePtrTraits : public ScopedFreePtrTraits<T>
   1.246 +{
   1.247 +    static void release(T* ptr) { delete ptr; }
   1.248 +};
   1.249 +SCOPED_TEMPLATE(ScopedDeletePtr, ScopedDeletePtrTraits)
   1.250 +
   1.251 +/*
   1.252 + * ScopedDeleteArray is a RAII wrapper for pointers that need to be delete[]ed.
   1.253 + *
   1.254 + *   struct S { ... };
   1.255 + *   ScopedDeleteArray<S> foo = new S[42];
   1.256 + */
   1.257 +template<typename T>
   1.258 +struct ScopedDeleteArrayTraits : public ScopedFreePtrTraits<T>
   1.259 +{
   1.260 +    static void release(T* ptr) { delete [] ptr; }
   1.261 +};
   1.262 +SCOPED_TEMPLATE(ScopedDeleteArray, ScopedDeleteArrayTraits)
   1.263 +
   1.264 +/*
   1.265 + * MOZ_TYPE_SPECIFIC_SCOPED_POINTER_TEMPLATE makes it easy to create scoped
   1.266 + * pointers for types with custom deleters; just overload
   1.267 + * TypeSpecificDelete(T*) in the same namespace as T to call the deleter for
   1.268 + * type T.
   1.269 + *
   1.270 + * @param name The name of the class to define.
   1.271 + * @param Type A struct implementing clean-up. See the implementations
   1.272 + * for more details.
   1.273 + * *param Deleter The function that is used to delete/destroy/free a
   1.274 + *        non-null value of Type*.
   1.275 + *
   1.276 + * Example:
   1.277 + *
   1.278 + *   MOZ_TYPE_SPECIFIC_SCOPED_POINTER_TEMPLATE(ScopedPRFileDesc, PRFileDesc, \
   1.279 + *                                             PR_Close)
   1.280 + *   ...
   1.281 + *   {
   1.282 + *       ScopedPRFileDesc file(PR_OpenFile(...));
   1.283 + *       ...
   1.284 + *   } // file is closed with PR_Close here
   1.285 + */
   1.286 +#define MOZ_TYPE_SPECIFIC_SCOPED_POINTER_TEMPLATE(name, Type, Deleter) \
   1.287 +template <> inline void TypeSpecificDelete(Type * value) { Deleter(value); } \
   1.288 +typedef ::mozilla::TypeSpecificScopedPointer<Type> name;
   1.289 +
   1.290 +template <typename T> void TypeSpecificDelete(T * value);
   1.291 +
   1.292 +template <typename T>
   1.293 +struct TypeSpecificScopedPointerTraits
   1.294 +{
   1.295 +    typedef T* type;
   1.296 +    const static type empty() { return nullptr; }
   1.297 +    const static void release(type value)
   1.298 +    {
   1.299 +      if (value)
   1.300 +        TypeSpecificDelete(value);
   1.301 +    }
   1.302 +};
   1.303 +
   1.304 +SCOPED_TEMPLATE(TypeSpecificScopedPointer, TypeSpecificScopedPointerTraits)
   1.305 +
   1.306 +} /* namespace mozilla */
   1.307 +
   1.308 +#endif /* mozilla_Scoped_h */

mercurial