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