xpcom/base/nsAutoRef.h

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rw-r--r--

Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.

     1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
     2  * vim: set shiftwidth=4 tabstop=8 autoindent cindent expandtab: */
     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/. */
     7 #ifndef nsAutoRef_h_
     8 #define nsAutoRef_h_
    10 #include "mozilla/Attributes.h"
    12 #include "nscore.h" // for nullptr, bool
    14 template <class T> class nsSimpleRef;
    15 template <class T> class nsAutoRefBase;
    16 template <class T> class nsReturnRef;
    17 template <class T> class nsReturningRef;
    19 /**
    20  * template <class T> class nsAutoRef
    21  *
    22  * A class that holds a handle to a resource that must be released.
    23  * No reference is added on construction.
    24  *
    25  * No copy constructor nor copy assignment operators are available, so the
    26  * resource will be held until released on destruction or explicitly
    27  * |reset()| or transferred through provided methods.
    28  *
    29  * The publicly available methods are the public methods on this class and its
    30  * public base classes |nsAutoRefBase<T>| and |nsSimpleRef<T>|.
    31  *
    32  * For ref-counted resources see also |nsCountedRef<T>|.
    33  * For function return values see |nsReturnRef<T>|.
    34  *
    35  * For each class |T|, |nsAutoRefTraits<T>| or |nsSimpleRef<T>| must be
    36  * specialized to use |nsAutoRef<T>| and |nsCountedRef<T>|.
    37  *
    38  * @param T  A class identifying the type of reference held by the
    39  *           |nsAutoRef<T>| and the unique set methods for managing references
    40  *           to the resource (defined by |nsAutoRefTraits<T>| or
    41  *           |nsSimpleRef<T>|).
    42  *
    43  *           Often this is the class representing the resource.  Sometimes a
    44  *           new possibly-incomplete class may need to be declared.
    45  *
    46  *
    47  * Example:  An Automatically closing file descriptor
    48  *
    49  * // References that are simple integral types (as file-descriptors are)
    50  * // usually need a new class to represent the resource and how to handle its
    51  * // references.
    52  * class nsRawFD;
    53  *
    54  * // Specializing nsAutoRefTraits<nsRawFD> describes how to manage file
    55  * // descriptors, so that nsAutoRef<nsRawFD> provides automatic closing of
    56  * // its file descriptor on destruction.
    57  * template <>
    58  * class nsAutoRefTraits<nsRawFD> {
    59  * public:
    60  *     // The file descriptor is held in an int.
    61  *     typedef int RawRef;
    62  *     // -1 means that there is no file associated with the handle.
    63  *     static int Void() { return -1; }
    64  *     // The file associated with a file descriptor is released with close().
    65  *     static void Release(RawRef aFD) { close(aFD); }
    66  * };
    67  *
    68  * // A function returning a file descriptor that must be closed.
    69  * nsReturnRef<nsRawFD> get_file(const char *filename) {
    70  *     // Constructing from a raw file descriptor assumes ownership.
    71  *     nsAutoRef<nsRawFD> fd(open(filename, O_RDONLY));
    72  *     fcntl(fd, F_SETFD, FD_CLOEXEC);
    73  *     return fd.out();
    74  * }
    75  *
    76  * void f() {
    77  *     unsigned char buf[1024];
    78  *
    79  *     // Hold a file descriptor for /etc/hosts in fd1.
    80  *     nsAutoRef<nsRawFD> fd1(get_file("/etc/hosts"));
    81  *
    82  *     nsAutoRef<nsRawFD> fd2;
    83  *     fd2.steal(fd1); // fd2 takes the file descriptor from fd1
    84  *     ssize_t count = read(fd1, buf, 1024); // error fd1 has no file
    85  *     count = read(fd2, buf, 1024); // reads from /etc/hosts
    86  *
    87  *     // If the file descriptor is not stored then it is closed.
    88  *     get_file("/etc/login.defs"); // login.defs is closed
    89  *
    90  *     // Now use fd1 to hold a file descriptor for /etc/passwd.
    91  *     fd1 = get_file("/etc/passwd");
    92  *
    93  *     // The nsAutoRef<nsRawFD> can give up the file descriptor if explicitly
    94  *     // instructed, but the caller must then ensure that the file is closed.
    95  *     int rawfd = fd1.disown();
    96  *
    97  *     // Assume ownership of another file descriptor.
    98  *     fd1.own(open("/proc/1/maps");
    99  *
   100  *     // On destruction, fd1 closes /proc/1/maps and fd2 closes /etc/hosts,
   101  *     // but /etc/passwd is not closed.
   102  * }
   103  *
   104  */
   107 template <class T>
   108 class nsAutoRef : public nsAutoRefBase<T>
   109 {
   110 protected:
   111     typedef nsAutoRef<T> ThisClass;
   112     typedef nsAutoRefBase<T> BaseClass;
   113     typedef nsSimpleRef<T> SimpleRef;
   114     typedef typename BaseClass::RawRefOnly RawRefOnly;
   115     typedef typename BaseClass::LocalSimpleRef LocalSimpleRef;
   117 public:
   118     nsAutoRef()
   119     {
   120     }
   122     // Explicit construction is required so as not to risk unintentionally
   123     // releasing the resource associated with a raw ref.
   124     explicit nsAutoRef(RawRefOnly aRefToRelease)
   125         : BaseClass(aRefToRelease)
   126     {
   127     }
   129     // Construction from a nsReturnRef<T> function return value, which expects
   130     // to give up ownership, transfers ownership.
   131     // (nsReturnRef<T> is converted to const nsReturningRef<T>.)
   132     explicit nsAutoRef(const nsReturningRef<T>& aReturning)
   133         : BaseClass(aReturning)
   134     {
   135     }
   137     // The only assignment operator provided is for transferring from an
   138     // nsReturnRef smart reference, which expects to pass its ownership to
   139     // another object.
   140     //
   141     // With raw references and other smart references, the type of the lhs and
   142     // its taking and releasing nature is often not obvious from an assignment
   143     // statement.  Assignment from a raw ptr especially is not normally
   144     // expected to release the reference.
   145     //
   146     // Use |steal| for taking ownership from other smart refs.
   147     //
   148     // For raw references, use |own| to indicate intention to have the
   149     // resource released.
   150     //
   151     // Or, to create another owner of the same reference, use an nsCountedRef.
   153     ThisClass& operator=(const nsReturningRef<T>& aReturning)
   154     {
   155         BaseClass::steal(aReturning.mReturnRef);
   156         return *this;
   157     }
   159     // Conversion to a raw reference allow the nsAutoRef<T> to often be used
   160     // like a raw reference.
   161     operator typename SimpleRef::RawRef() const
   162     {
   163         return this->get();
   164     }
   166     // Transfer ownership from another smart reference.
   167     void steal(ThisClass& aOtherRef)
   168     {
   169         BaseClass::steal(aOtherRef);
   170     }
   172     // Assume ownership of a raw ref.
   173     //
   174     // |own| has similar function to |steal|, and is useful for receiving
   175     // ownership from a return value of a function.  It is named differently
   176     // because |own| requires more care to ensure that the function intends to
   177     // give away ownership, and so that |steal| can be safely used, knowing
   178     // that it won't steal ownership from any methods returning raw ptrs to
   179     // data owned by a foreign object.
   180     void own(RawRefOnly aRefToRelease)
   181     {
   182         BaseClass::own(aRefToRelease);
   183     }
   185     // Exchange ownership with |aOther|
   186     void swap(ThisClass& aOther)
   187     {
   188         LocalSimpleRef temp;
   189         temp.SimpleRef::operator=(*this);
   190         SimpleRef::operator=(aOther);
   191         aOther.SimpleRef::operator=(temp);
   192     }
   194     // Release the reference now.
   195     void reset()
   196     {
   197         this->SafeRelease();
   198         LocalSimpleRef empty;
   199         SimpleRef::operator=(empty);
   200     }
   202     // Pass out the reference for a function return values.
   203     nsReturnRef<T> out()
   204     {
   205         return nsReturnRef<T>(this->disown());
   206     }
   208     // operator->() and disown() are provided by nsAutoRefBase<T>.
   209     // The default nsSimpleRef<T> provides get().
   211 private:
   212     // No copy constructor
   213     explicit nsAutoRef(ThisClass& aRefToSteal);
   214 };
   216 /**
   217  * template <class T> class nsCountedRef
   218  *
   219  * A class that creates (adds) a new reference to a resource on construction
   220  * or assignment and releases on destruction.
   221  *
   222  * This class is similar to nsAutoRef<T> and inherits its methods, but also
   223  * provides copy construction and assignment operators that enable more than
   224  * one concurrent reference to the same resource.
   225  *
   226  * Specialize |nsAutoRefTraits<T>| or |nsSimpleRef<T>| to use this.  This
   227  * class assumes that the resource itself counts references and so can only be
   228  * used when |T| represents a reference-counting resource.
   229  */
   231 template <class T>
   232 class nsCountedRef : public nsAutoRef<T>
   233 {
   234 protected:
   235     typedef nsCountedRef<T> ThisClass;
   236     typedef nsAutoRef<T> BaseClass;
   237     typedef nsSimpleRef<T> SimpleRef;
   238     typedef typename BaseClass::RawRef RawRef;
   240 public:
   241     nsCountedRef()
   242     {
   243     }
   245     // Construction and assignment from a another nsCountedRef
   246     // or a raw ref copies and increments the ref count.
   247     nsCountedRef(const ThisClass& aRefToCopy)
   248     {
   249         SimpleRef::operator=(aRefToCopy);
   250         SafeAddRef();
   251     }
   252     ThisClass& operator=(const ThisClass& aRefToCopy)
   253     {
   254         if (this == &aRefToCopy)
   255             return *this;
   257         this->SafeRelease();
   258         SimpleRef::operator=(aRefToCopy);
   259         SafeAddRef();
   260         return *this;
   261     }
   263     // Implicit conversion from another smart ref argument (to a raw ref) is
   264     // accepted here because construction and assignment safely creates a new
   265     // reference without interfering with the reference to copy.
   266     explicit nsCountedRef(RawRef aRefToCopy)
   267         : BaseClass(aRefToCopy)
   268     {
   269         SafeAddRef();
   270     }
   271     ThisClass& operator=(RawRef aRefToCopy)
   272     {
   273         this->own(aRefToCopy);
   274         SafeAddRef();
   275         return *this;
   276     }
   278     // Construction and assignment from an nsReturnRef function return value,
   279     // which expects to give up ownership, transfers ownership.
   280     explicit nsCountedRef(const nsReturningRef<T>& aReturning)
   281         : BaseClass(aReturning)
   282     {
   283     }
   284     ThisClass& operator=(const nsReturningRef<T>& aReturning)
   285     {
   286         BaseClass::operator=(aReturning);
   287         return *this;
   288     }
   290 protected:
   291     // Increase the reference count if there is a resource.
   292     void SafeAddRef()
   293     {
   294         if (this->HaveResource())
   295             this->AddRef(this->get());
   296     }
   297 };
   299 /**
   300  * template <class T> class nsReturnRef
   301  *
   302  * A type for function return values that hold a reference to a resource that
   303  * must be released.  See also |nsAutoRef<T>::out()|.
   304  */
   306 template <class T>
   307 class nsReturnRef : public nsAutoRefBase<T>
   308 {
   309 protected:
   310     typedef nsAutoRefBase<T> BaseClass;
   311     typedef typename BaseClass::RawRefOnly RawRefOnly;
   313 public:
   314     // For constructing a return value with no resource
   315     nsReturnRef()
   316     {
   317     }
   319     // For returning a smart reference from a raw reference that must be
   320     // released.  Explicit construction is required so as not to risk
   321     // unintentionally releasing the resource associated with a raw ref.
   322     explicit nsReturnRef(RawRefOnly aRefToRelease)
   323         : BaseClass(aRefToRelease)
   324     {
   325     }
   327     // Copy construction transfers ownership
   328     nsReturnRef(nsReturnRef<T>& aRefToSteal)
   329         : BaseClass(aRefToSteal)
   330     {
   331     }
   333     nsReturnRef(const nsReturningRef<T>& aReturning)
   334         : BaseClass(aReturning)
   335     {
   336     }
   338     // Conversion to a temporary (const) object referring to this object so
   339     // that the reference may be passed from a function return value
   340     // (temporary) to another smart reference.  There is no need to use this
   341     // explicitly.  Simply assign a nsReturnRef<T> function return value to a
   342     // smart reference.
   343     operator nsReturningRef<T>()
   344     {
   345         return nsReturningRef<T>(*this);
   346     }
   348     // No conversion to RawRef operator is provided on nsReturnRef, to ensure
   349     // that the return value is not carelessly assigned to a raw ptr (and the
   350     // resource then released).  If passing to a function that takes a raw
   351     // ptr, use get or disown as appropriate.
   352 };
   354 /**
   355  * template <class T> class nsReturningRef
   356  *
   357  * A class to allow ownership to be transferred from nsReturnRef function
   358  * return values.
   359  *
   360  * It should not be necessary for clients to reference this
   361  * class directly.  Simply pass an nsReturnRef<T> to a parameter taking an
   362  * |nsReturningRef<T>|.
   363  *
   364  * The conversion operator on nsReturnRef constructs a temporary wrapper of
   365  * class nsReturningRef<T> around a non-const reference to the nsReturnRef.
   366  * The wrapper can then be passed as an rvalue parameter.
   367  */
   369 template <class T>
   370 class nsReturningRef
   371 {
   372 private:
   373     friend class nsReturnRef<T>;
   375     explicit nsReturningRef(nsReturnRef<T>& aReturnRef)
   376         : mReturnRef(aReturnRef)
   377     {
   378     }
   379 public:
   380     nsReturnRef<T>& mReturnRef;
   381 };
   383 /**
   384  * template <class T> class nsAutoRefTraits
   385  *
   386  * A class describing traits of references managed by the default
   387  * |nsSimpleRef<T>| implementation and thus |nsAutoRef<T>| and |nsCountedRef|.
   388  * The default |nsSimpleRef<T> is suitable for resources with handles that
   389  * have a void value.  (If there is no such void value for a handle,
   390  * specialize |nsSimpleRef<T>|.)
   391  *
   392  * Specializations must be provided for each class |T| according to the
   393  * following pattern:
   394  *
   395  * // The template parameter |T| should be a class such that the set of fields
   396  * // in class nsAutoRefTraits<T> is unique for class |T|.  Usually the
   397  * // resource object class is sufficient.  For handles that are simple
   398  * // integral typedefs, a new unique possibly-incomplete class may need to be
   399  * // declared.
   400  *
   401  * template <>
   402  * class nsAutoRefTraits<T>
   403  * {
   404  *     // Specializations must provide a typedef for RawRef, describing the
   405  *     // type of the handle to the resource.
   406  *     typedef <handle-type> RawRef;
   407  *
   408  *     // Specializations should define Void(), a function returning a value
   409  *     // suitable for a handle that does not have an associated resource.
   410  *     //
   411  *     // The return type must be a suitable as the parameter to a RawRef
   412  *     // constructor and operator==.
   413  *     //
   414  *     // If this method is not accessible then some limited nsAutoRef
   415  *     // functionality will still be available, but the default constructor,
   416  *     // |reset|, and most transfer of ownership methods will not be available.
   417  *     static <return-type> Void();
   418  *
   419  *     // Specializations must define Release() to properly finalize the
   420  *     // handle to a non-void custom-deleted or reference-counted resource.
   421  *     static void Release(RawRef aRawRef);
   422  *
   423  *     // For reference-counted resources, if |nsCountedRef<T>| is to be used,
   424  *     // specializations must define AddRef to increment the reference count
   425  *     // held by a non-void handle.
   426  *     // (AddRef() is not necessary for |nsAutoRef<T>|.)
   427  *     static void AddRef(RawRef aRawRef);
   428  * };
   429  *
   430  * See nsPointerRefTraits for example specializations for simple pointer
   431  * references.  See nsAutoRef for an example specialization for a non-pointer
   432  * reference.
   433  */
   435 template <class T> class nsAutoRefTraits;
   437 /**
   438  * template <class T> class nsPointerRefTraits
   439  *
   440  * A convenience class useful as a base class for specializations of
   441  * |nsAutoRefTraits<T>| where the handle to the resource is a pointer to |T|.
   442  * By inheriting from this class, definitions of only Release(RawRef) and
   443  * possibly AddRef(RawRef) need to be added.
   444  *
   445  * Examples of use:
   446  *
   447  * template <>
   448  * class nsAutoRefTraits<PRFileDesc> : public nsPointerRefTraits<PRFileDesc>
   449  * {
   450  * public:
   451  *     static void Release(PRFileDesc *ptr) { PR_Close(ptr); }
   452  * };
   453  *
   454  * template <>
   455  * class nsAutoRefTraits<FcPattern> : public nsPointerRefTraits<FcPattern>
   456  * {
   457  * public:
   458  *     static void Release(FcPattern *ptr) { FcPatternDestroy(ptr); }
   459  *     static void AddRef(FcPattern *ptr) { FcPatternReference(ptr); }
   460  * };
   461  */
   463 template <class T>
   464 class nsPointerRefTraits
   465 {
   466 public:
   467     // The handle is a pointer to T.
   468     typedef T* RawRef;
   469     // A nullptr does not have a resource.
   470     static RawRef Void() { return nullptr; }
   471 };
   473 /**
   474  * template <class T> class nsSimpleRef
   475  *
   476  * Constructs a non-smart reference, and provides methods to test whether
   477  * there is an associated resource and (if so) get its raw handle.
   478  *
   479  * A default implementation is suitable for resources with handles that have a
   480  * void value.  This is not intended for direct use but used by |nsAutoRef<T>|
   481  * and thus |nsCountedRef<T>|.
   482  *
   483  * Specialize this class if there is no particular void value for the resource
   484  * handle.  A specialized implementation must also provide Release(RawRef),
   485  * and, if |nsCountedRef<T>| is required, AddRef(RawRef), as described in
   486  * nsAutoRefTraits<T>.
   487  */
   489 template <class T>
   490 class nsSimpleRef : protected nsAutoRefTraits<T>
   491 {
   492 protected:
   493     // The default implementation uses nsAutoRefTrait<T>.
   494     // Specializations need not define this typedef.
   495     typedef nsAutoRefTraits<T> Traits;
   496     // The type of the handle to the resource.
   497     // A specialization must provide a typedef for RawRef.
   498     typedef typename Traits::RawRef RawRef;
   500     // Construct with no resource.
   501     //
   502     // If this constructor is not accessible then some limited nsAutoRef
   503     // functionality will still be available, but the default constructor,
   504     // |reset|, and most transfer of ownership methods will not be available.
   505     nsSimpleRef()
   506         : mRawRef(Traits::Void())
   507     {
   508     }
   509     // Construct with a handle to a resource.
   510     // A specialization must provide this. 
   511     nsSimpleRef(RawRef aRawRef)
   512         : mRawRef(aRawRef)
   513     {
   514     }
   516     // Test whether there is an associated resource.  A specialization must
   517     // provide this.  The function is permitted to always return true if the
   518     // default constructor is not accessible, or if Release (and AddRef) can
   519     // deal with void handles.
   520     bool HaveResource() const
   521     {
   522         return mRawRef != Traits::Void();
   523     }
   525 public:
   526     // A specialization must provide get() or loose some functionality.  This
   527     // is inherited by derived classes and the specialization may choose
   528     // whether it is public or protected.
   529     RawRef get() const
   530     {
   531         return mRawRef;
   532     }
   534 private:
   535     RawRef mRawRef;
   536 };
   539 /**
   540  * template <class T> class nsAutoRefBase
   541  *
   542  * Internal base class for |nsAutoRef<T>| and |nsReturnRef<T>|.
   543  * Adds release on destruction to a |nsSimpleRef<T>|.
   544  */
   546 template <class T>
   547 class nsAutoRefBase : public nsSimpleRef<T>
   548 {
   549 protected:
   550     typedef nsAutoRefBase<T> ThisClass;
   551     typedef nsSimpleRef<T> SimpleRef;
   552     typedef typename SimpleRef::RawRef RawRef;
   554     nsAutoRefBase()
   555     {
   556     }
   558     // A type for parameters that should be passed a raw ref but should not
   559     // accept implicit conversions (from another smart ref).  (The only
   560     // conversion to this type is from a raw ref so only raw refs will be
   561     // accepted.)
   562     class RawRefOnly
   563     {
   564     public:
   565         RawRefOnly(RawRef aRawRef)
   566             : mRawRef(aRawRef)
   567         {
   568         }
   569         operator RawRef() const
   570         {
   571             return mRawRef;
   572         }
   573     private:
   574         RawRef mRawRef;
   575     };
   577     // Construction from a raw ref assumes ownership
   578     explicit nsAutoRefBase(RawRefOnly aRefToRelease)
   579         : SimpleRef(aRefToRelease)
   580     {
   581     }
   583     // Constructors that steal ownership
   584     explicit nsAutoRefBase(ThisClass& aRefToSteal)
   585         : SimpleRef(aRefToSteal.disown())
   586     {
   587     }
   588     explicit nsAutoRefBase(const nsReturningRef<T>& aReturning)
   589         : SimpleRef(aReturning.mReturnRef.disown())
   590     {
   591     }
   593     ~nsAutoRefBase()
   594     {
   595         SafeRelease();
   596     }
   598     // An internal class providing access to protected nsSimpleRef<T>
   599     // constructors for construction of temporary simple references (that are
   600     // not ThisClass).
   601     class LocalSimpleRef : public SimpleRef
   602     {
   603     public:
   604         LocalSimpleRef()
   605         {
   606         }
   607         explicit LocalSimpleRef(RawRef aRawRef)
   608             : SimpleRef(aRawRef)
   609         {
   610         }
   611     };
   613 private:
   614     ThisClass& operator=(const ThisClass& aSmartRef) MOZ_DELETE;
   616 public:
   617     RawRef operator->() const
   618     {
   619         return this->get();
   620     }
   622     // Transfer ownership to a raw reference.
   623     //
   624     // THE CALLER MUST ENSURE THAT THE REFERENCE IS EXPLICITLY RELEASED.
   625     //
   626     // Is this really what you want to use?  Using this removes any guarantee
   627     // of release.  Use nsAutoRef<T>::out() for return values, or an
   628     // nsAutoRef<T> modifiable lvalue for an out parameter.  Use disown() when
   629     // the reference must be stored in a POD type object, such as may be
   630     // preferred for a namespace-scope object with static storage duration,
   631     // for example.
   632     RawRef disown()
   633     {
   634         RawRef temp = this->get();
   635         LocalSimpleRef empty;
   636         SimpleRef::operator=(empty);
   637         return temp;
   638     }
   640 protected:
   641     // steal and own are protected because they make no sense on nsReturnRef,
   642     // but steal is implemented on this class for access to aOtherRef.disown()
   643     // when aOtherRef is an nsReturnRef;
   645     // Transfer ownership from another smart reference.
   646     void steal(ThisClass& aOtherRef)
   647     {
   648         own(aOtherRef.disown());
   649     }
   650     // Assume ownership of a raw ref.
   651     void own(RawRefOnly aRefToRelease)
   652     {
   653         SafeRelease();
   654         LocalSimpleRef ref(aRefToRelease);
   655         SimpleRef::operator=(ref);
   656     }
   658     // Release a resource if there is one.
   659     void SafeRelease()
   660     {
   661         if (this->HaveResource())
   662             this->Release(this->get());
   663     }
   664 };
   666 #endif // !defined(nsAutoRef_h_)

mercurial