Scoped.h 9.0 KB

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