forked from mirrors/gecko-dev
		
	 ae75c3faa8
			
		
	
	
		ae75c3faa8
		
	
	
	
	
		
			
			Also make CompactPair<A, B> a literal type if A and B are literal types, and add MaybeStorageBase that ought to be used as a basis of MaybeStorage in a follow-up patch. Differential Revision: https://phabricator.services.mozilla.com/D55930
		
			
				
	
	
		
			489 lines
		
	
	
	
		
			17 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			489 lines
		
	
	
	
		
			17 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
| /* -*- 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/. */
 | |
| 
 | |
| // NB: This code may be used from non-XPCOM code, in particular, the
 | |
| // Windows Default Browser Agent.
 | |
| 
 | |
| #ifndef nsAutoRef_h_
 | |
| #define nsAutoRef_h_
 | |
| 
 | |
| #include "mozilla/Attributes.h"
 | |
| 
 | |
| template <class T>
 | |
| class nsSimpleRef;
 | |
| template <class T>
 | |
| class nsAutoRefBase;
 | |
| template <class T>
 | |
| class nsReturnRef;
 | |
| template <class T>
 | |
| class nsReturningRef;
 | |
| 
 | |
| /**
 | |
|  * template <class T> class nsAutoRef
 | |
|  *
 | |
|  * A class that holds a handle to a resource that must be released.
 | |
|  * No reference is added on construction.
 | |
|  *
 | |
|  * No copy constructor nor copy assignment operators are available, so the
 | |
|  * resource will be held until released on destruction or explicitly
 | |
|  * |reset()| or transferred through provided methods.
 | |
|  *
 | |
|  * The publicly available methods are the public methods on this class and its
 | |
|  * public base classes |nsAutoRefBase<T>| and |nsSimpleRef<T>|.
 | |
|  *
 | |
|  * For function return values see |nsReturnRef<T>|.
 | |
|  *
 | |
|  * For each class |T|, |nsAutoRefTraits<T>| or |nsSimpleRef<T>| must be
 | |
|  * specialized to use |nsAutoRef<T>|.
 | |
|  *
 | |
|  * @param T  A class identifying the type of reference held by the
 | |
|  *           |nsAutoRef<T>| and the unique set methods for managing references
 | |
|  *           to the resource (defined by |nsAutoRefTraits<T>| or
 | |
|  *           |nsSimpleRef<T>|).
 | |
|  *
 | |
|  *           Often this is the class representing the resource.  Sometimes a
 | |
|  *           new possibly-incomplete class may need to be declared.
 | |
|  *
 | |
|  *
 | |
|  * Example:  An Automatically closing file descriptor
 | |
|  *
 | |
|  * // References that are simple integral types (as file-descriptors are)
 | |
|  * // usually need a new class to represent the resource and how to handle its
 | |
|  * // references.
 | |
|  * class nsRawFD;
 | |
|  *
 | |
|  * // Specializing nsAutoRefTraits<nsRawFD> describes how to manage file
 | |
|  * // descriptors, so that nsAutoRef<nsRawFD> provides automatic closing of
 | |
|  * // its file descriptor on destruction.
 | |
|  * template <>
 | |
|  * class nsAutoRefTraits<nsRawFD> {
 | |
|  * public:
 | |
|  *     // The file descriptor is held in an int.
 | |
|  *     typedef int RawRef;
 | |
|  *     // -1 means that there is no file associated with the handle.
 | |
|  *     static int Void() { return -1; }
 | |
|  *     // The file associated with a file descriptor is released with close().
 | |
|  *     static void Release(RawRef aFD) { close(aFD); }
 | |
|  * };
 | |
|  *
 | |
|  * // A function returning a file descriptor that must be closed.
 | |
|  * nsReturnRef<nsRawFD> get_file(const char *filename) {
 | |
|  *     // Constructing from a raw file descriptor assumes ownership.
 | |
|  *     nsAutoRef<nsRawFD> fd(open(filename, O_RDONLY));
 | |
|  *     fcntl(fd, F_SETFD, FD_CLOEXEC);
 | |
|  *     return fd.out();
 | |
|  * }
 | |
|  *
 | |
|  * void f() {
 | |
|  *     unsigned char buf[1024];
 | |
|  *
 | |
|  *     // Hold a file descriptor for /etc/hosts in fd1.
 | |
|  *     nsAutoRef<nsRawFD> fd1(get_file("/etc/hosts"));
 | |
|  *
 | |
|  *     nsAutoRef<nsRawFD> fd2;
 | |
|  *     fd2.steal(fd1); // fd2 takes the file descriptor from fd1
 | |
|  *     ssize_t count = read(fd1, buf, 1024); // error fd1 has no file
 | |
|  *     count = read(fd2, buf, 1024); // reads from /etc/hosts
 | |
|  *
 | |
|  *     // If the file descriptor is not stored then it is closed.
 | |
|  *     get_file("/etc/login.defs"); // login.defs is closed
 | |
|  *
 | |
|  *     // Now use fd1 to hold a file descriptor for /etc/passwd.
 | |
|  *     fd1 = get_file("/etc/passwd");
 | |
|  *
 | |
|  *     // The nsAutoRef<nsRawFD> can give up the file descriptor if explicitly
 | |
|  *     // instructed, but the caller must then ensure that the file is closed.
 | |
|  *     int rawfd = fd1.disown();
 | |
|  *
 | |
|  *     // Assume ownership of another file descriptor.
 | |
|  *     fd1.own(open("/proc/1/maps");
 | |
|  *
 | |
|  *     // On destruction, fd1 closes /proc/1/maps and fd2 closes /etc/hosts,
 | |
|  *     // but /etc/passwd is not closed.
 | |
|  * }
 | |
|  *
 | |
|  */
 | |
| 
 | |
| template <class T>
 | |
| class nsAutoRef : public nsAutoRefBase<T> {
 | |
|  protected:
 | |
|   typedef nsAutoRef<T> ThisClass;
 | |
|   typedef nsAutoRefBase<T> BaseClass;
 | |
|   typedef nsSimpleRef<T> SimpleRef;
 | |
|   typedef typename BaseClass::RawRefOnly RawRefOnly;
 | |
|   typedef typename BaseClass::LocalSimpleRef LocalSimpleRef;
 | |
| 
 | |
|  public:
 | |
|   nsAutoRef() = default;
 | |
| 
 | |
|   // Explicit construction is required so as not to risk unintentionally
 | |
|   // releasing the resource associated with a raw ref.
 | |
|   explicit nsAutoRef(RawRefOnly aRefToRelease) : BaseClass(aRefToRelease) {}
 | |
| 
 | |
|   // Construction from a nsReturnRef<T> function return value, which expects
 | |
|   // to give up ownership, transfers ownership.
 | |
|   // (nsReturnRef<T> is converted to const nsReturningRef<T>.)
 | |
|   explicit nsAutoRef(const nsReturningRef<T>& aReturning)
 | |
|       : BaseClass(aReturning) {}
 | |
| 
 | |
|   // The only assignment operator provided is for transferring from an
 | |
|   // nsReturnRef smart reference, which expects to pass its ownership to
 | |
|   // another object.
 | |
|   //
 | |
|   // With raw references and other smart references, the type of the lhs and
 | |
|   // its taking and releasing nature is often not obvious from an assignment
 | |
|   // statement.  Assignment from a raw ptr especially is not normally
 | |
|   // expected to release the reference.
 | |
|   //
 | |
|   // Use |steal| for taking ownership from other smart refs.
 | |
|   //
 | |
|   // For raw references, use |own| to indicate intention to have the
 | |
|   // resource released.
 | |
| 
 | |
|   ThisClass& operator=(const nsReturningRef<T>& aReturning) {
 | |
|     BaseClass::steal(aReturning.mReturnRef);
 | |
|     return *this;
 | |
|   }
 | |
| 
 | |
|   // Conversion to a raw reference allow the nsAutoRef<T> to often be used
 | |
|   // like a raw reference.
 | |
|   operator typename SimpleRef::RawRef() const { return this->get(); }
 | |
| 
 | |
|   explicit operator bool() const { return this->HaveResource(); }
 | |
| 
 | |
|   // Transfer ownership from another smart reference.
 | |
|   void steal(ThisClass& aOtherRef) { BaseClass::steal(aOtherRef); }
 | |
| 
 | |
|   // Assume ownership of a raw ref.
 | |
|   //
 | |
|   // |own| has similar function to |steal|, and is useful for receiving
 | |
|   // ownership from a return value of a function.  It is named differently
 | |
|   // because |own| requires more care to ensure that the function intends to
 | |
|   // give away ownership, and so that |steal| can be safely used, knowing
 | |
|   // that it won't steal ownership from any methods returning raw ptrs to
 | |
|   // data owned by a foreign object.
 | |
|   void own(RawRefOnly aRefToRelease) { BaseClass::own(aRefToRelease); }
 | |
| 
 | |
|   // Exchange ownership with |aOther|
 | |
|   void swap(ThisClass& aOther) {
 | |
|     LocalSimpleRef temp;
 | |
|     temp.SimpleRef::operator=(*this);
 | |
|     SimpleRef::operator=(aOther);
 | |
|     aOther.SimpleRef::operator=(temp);
 | |
|   }
 | |
| 
 | |
|   // Release the reference now.
 | |
|   void reset() {
 | |
|     this->SafeRelease();
 | |
|     LocalSimpleRef empty;
 | |
|     SimpleRef::operator=(empty);
 | |
|   }
 | |
| 
 | |
|   // Pass out the reference for a function return values.
 | |
|   nsReturnRef<T> out() { return nsReturnRef<T>(this->disown()); }
 | |
| 
 | |
|   // operator->() and disown() are provided by nsAutoRefBase<T>.
 | |
|   // The default nsSimpleRef<T> provides get().
 | |
| 
 | |
|   // No copy constructor
 | |
|   explicit nsAutoRef(const ThisClass& aRefToSteal) = delete;
 | |
| };
 | |
| 
 | |
| /**
 | |
|  * template <class T> class nsReturnRef
 | |
|  *
 | |
|  * A type for function return values that hold a reference to a resource that
 | |
|  * must be released.  See also |nsAutoRef<T>::out()|.
 | |
|  */
 | |
| 
 | |
| template <class T>
 | |
| class nsReturnRef : public nsAutoRefBase<T> {
 | |
|  protected:
 | |
|   typedef nsAutoRefBase<T> BaseClass;
 | |
|   typedef typename BaseClass::RawRefOnly RawRefOnly;
 | |
| 
 | |
|  public:
 | |
|   // For constructing a return value with no resource
 | |
|   nsReturnRef() = default;
 | |
| 
 | |
|   // For returning a smart reference from a raw reference that must be
 | |
|   // released.  Explicit construction is required so as not to risk
 | |
|   // unintentionally releasing the resource associated with a raw ref.
 | |
|   MOZ_IMPLICIT nsReturnRef(RawRefOnly aRefToRelease)
 | |
|       : BaseClass(aRefToRelease) {}
 | |
| 
 | |
|   // Move construction transfers ownership
 | |
|   nsReturnRef(nsReturnRef<T>&& aRefToSteal) = default;
 | |
| 
 | |
|   MOZ_IMPLICIT nsReturnRef(const nsReturningRef<T>& aReturning)
 | |
|       : BaseClass(aReturning) {}
 | |
| 
 | |
|   // Conversion to a temporary (const) object referring to this object so
 | |
|   // that the reference may be passed from a function return value
 | |
|   // (temporary) to another smart reference.  There is no need to use this
 | |
|   // explicitly.  Simply assign a nsReturnRef<T> function return value to a
 | |
|   // smart reference.
 | |
|   operator nsReturningRef<T>() { return nsReturningRef<T>(*this); }
 | |
| 
 | |
|   // No conversion to RawRef operator is provided on nsReturnRef, to ensure
 | |
|   // that the return value is not carelessly assigned to a raw ptr (and the
 | |
|   // resource then released).  If passing to a function that takes a raw
 | |
|   // ptr, use get or disown as appropriate.
 | |
| };
 | |
| 
 | |
| /**
 | |
|  * template <class T> class nsReturningRef
 | |
|  *
 | |
|  * A class to allow ownership to be transferred from nsReturnRef function
 | |
|  * return values.
 | |
|  *
 | |
|  * It should not be necessary for clients to reference this
 | |
|  * class directly.  Simply pass an nsReturnRef<T> to a parameter taking an
 | |
|  * |nsReturningRef<T>|.
 | |
|  *
 | |
|  * The conversion operator on nsReturnRef constructs a temporary wrapper of
 | |
|  * class nsReturningRef<T> around a non-const reference to the nsReturnRef.
 | |
|  * The wrapper can then be passed as an rvalue parameter.
 | |
|  */
 | |
| 
 | |
| template <class T>
 | |
| class nsReturningRef {
 | |
|  private:
 | |
|   friend class nsReturnRef<T>;
 | |
| 
 | |
|   explicit nsReturningRef(nsReturnRef<T>& aReturnRef)
 | |
|       : mReturnRef(aReturnRef) {}
 | |
| 
 | |
|  public:
 | |
|   nsReturnRef<T>& mReturnRef;
 | |
| };
 | |
| 
 | |
| /**
 | |
|  * template <class T> class nsAutoRefTraits
 | |
|  *
 | |
|  * A class describing traits of references managed by the default
 | |
|  * |nsSimpleRef<T>| implementation and thus |nsAutoRef<T>|.
 | |
|  * The default |nsSimpleRef<T> is suitable for resources with handles that
 | |
|  * have a void value.  (If there is no such void value for a handle,
 | |
|  * specialize |nsSimpleRef<T>|.)
 | |
|  *
 | |
|  * Specializations must be provided for each class |T| according to the
 | |
|  * following pattern:
 | |
|  *
 | |
|  * // The template parameter |T| should be a class such that the set of fields
 | |
|  * // in class nsAutoRefTraits<T> is unique for class |T|.  Usually the
 | |
|  * // resource object class is sufficient.  For handles that are simple
 | |
|  * // integral typedefs, a new unique possibly-incomplete class may need to be
 | |
|  * // declared.
 | |
|  *
 | |
|  * template <>
 | |
|  * class nsAutoRefTraits<T>
 | |
|  * {
 | |
|  *     // Specializations must provide a typedef for RawRef, describing the
 | |
|  *     // type of the handle to the resource.
 | |
|  *     typedef <handle-type> RawRef;
 | |
|  *
 | |
|  *     // Specializations should define Void(), a function returning a value
 | |
|  *     // suitable for a handle that does not have an associated resource.
 | |
|  *     //
 | |
|  *     // The return type must be a suitable as the parameter to a RawRef
 | |
|  *     // constructor and operator==.
 | |
|  *     //
 | |
|  *     // If this method is not accessible then some limited nsAutoRef
 | |
|  *     // functionality will still be available, but the default constructor,
 | |
|  *     // |reset|, and most transfer of ownership methods will not be available.
 | |
|  *     static <return-type> Void();
 | |
|  *
 | |
|  *     // Specializations must define Release() to properly finalize the
 | |
|  *     // handle to a non-void custom-deleted or reference-counted resource.
 | |
|  *     static void Release(RawRef aRawRef);
 | |
|  * };
 | |
|  *
 | |
|  * See nsPointerRefTraits for example specializations for simple pointer
 | |
|  * references.  See nsAutoRef for an example specialization for a non-pointer
 | |
|  * reference.
 | |
|  */
 | |
| 
 | |
| template <class T>
 | |
| class nsAutoRefTraits;
 | |
| 
 | |
| /**
 | |
|  * template <class T> class nsPointerRefTraits
 | |
|  *
 | |
|  * A convenience class useful as a base class for specializations of
 | |
|  * |nsAutoRefTraits<T>| where the handle to the resource is a pointer to |T|.
 | |
|  * By inheriting from this class, definitions of only Release(RawRef) and
 | |
|  * possibly AddRef(RawRef) need to be added.
 | |
|  *
 | |
|  * Examples of use:
 | |
|  *
 | |
|  * template <>
 | |
|  * class nsAutoRefTraits<PRFileDesc> : public nsPointerRefTraits<PRFileDesc>
 | |
|  * {
 | |
|  * public:
 | |
|  *     static void Release(PRFileDesc *ptr) { PR_Close(ptr); }
 | |
|  * };
 | |
|  *
 | |
|  * template <>
 | |
|  * class nsAutoRefTraits<FcPattern> : public nsPointerRefTraits<FcPattern>
 | |
|  * {
 | |
|  * public:
 | |
|  *     static void Release(FcPattern *ptr) { FcPatternDestroy(ptr); }
 | |
|  *     static void AddRef(FcPattern *ptr) { FcPatternReference(ptr); }
 | |
|  * };
 | |
|  */
 | |
| 
 | |
| template <class T>
 | |
| class nsPointerRefTraits {
 | |
|  public:
 | |
|   // The handle is a pointer to T.
 | |
|   typedef T* RawRef;
 | |
|   // A nullptr does not have a resource.
 | |
|   static RawRef Void() { return nullptr; }
 | |
| };
 | |
| 
 | |
| /**
 | |
|  * template <class T> class nsSimpleRef
 | |
|  *
 | |
|  * Constructs a non-smart reference, and provides methods to test whether
 | |
|  * there is an associated resource and (if so) get its raw handle.
 | |
|  *
 | |
|  * A default implementation is suitable for resources with handles that have a
 | |
|  * void value.  This is not intended for direct use but used by |nsAutoRef<T>|.
 | |
|  *
 | |
|  * Specialize this class if there is no particular void value for the resource
 | |
|  * handle.  A specialized implementation must also provide Release(RawRef),
 | |
|  */
 | |
| 
 | |
| template <class T>
 | |
| class nsSimpleRef : protected nsAutoRefTraits<T> {
 | |
|  protected:
 | |
|   // The default implementation uses nsAutoRefTrait<T>.
 | |
|   // Specializations need not define this typedef.
 | |
|   typedef nsAutoRefTraits<T> Traits;
 | |
|   // The type of the handle to the resource.
 | |
|   // A specialization must provide a typedef for RawRef.
 | |
|   typedef typename Traits::RawRef RawRef;
 | |
| 
 | |
|   // Construct with no resource.
 | |
|   //
 | |
|   // If this constructor is not accessible then some limited nsAutoRef
 | |
|   // functionality will still be available, but the default constructor,
 | |
|   // |reset|, and most transfer of ownership methods will not be available.
 | |
|   nsSimpleRef() : mRawRef(Traits::Void()) {}
 | |
|   // Construct with a handle to a resource.
 | |
|   // A specialization must provide this.
 | |
|   explicit nsSimpleRef(RawRef aRawRef) : mRawRef(aRawRef) {}
 | |
| 
 | |
|   // Test whether there is an associated resource.  A specialization must
 | |
|   // provide this.  The function is permitted to always return true if the
 | |
|   // default constructor is not accessible, or if Release (and AddRef) can
 | |
|   // deal with void handles.
 | |
|   bool HaveResource() const { return mRawRef != Traits::Void(); }
 | |
| 
 | |
|  public:
 | |
|   // A specialization must provide get() or loose some functionality.  This
 | |
|   // is inherited by derived classes and the specialization may choose
 | |
|   // whether it is public or protected.
 | |
|   RawRef get() const { return mRawRef; }
 | |
| 
 | |
|  private:
 | |
|   RawRef mRawRef;
 | |
| };
 | |
| 
 | |
| /**
 | |
|  * template <class T> class nsAutoRefBase
 | |
|  *
 | |
|  * Internal base class for |nsAutoRef<T>| and |nsReturnRef<T>|.
 | |
|  * Adds release on destruction to a |nsSimpleRef<T>|.
 | |
|  */
 | |
| 
 | |
| template <class T>
 | |
| class nsAutoRefBase : public nsSimpleRef<T> {
 | |
|  protected:
 | |
|   typedef nsAutoRefBase<T> ThisClass;
 | |
|   typedef nsSimpleRef<T> SimpleRef;
 | |
|   typedef typename SimpleRef::RawRef RawRef;
 | |
| 
 | |
|   nsAutoRefBase() = default;
 | |
| 
 | |
|   // A type for parameters that should be passed a raw ref but should not
 | |
|   // accept implicit conversions (from another smart ref).  (The only
 | |
|   // conversion to this type is from a raw ref so only raw refs will be
 | |
|   // accepted.)
 | |
|   class RawRefOnly {
 | |
|    public:
 | |
|     MOZ_IMPLICIT RawRefOnly(RawRef aRawRef) : mRawRef(aRawRef) {}
 | |
|     operator RawRef() const { return mRawRef; }
 | |
| 
 | |
|    private:
 | |
|     RawRef mRawRef;
 | |
|   };
 | |
| 
 | |
|   // Construction from a raw ref assumes ownership
 | |
|   explicit nsAutoRefBase(RawRefOnly aRefToRelease) : SimpleRef(aRefToRelease) {}
 | |
| 
 | |
|   // Constructors that steal ownership
 | |
|   nsAutoRefBase(ThisClass&& aRefToSteal) : SimpleRef(aRefToSteal.disown()) {}
 | |
|   explicit nsAutoRefBase(const nsReturningRef<T>& aReturning)
 | |
|       : SimpleRef(aReturning.mReturnRef.disown()) {}
 | |
| 
 | |
|   ~nsAutoRefBase() { SafeRelease(); }
 | |
| 
 | |
|   // An internal class providing access to protected nsSimpleRef<T>
 | |
|   // constructors for construction of temporary simple references (that are
 | |
|   // not ThisClass).
 | |
|   class LocalSimpleRef : public SimpleRef {
 | |
|    public:
 | |
|     LocalSimpleRef() = default;
 | |
|     explicit LocalSimpleRef(RawRef aRawRef) : SimpleRef(aRawRef) {}
 | |
|   };
 | |
| 
 | |
|  public:
 | |
|   ThisClass& operator=(const ThisClass& aSmartRef) = delete;
 | |
| 
 | |
|   RawRef operator->() const { return this->get(); }
 | |
| 
 | |
|   // Transfer ownership to a raw reference.
 | |
|   //
 | |
|   // THE CALLER MUST ENSURE THAT THE REFERENCE IS EXPLICITLY RELEASED.
 | |
|   //
 | |
|   // Is this really what you want to use?  Using this removes any guarantee
 | |
|   // of release.  Use nsAutoRef<T>::out() for return values, or an
 | |
|   // nsAutoRef<T> modifiable lvalue for an out parameter.  Use disown() when
 | |
|   // the reference must be stored in a POD type object, such as may be
 | |
|   // preferred for a namespace-scope object with static storage duration,
 | |
|   // for example.
 | |
|   RawRef disown() {
 | |
|     RawRef temp = this->get();
 | |
|     LocalSimpleRef empty;
 | |
|     SimpleRef::operator=(empty);
 | |
|     return temp;
 | |
|   }
 | |
| 
 | |
|  protected:
 | |
|   // steal and own are protected because they make no sense on nsReturnRef,
 | |
|   // but steal is implemented on this class for access to aOtherRef.disown()
 | |
|   // when aOtherRef is an nsReturnRef;
 | |
| 
 | |
|   // Transfer ownership from another smart reference.
 | |
|   void steal(ThisClass& aOtherRef) { own(aOtherRef.disown()); }
 | |
|   // Assume ownership of a raw ref.
 | |
|   void own(RawRefOnly aRefToRelease) {
 | |
|     SafeRelease();
 | |
|     LocalSimpleRef ref(aRefToRelease);
 | |
|     SimpleRef::operator=(ref);
 | |
|   }
 | |
| 
 | |
|   // Release a resource if there is one.
 | |
|   void SafeRelease() {
 | |
|     if (this->HaveResource()) {
 | |
|       this->Release(this->get());
 | |
|     }
 | |
|   }
 | |
| };
 | |
| 
 | |
| #endif  // !defined(nsAutoRef_h_)
 |