summaryrefslogtreecommitdiffstats
path: root/xpcom/base/nsAutoRef.h
diff options
context:
space:
mode:
Diffstat (limited to 'xpcom/base/nsAutoRef.h')
-rw-r--r--xpcom/base/nsAutoRef.h489
1 files changed, 489 insertions, 0 deletions
diff --git a/xpcom/base/nsAutoRef.h b/xpcom/base/nsAutoRef.h
new file mode 100644
index 0000000000..9a1f3ddd93
--- /dev/null
+++ b/xpcom/base/nsAutoRef.h
@@ -0,0 +1,489 @@
+/* -*- 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_)