Scoped.h 8.9 KB

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