/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ /* vim: set ts=8 sts=2 et sw=2 tw=80: */ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ /* DEPRECATED: Use UniquePtr.h instead. */ #ifndef mozilla_Scoped_h #define mozilla_Scoped_h /* * DEPRECATED: Use UniquePtr.h instead. * * Resource Acquisition Is Initialization is a programming idiom used * to write robust code that is able to deallocate resources properly, * even in presence of execution errors or exceptions that need to be * propagated. The Scoped* classes defined in this header perform the * deallocation of the resource they hold once program execution * reaches the end of the scope for which they have been defined. * * This header provides the following RAII classes: * * - |ScopedFreePtr| - a container for a pointer, that automatically calls * |free()| at the end of the scope; * - |ScopedDeletePtr| - a container for a pointer, that automatically calls * |delete| at the end of the scope; * - |ScopedDeleteArray| - a container for a pointer to an array, that * automatically calls |delete[]| at the end of the scope. * * The general scenario for each of the RAII classes is the following: * * ScopedClass foo(create_value()); * // ... In this scope, |foo| is defined. Use |foo.get()| or |foo.rwget()| * to access the value. * // ... In case of |return| or |throw|, |foo| is deallocated automatically. * // ... If |foo| needs to be returned or stored, use |foo.forget()| * * Note that the RAII classes defined in this header do _not_ perform any form * of reference-counting or garbage-collection. These classes have exactly two * behaviors: * * - if |forget()| has not been called, the resource is always deallocated at * the end of the scope; * - if |forget()| has been called, any control on the resource is unbound * and the resource is not deallocated by the class. * * Extension: * * In addition, this header provides class |Scoped| and macros |SCOPED_TEMPLATE| * and |MOZ_TYPE_SPECIFIC_SCOPED_POINTER_TEMPLATE| to simplify the definition * of RAII classes for other scenarios. These macros have been used to * automatically close file descriptors/file handles when reaching the end of * the scope, graphics contexts, etc. */ #include "mozilla/Assertions.h" #include "mozilla/Attributes.h" #include "mozilla/GuardObjects.h" #include "mozilla/Move.h" #include "mozilla/NullPtr.h" namespace mozilla { /* * Scoped is a helper to create RAII wrappers * Type argument |Traits| is expected to have the following structure: * * struct Traits * { * // Define the type of the value stored in the wrapper * typedef value_type type; * // Returns the value corresponding to the uninitialized or freed state * const static type empty(); * // Release resources corresponding to the wrapped value * // This function is responsible for not releasing an |empty| value * const static void release(type); * } */ template class Scoped { public: typedef typename Traits::type Resource; explicit Scoped(MOZ_GUARD_OBJECT_NOTIFIER_ONLY_PARAM) : mValue(Traits::empty()) { MOZ_GUARD_OBJECT_NOTIFIER_INIT; } explicit Scoped(const Resource& aValue MOZ_GUARD_OBJECT_NOTIFIER_PARAM) : mValue(aValue) { MOZ_GUARD_OBJECT_NOTIFIER_INIT; } /* Move constructor. */ explicit Scoped(Scoped&& aOther MOZ_GUARD_OBJECT_NOTIFIER_PARAM) : mValue(Move(aOther.mValue)) { MOZ_GUARD_OBJECT_NOTIFIER_INIT; aOther.mValue = Traits::empty(); } ~Scoped() { Traits::release(mValue); } // Constant getter operator const Resource&() const { return mValue; } const Resource& operator->() const { return mValue; } const Resource& get() const { return mValue; } // Non-constant getter. Resource& rwget() { return mValue; } /* * Forget the resource. * * Once |forget| has been called, the |Scoped| is neutralized, i.e. it will * have no effect at destruction (unless it is reset to another resource by * |operator=|). * * @return The original resource. */ Resource forget() { Resource tmp = mValue; mValue = Traits::empty(); return tmp; } /* * Perform immediate clean-up of this |Scoped|. * * If this |Scoped| is currently empty, this method has no effect. */ void dispose() { Traits::release(mValue); mValue = Traits::empty(); } bool operator==(const Resource& aOther) const { return mValue == aOther; } /* * Replace the resource with another resource. * * Calling |operator=| has the side-effect of triggering clean-up. If you do * not want to trigger clean-up, you should first invoke |forget|. * * @return this */ Scoped& operator=(const Resource& aOther) { return reset(aOther); } Scoped& reset(const Resource& aOther) { Traits::release(mValue); mValue = aOther; return *this; } /* Move assignment operator. */ Scoped& operator=(Scoped&& aRhs) { MOZ_ASSERT(&aRhs != this, "self-move-assignment not allowed"); this->~Scoped(); new(this) Scoped(Move(aRhs)); return *this; } private: explicit Scoped(const Scoped& aValue) MOZ_DELETE; Scoped& operator=(const Scoped& aValue) MOZ_DELETE; private: Resource mValue; MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER }; /* * SCOPED_TEMPLATE defines a templated class derived from Scoped * This allows to implement templates such as ScopedFreePtr. * * @param name The name of the class to define. * @param Traits A struct implementing clean-up. See the implementations * for more details. */ #define SCOPED_TEMPLATE(name, Traits) \ template \ struct name : public mozilla::Scoped > \ { \ typedef mozilla::Scoped > Super; \ typedef typename Super::Resource Resource; \ name& operator=(Resource aRhs) \ { \ Super::operator=(aRhs); \ return *this; \ } \ name& operator=(name&& aRhs) \ { \ Super::operator=(Move(aRhs)); \ return *this; \ } \ explicit name(MOZ_GUARD_OBJECT_NOTIFIER_ONLY_PARAM) \ : Super(MOZ_GUARD_OBJECT_NOTIFIER_ONLY_PARAM_TO_PARENT) \ {} \ explicit name(Resource aRhs \ MOZ_GUARD_OBJECT_NOTIFIER_PARAM) \ : Super(aRhs \ MOZ_GUARD_OBJECT_NOTIFIER_PARAM_TO_PARENT) \ {} \ explicit name(name&& aRhs \ MOZ_GUARD_OBJECT_NOTIFIER_PARAM) \ : Super(Move(aRhs) \ MOZ_GUARD_OBJECT_NOTIFIER_PARAM_TO_PARENT) \ {} \ private: \ explicit name(name&) MOZ_DELETE; \ name& operator=(name&) MOZ_DELETE; \ }; /* * ScopedFreePtr is a RAII wrapper for pointers that need to be free()d. * * struct S { ... }; * ScopedFreePtr foo = malloc(sizeof(S)); * ScopedFreePtr bar = strdup(str); */ template struct ScopedFreePtrTraits { typedef T* type; static T* empty() { return nullptr; } static void release(T* aPtr) { free(aPtr); } }; SCOPED_TEMPLATE(ScopedFreePtr, ScopedFreePtrTraits) /* * ScopedDeletePtr is a RAII wrapper for pointers that need to be deleted. * * struct S { ... }; * ScopedDeletePtr foo = new S(); */ template struct ScopedDeletePtrTraits : public ScopedFreePtrTraits { static void release(T* aPtr) { delete aPtr; } }; SCOPED_TEMPLATE(ScopedDeletePtr, ScopedDeletePtrTraits) /* * ScopedDeleteArray is a RAII wrapper for pointers that need to be delete[]ed. * * struct S { ... }; * ScopedDeleteArray foo = new S[42]; */ template struct ScopedDeleteArrayTraits : public ScopedFreePtrTraits { static void release(T* aPtr) { delete [] aPtr; } }; SCOPED_TEMPLATE(ScopedDeleteArray, ScopedDeleteArrayTraits) /* * MOZ_TYPE_SPECIFIC_SCOPED_POINTER_TEMPLATE makes it easy to create scoped * pointers for types with custom deleters; just overload * TypeSpecificDelete(T*) in the same namespace as T to call the deleter for * type T. * * @param name The name of the class to define. * @param Type A struct implementing clean-up. See the implementations * for more details. * *param Deleter The function that is used to delete/destroy/free a * non-null value of Type*. * * Example: * * MOZ_TYPE_SPECIFIC_SCOPED_POINTER_TEMPLATE(ScopedPRFileDesc, PRFileDesc, \ * PR_Close) * ... * { * ScopedPRFileDesc file(PR_OpenFile(...)); * ... * } // file is closed with PR_Close here */ #define MOZ_TYPE_SPECIFIC_SCOPED_POINTER_TEMPLATE(name, Type, Deleter) \ template <> inline void TypeSpecificDelete(Type* aValue) { Deleter(aValue); } \ typedef ::mozilla::TypeSpecificScopedPointer name; template void TypeSpecificDelete(T* aValue); template struct TypeSpecificScopedPointerTraits { typedef T* type; static type empty() { return nullptr; } static void release(type aValue) { if (aValue) { TypeSpecificDelete(aValue); } } }; SCOPED_TEMPLATE(TypeSpecificScopedPointer, TypeSpecificScopedPointerTraits) } /* namespace mozilla */ #endif /* mozilla_Scoped_h */