LCOV - code coverage report
Current view: top level - mfbt - AlreadyAddRefed.h (source / functions) Hit Total Coverage
Test: output.info Lines: 18 18 100.0 %
Date: 2017-07-14 16:53:18 Functions: 1825 11321 16.1 %
Legend: Lines: hit not hit

          Line data    Source code
       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             : 
       7             : /* Typed temporary pointers for reference-counted smart pointers. */
       8             : 
       9             : #ifndef AlreadyAddRefed_h
      10             : #define AlreadyAddRefed_h
      11             : 
      12             : #include "mozilla/Assertions.h"
      13             : #include "mozilla/Attributes.h"
      14             : #include "mozilla/Move.h"
      15             : 
      16             : namespace mozilla {
      17             : 
      18             : struct unused_t;
      19             : 
      20             : } // namespace mozilla
      21             : 
      22             : /**
      23             :  * already_AddRefed cooperates with reference counting smart pointers to enable
      24             :  * you to assign in a pointer _without_ |AddRef|ing it.  You might want to use
      25             :  * this as a return type from a function that returns an already |AddRef|ed
      26             :  * pointer.
      27             :  *
      28             :  * TODO Move already_AddRefed to namespace mozilla.  This has not yet been done
      29             :  * because of the sheer number of usages of already_AddRefed.
      30             :  *
      31             :  * When should you use already_AddRefed<>?
      32             :  * * Ensure a consumer takes ownership of a reference
      33             :  * * Pass ownership without calling AddRef/Release (sometimes required in
      34             :  *   off-main-thread code)
      35             :  * * The ref pointer type you're using doesn't support move construction
      36             :  *
      37             :  * Otherwise, use Move(RefPtr/nsCOMPtr/etc).
      38             :  */
      39             : template<class T>
      40             : struct MOZ_MUST_USE_TYPE MOZ_NON_AUTOABLE already_AddRefed
      41             : {
      42             :   /*
      43             :    * We want to allow returning nullptr from functions returning
      44             :    * already_AddRefed<T>, for simplicity.  But we also don't want to allow
      45             :    * returning raw T*, instead preferring creation of already_AddRefed<T> from
      46             :    * a reference counting smart pointer.
      47             :    *
      48             :    * We address the latter requirement by making the (T*) constructor explicit.
      49             :    * But |return nullptr| won't consider an explicit constructor, so we need
      50             :    * another constructor to handle it.  Plain old (decltype(nullptr)) doesn't
      51             :    * cut it, because if nullptr is emulated as __null (with type int or long),
      52             :    * passing nullptr to an int/long parameter triggers compiler warnings.  We
      53             :    * need a type that no one can pass accidentally; a pointer-to-member-function
      54             :    * (where no such function exists) does the trick nicely.
      55             :    *
      56             :    * That handles the return-value case.  What about for locals, argument types,
      57             :    * and so on?  |already_AddRefed<T>(nullptr)| considers both overloads (and
      58             :    * the (already_AddRefed<T>&&) overload as well!), so there's an ambiguity.
      59             :    * We can target true nullptr using decltype(nullptr), but we can't target
      60             :    * emulated nullptr the same way, because passing __null to an int/long
      61             :    * parameter triggers compiler warnings.  So just give up on this, and provide
      62             :    * this behavior through the default constructor.
      63             :    *
      64             :    * We can revert to simply explicit (T*) and implicit (decltype(nullptr)) when
      65             :    * nullptr no longer needs to be emulated to support the ancient b2g compiler.
      66             :    * (The () overload could also be removed, if desired, if we changed callers.)
      67             :    */
      68           3 :   already_AddRefed() : mRawPtr(nullptr) {}
      69             : 
      70        7815 :   MOZ_IMPLICIT already_AddRefed(decltype(nullptr)) : mRawPtr(nullptr) {}
      71             : 
      72      304276 :   explicit already_AddRefed(T* aRawPtr) : mRawPtr(aRawPtr) {}
      73             : 
      74             :   // Disallow copy constructor and copy assignment operator: move semantics used instead.
      75             :   already_AddRefed(const already_AddRefed<T>& aOther) = delete;
      76             :   already_AddRefed<T>& operator=(const already_AddRefed<T>& aOther) = delete;
      77             : 
      78        7405 :   already_AddRefed(already_AddRefed<T>&& aOther) : mRawPtr(aOther.take()) {}
      79             : 
      80             :   already_AddRefed<T>& operator=(already_AddRefed<T>&& aOther)
      81             :   {
      82             :     mRawPtr = aOther.take();
      83             :     return *this;
      84             :   }
      85             : 
      86             :   /**
      87             :    * This helper is useful in cases like
      88             :    *
      89             :    *  already_AddRefed<BaseClass>
      90             :    *  Foo()
      91             :    *  {
      92             :    *    RefPtr<SubClass> x = ...;
      93             :    *    return x.forget();
      94             :    *  }
      95             :    *
      96             :    * The autoconversion allows one to omit the idiom
      97             :    *
      98             :    *    RefPtr<BaseClass> y = x.forget();
      99             :    *    return y.forget();
     100             :    *
     101             :    * Note that nsRefPtr is the XPCOM reference counting smart pointer class.
     102             :    */
     103             :   template <typename U>
     104        7503 :   MOZ_IMPLICIT already_AddRefed(already_AddRefed<U>&& aOther) : mRawPtr(aOther.take()) {}
     105             : 
     106      327003 :   ~already_AddRefed() { MOZ_ASSERT(!mRawPtr); }
     107             : 
     108             :   // Specialize the unused operator<< for already_AddRefed, to allow
     109             :   // nsCOMPtr<nsIFoo> foo;
     110             :   // Unused << foo.forget();
     111             :   // Note that nsCOMPtr is the XPCOM reference counting smart pointer class.
     112        2856 :   friend void operator<<(const mozilla::unused_t& aUnused,
     113             :                          const already_AddRefed<T>& aRhs)
     114             :   {
     115        2856 :     auto mutableAlreadyAddRefed = const_cast<already_AddRefed<T>*>(&aRhs);
     116        2856 :     aUnused << mutableAlreadyAddRefed->take();
     117        2856 :   }
     118             : 
     119      326673 :   MOZ_MUST_USE T* take()
     120             :   {
     121      326673 :     T* rawPtr = mRawPtr;
     122      326673 :     mRawPtr = nullptr;
     123      326673 :     return rawPtr;
     124             :   }
     125             : 
     126             :   /**
     127             :    * This helper provides a static_cast replacement for already_AddRefed, so
     128             :    * if you have
     129             :    *
     130             :    *   already_AddRefed<Parent> F();
     131             :    *
     132             :    * you can write
     133             :    *
     134             :    *   already_AddRefed<Child>
     135             :    *   G()
     136             :    *   {
     137             :    *     return F().downcast<Child>();
     138             :    *   }
     139             :    */
     140             :   template<class U>
     141         374 :   already_AddRefed<U> downcast()
     142             :   {
     143         374 :     U* tmp = static_cast<U*>(mRawPtr);
     144         374 :     mRawPtr = nullptr;
     145         374 :     return already_AddRefed<U>(tmp);
     146             :   }
     147             : 
     148             : private:
     149             :   T* MOZ_OWNING_REF mRawPtr;
     150             : };
     151             : 
     152             : #endif // AlreadyAddRefed_h

Generated by: LCOV version 1.13