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 /* DEPRECATED: Use UniquePtr.h instead. */
8 
9 #ifndef mozilla_Scoped_h
10 #define mozilla_Scoped_h
11 
12 /*
13  * DEPRECATED: Use UniquePtr.h instead.
14  *
15  * Resource Acquisition Is Initialization is a programming idiom used
16  * to write robust code that is able to deallocate resources properly,
17  * even in presence of execution errors or exceptions that need to be
18  * propagated.  The Scoped* classes defined in this header perform the
19  * deallocation of the resource they hold once program execution
20  * reaches the end of the scope for which they have been defined.
21  *
22  * This header provides the following RAII classes:
23  *
24  * - |ScopedFreePtr| - a container for a pointer, that automatically calls
25  *   |free()| at the end of the scope;
26  * - |ScopedDeletePtr| - a container for a pointer, that automatically calls
27  *   |delete| at the end of the scope;
28  *
29  * |ScopedDeleteArray| is removed in favor of |UniquePtr<T[]>|.
30  *
31  * The general scenario for each of the RAII classes is the following:
32  *
33  * ScopedClass foo(create_value());
34  * // ... In this scope, |foo| is defined. Use |foo.get()| or |foo.rwget()|
35  *        to access the value.
36  * // ... In case of |return| or |throw|, |foo| is deallocated automatically.
37  * // ... If |foo| needs to be returned or stored, use |foo.forget()|
38  *
39  * Note that the RAII classes defined in this header do _not_ perform any form
40  * of reference-counting or garbage-collection. These classes have exactly two
41  * behaviors:
42  *
43  * - if |forget()| has not been called, the resource is always deallocated at
44  *   the end of the scope;
45  * - if |forget()| has been called, any control on the resource is unbound
46  *   and the resource is not deallocated by the class.
47  *
48  * Extension:
49  *
50  * In addition, this header provides class |Scoped| and macros |SCOPED_TEMPLATE|
51  * and |MOZ_TYPE_SPECIFIC_SCOPED_POINTER_TEMPLATE|  to simplify the definition
52  * of RAII classes for other scenarios. These macros have been used to
53  * automatically close file descriptors/file handles when reaching the end of
54  * the scope, graphics contexts, etc.
55  */
56 
57 #include "mozilla/Assertions.h"
58 #include "mozilla/Attributes.h"
59 #include "mozilla/GuardObjects.h"
60 #include "mozilla/Move.h"
61 
62 namespace mozilla {
63 
64 /*
65  * Scoped is a helper to create RAII wrappers
66  * Type argument |Traits| is expected to have the following structure:
67  *
68  *   struct Traits
69  *   {
70  *     // Define the type of the value stored in the wrapper
71  *     typedef value_type type;
72  *     // Returns the value corresponding to the uninitialized or freed state
73  *     const static type empty();
74  *     // Release resources corresponding to the wrapped value
75  *     // This function is responsible for not releasing an |empty| value
76  *     const static void release(type);
77  *   }
78  */
79 template<typename Traits>
80 class MOZ_NON_TEMPORARY_CLASS Scoped
81 {
82 public:
83   typedef typename Traits::type Resource;
84 
Scoped(MOZ_GUARD_OBJECT_NOTIFIER_ONLY_PARAM)85   explicit Scoped(MOZ_GUARD_OBJECT_NOTIFIER_ONLY_PARAM)
86     : mValue(Traits::empty())
87   {
88     MOZ_GUARD_OBJECT_NOTIFIER_INIT;
89   }
90 
Scoped(const Resource & aValue MOZ_GUARD_OBJECT_NOTIFIER_PARAM)91   explicit Scoped(const Resource& aValue
92                   MOZ_GUARD_OBJECT_NOTIFIER_PARAM)
93     : mValue(aValue)
94   {
95     MOZ_GUARD_OBJECT_NOTIFIER_INIT;
96   }
97 
98   /* Move constructor. */
Scoped(Scoped && aOther MOZ_GUARD_OBJECT_NOTIFIER_PARAM)99   Scoped(Scoped&& aOther
100          MOZ_GUARD_OBJECT_NOTIFIER_PARAM)
101     : mValue(Move(aOther.mValue))
102   {
103     MOZ_GUARD_OBJECT_NOTIFIER_INIT;
104     aOther.mValue = Traits::empty();
105   }
106 
~Scoped()107   ~Scoped() { Traits::release(mValue); }
108 
109   // Constant getter
110   operator const Resource&() const { return mValue; }
111   const Resource& operator->() const { return mValue; }
get()112   const Resource& get() const { return mValue; }
113   // Non-constant getter.
rwget()114   Resource& rwget() { return mValue; }
115 
116   /*
117    * Forget the resource.
118    *
119    * Once |forget| has been called, the |Scoped| is neutralized, i.e. it will
120    * have no effect at destruction (unless it is reset to another resource by
121    * |operator=|).
122    *
123    * @return The original resource.
124    */
forget()125   Resource forget()
126   {
127     Resource tmp = mValue;
128     mValue = Traits::empty();
129     return tmp;
130   }
131 
132   /*
133    * Perform immediate clean-up of this |Scoped|.
134    *
135    * If this |Scoped| is currently empty, this method has no effect.
136    */
dispose()137   void dispose()
138   {
139     Traits::release(mValue);
140     mValue = Traits::empty();
141   }
142 
143   bool operator==(const Resource& aOther) const { return mValue == aOther; }
144 
145   /*
146    * Replace the resource with another resource.
147    *
148    * Calling |operator=| has the side-effect of triggering clean-up. If you do
149    * not want to trigger clean-up, you should first invoke |forget|.
150    *
151    * @return this
152    */
153   Scoped& operator=(const Resource& aOther) { return reset(aOther); }
154 
reset(const Resource & aOther)155   Scoped& reset(const Resource& aOther)
156   {
157     Traits::release(mValue);
158     mValue = aOther;
159     return *this;
160   }
161 
162   /* Move assignment operator. */
163   Scoped& operator=(Scoped&& aRhs)
164   {
165     MOZ_ASSERT(&aRhs != this, "self-move-assignment not allowed");
166     this->~Scoped();
167     new(this) Scoped(Move(aRhs));
168     return *this;
169   }
170 
171 private:
172   explicit Scoped(const Scoped& aValue) = delete;
173   Scoped& operator=(const Scoped& aValue) = delete;
174 
175 private:
176   Resource mValue;
177   MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER
178 };
179 
180 /*
181  * SCOPED_TEMPLATE defines a templated class derived from Scoped
182  * This allows to implement templates such as ScopedFreePtr.
183  *
184  * @param name The name of the class to define.
185  * @param Traits A struct implementing clean-up. See the implementations
186  * for more details.
187  */
188 #define SCOPED_TEMPLATE(name, Traits)                                         \
189 template<typename Type>                                                       \
190 struct MOZ_NON_TEMPORARY_CLASS name : public mozilla::Scoped<Traits<Type> >   \
191 {                                                                             \
192   typedef mozilla::Scoped<Traits<Type> > Super;                               \
193   typedef typename Super::Resource Resource;                                  \
194   name& operator=(Resource aRhs)                                              \
195   {                                                                           \
196     Super::operator=(aRhs);                                                   \
197     return *this;                                                             \
198   }                                                                           \
199   name& operator=(name&& aRhs)                                                \
200   {                                                                           \
201     Super::operator=(Move(aRhs));                                             \
202     return *this;                                                             \
203   }                                                                           \
204   explicit name(MOZ_GUARD_OBJECT_NOTIFIER_ONLY_PARAM)                         \
205     : Super(MOZ_GUARD_OBJECT_NOTIFIER_ONLY_PARAM_TO_PARENT)                   \
206   {}                                                                          \
207   explicit name(Resource aRhs                                                 \
208                 MOZ_GUARD_OBJECT_NOTIFIER_PARAM)                              \
209     : Super(aRhs                                                              \
210             MOZ_GUARD_OBJECT_NOTIFIER_PARAM_TO_PARENT)                        \
211   {}                                                                          \
212   name(name&& aRhs                                                            \
213        MOZ_GUARD_OBJECT_NOTIFIER_PARAM)                                       \
214     : Super(Move(aRhs)                                                        \
215             MOZ_GUARD_OBJECT_NOTIFIER_PARAM_TO_PARENT)                        \
216   {}                                                                          \
217 private:                                                                      \
218   explicit name(name&) = delete;                                              \
219   name& operator=(name&) = delete;                                            \
220 };
221 
222 /*
223  * ScopedFreePtr is a RAII wrapper for pointers that need to be free()d.
224  *
225  *   struct S { ... };
226  *   ScopedFreePtr<S> foo = malloc(sizeof(S));
227  *   ScopedFreePtr<char> bar = strdup(str);
228  */
229 template<typename T>
230 struct ScopedFreePtrTraits
231 {
232   typedef T* type;
emptyScopedFreePtrTraits233   static T* empty() { return nullptr; }
releaseScopedFreePtrTraits234   static void release(T* aPtr) { free(aPtr); }
235 };
236 SCOPED_TEMPLATE(ScopedFreePtr, ScopedFreePtrTraits)
237 
238 /*
239  * ScopedDeletePtr is a RAII wrapper for pointers that need to be deleted.
240  *
241  *   struct S { ... };
242  *   ScopedDeletePtr<S> foo = new S();
243  */
244 template<typename T>
245 struct ScopedDeletePtrTraits : public ScopedFreePtrTraits<T>
246 {
releaseScopedDeletePtrTraits247   static void release(T* aPtr) { delete aPtr; }
248 };
249 SCOPED_TEMPLATE(ScopedDeletePtr, ScopedDeletePtrTraits)
250 
251 /*
252  * MOZ_TYPE_SPECIFIC_SCOPED_POINTER_TEMPLATE makes it easy to create scoped
253  * pointers for types with custom deleters; just overload
254  * TypeSpecificDelete(T*) in the same namespace as T to call the deleter for
255  * type T.
256  *
257  * @param name The name of the class to define.
258  * @param Type A struct implementing clean-up. See the implementations
259  * for more details.
260  * *param Deleter The function that is used to delete/destroy/free a
261  *        non-null value of Type*.
262  *
263  * Example:
264  *
265  *   MOZ_TYPE_SPECIFIC_SCOPED_POINTER_TEMPLATE(ScopedPRFileDesc, PRFileDesc, \
266  *                                             PR_Close)
267  *   ...
268  *   {
269  *       ScopedPRFileDesc file(PR_OpenFile(...));
270  *       ...
271  *   } // file is closed with PR_Close here
272  */
273 #define MOZ_TYPE_SPECIFIC_SCOPED_POINTER_TEMPLATE(name, Type, Deleter) \
274 template <> inline void TypeSpecificDelete(Type* aValue) { Deleter(aValue); } \
275 typedef ::mozilla::TypeSpecificScopedPointer<Type> name;
276 
277 template <typename T> void TypeSpecificDelete(T* aValue);
278 
279 template <typename T>
280 struct TypeSpecificScopedPointerTraits
281 {
282   typedef T* type;
emptyTypeSpecificScopedPointerTraits283   static type empty() { return nullptr; }
releaseTypeSpecificScopedPointerTraits284   static void release(type aValue)
285   {
286     if (aValue) {
287       TypeSpecificDelete(aValue);
288     }
289   }
290 };
291 
292 SCOPED_TEMPLATE(TypeSpecificScopedPointer, TypeSpecificScopedPointerTraits)
293 
294 } /* namespace mozilla */
295 
296 #endif /* mozilla_Scoped_h */
297