LCOV - code coverage report
Current view: directory - objdir/dist/include/mozilla - RefPtr.h (source / functions) Found Hit Coverage
Test: app.info Lines: 54 6 11.1 %
Date: 2012-06-02 Functions: 211 16 7.6 %

       1                 : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
       2                 :  * vim: set ts=8 sw=4 et tw=99 ft=cpp:
       3                 :  *
       4                 :  * ***** BEGIN LICENSE BLOCK *****
       5                 :  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
       6                 :  *
       7                 :  * The contents of this file are subject to the Mozilla Public License Version
       8                 :  * 1.1 (the "License"); you may not use this file except in compliance with
       9                 :  * the License. You may obtain a copy of the License at:
      10                 :  * http://www.mozilla.org/MPL/
      11                 :  *
      12                 :  * Software distributed under the License is distributed on an "AS IS" basis,
      13                 :  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
      14                 :  * for the specific language governing rights and limitations under the
      15                 :  * License.
      16                 :  *
      17                 :  * The Original Code is Mozilla Code.
      18                 :  *
      19                 :  * The Initial Developer of the Original Code is
      20                 :  *   The Mozilla Foundation
      21                 :  * Portions created by the Initial Developer are Copyright (C) 2011
      22                 :  * the Initial Developer. All Rights Reserved.
      23                 :  *
      24                 :  * Contributor(s):
      25                 :  *   Chris Jones <jones.chris.g@gmail.com>
      26                 :  *
      27                 :  * Alternatively, the contents of this file may be used under the terms of
      28                 :  * either the GNU General Public License Version 2 or later (the "GPL"), or
      29                 :  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
      30                 :  * in which case the provisions of the GPL or the LGPL are applicable instead
      31                 :  * of those above. If you wish to allow use of your version of this file only
      32                 :  * under the terms of either the GPL or the LGPL, and not to allow others to
      33                 :  * use your version of this file under the terms of the MPL, indicate your
      34                 :  * decision by deleting the provisions above and replace them with the notice
      35                 :  * and other provisions required by the GPL or the LGPL. If you do not delete
      36                 :  * the provisions above, a recipient may use your version of this file under
      37                 :  * the terms of any one of the MPL, the GPL or the LGPL.
      38                 :  *
      39                 :  * ***** END LICENSE BLOCK ***** */
      40                 : 
      41                 : /* Helpers for defining and using refcounted objects. */
      42                 : 
      43                 : #ifndef mozilla_RefPtr_h_
      44                 : #define mozilla_RefPtr_h_
      45                 : 
      46                 : #include "mozilla/Assertions.h"
      47                 : #include "mozilla/Attributes.h"
      48                 : 
      49                 : namespace mozilla {
      50                 : 
      51                 : template<typename T> class RefCounted;
      52                 : template<typename T> class RefPtr;
      53                 : template<typename T> class TemporaryRef;
      54                 : template<typename T> class OutParamRef;
      55                 : template<typename T> OutParamRef<T> byRef(RefPtr<T>&);
      56                 : 
      57                 : /**
      58                 :  * RefCounted<T> is a sort of a "mixin" for a class T.  RefCounted
      59                 :  * manages, well, refcounting for T, and because RefCounted is
      60                 :  * parameterized on T, RefCounted<T> can call T's destructor directly.
      61                 :  * This means T doesn't need to have a virtual dtor and so doesn't
      62                 :  * need a vtable.
      63                 :  *
      64                 :  * RefCounted<T> is created with refcount == 0.  Newly-allocated
      65                 :  * RefCounted<T> must immediately be assigned to a RefPtr to make the
      66                 :  * refcount > 0.  It's an error to allocate and free a bare
      67                 :  * RefCounted<T>, i.e. outside of the RefPtr machinery.  Attempts to
      68                 :  * do so will abort DEBUG builds.
      69                 :  *
      70                 :  * Live RefCounted<T> have refcount > 0.  The lifetime (refcounts) of
      71                 :  * live RefCounted<T> are controlled by RefPtr<T> and
      72                 :  * RefPtr<super/subclass of T>.  Upon a transition from refcounted==1
      73                 :  * to 0, the RefCounted<T> "dies" and is destroyed.  The "destroyed"
      74                 :  * state is represented in DEBUG builds by refcount==-0xdead.  This
      75                 :  * state distinguishes use-before-ref (refcount==0) from
      76                 :  * use-after-destroy (refcount==-0xdead).
      77                 :  */
      78                 : template<typename T>
      79                 : class RefCounted
      80                 : {
      81                 :     friend class RefPtr<T>;
      82                 : 
      83                 : public:
      84               0 :     RefCounted() : refCnt(0) { }
      85               0 :     ~RefCounted() { MOZ_ASSERT(refCnt == -0xdead); }
      86                 : 
      87                 :     // Compatibility with nsRefPtr.
      88               0 :     void AddRef() {
      89               0 :         MOZ_ASSERT(refCnt >= 0);
      90               0 :         ++refCnt;
      91               0 :     }
      92                 : 
      93               0 :     void Release() {
      94               0 :         MOZ_ASSERT(refCnt > 0);
      95               0 :         if (0 == --refCnt) {
      96                 : #ifdef DEBUG
      97               0 :             refCnt = -0xdead;
      98                 : #endif
      99               0 :             delete static_cast<T*>(this);
     100                 :         }
     101               0 :     }
     102                 : 
     103                 :     // Compatibility with wtf::RefPtr.
     104                 :     void ref() { AddRef(); }
     105                 :     void deref() { Release(); }
     106                 :     int refCount() const { return refCnt; }
     107                 :     bool hasOneRef() const {
     108                 :         MOZ_ASSERT(refCnt > 0);
     109                 :         return refCnt == 1;
     110                 :     }
     111                 : 
     112                 : private:
     113                 :     int refCnt;
     114                 : };
     115                 : 
     116                 : /**
     117                 :  * RefPtr points to a refcounted thing that has AddRef and Release
     118                 :  * methods to increase/decrease the refcount, respectively.  After a
     119                 :  * RefPtr<T> is assigned a T*, the T* can be used through the RefPtr
     120                 :  * as if it were a T*.
     121                 :  *
     122                 :  * A RefPtr can forget its underlying T*, which results in the T*
     123                 :  * being wrapped in a temporary object until the T* is either
     124                 :  * re-adopted from or released by the temporary.
     125                 :  */
     126                 : template<typename T>
     127                 : class RefPtr
     128                 : {
     129                 :     // To allow them to use unref()
     130                 :     friend class TemporaryRef<T>;
     131                 :     friend class OutParamRef<T>;
     132                 : 
     133                 :     struct dontRef {};
     134                 : 
     135                 : public:
     136             294 :     RefPtr() : ptr(0) { }
     137               0 :     RefPtr(const RefPtr& o) : ptr(ref(o.ptr)) {}
     138               0 :     RefPtr(const TemporaryRef<T>& o) : ptr(o.drop()) {}
     139               0 :     RefPtr(T* t) : ptr(ref(t)) {}
     140                 : 
     141                 :     template<typename U>
     142                 :     RefPtr(const RefPtr<U>& o) : ptr(ref(o.get())) {}
     143                 : 
     144             294 :     ~RefPtr() { unref(ptr); }
     145                 : 
     146               0 :     RefPtr& operator=(const RefPtr& o) {
     147               0 :         assign(ref(o.ptr));
     148               0 :         return *this;
     149                 :     }
     150               0 :     RefPtr& operator=(const TemporaryRef<T>& o) {
     151               0 :         assign(o.drop());
     152               0 :         return *this;
     153                 :     }
     154               0 :     RefPtr& operator=(T* t) {
     155               0 :         assign(ref(t));
     156               0 :         return *this;
     157                 :     }
     158                 : 
     159                 :     template<typename U>
     160                 :     RefPtr& operator=(const RefPtr<U>& o) {
     161                 :         assign(ref(o.get()));
     162                 :         return *this;
     163                 :     }
     164                 : 
     165               0 :     TemporaryRef<T> forget() {
     166               0 :         T* tmp = ptr;
     167               0 :         ptr = 0;
     168               0 :         return TemporaryRef<T>(tmp, dontRef());
     169                 :     }
     170                 : 
     171               0 :     T* get() const { return ptr; }
     172              64 :     operator T*() const { return ptr; }
     173               0 :     T* operator->() const { return ptr; }
     174               0 :     T& operator*() const { return *ptr; }
     175                 :     template<typename U>
     176               0 :     operator TemporaryRef<U>() { return TemporaryRef<U>(ptr); }
     177                 : 
     178                 : private:
     179               0 :     void assign(T* t) {
     180               0 :         unref(ptr);
     181               0 :         ptr = t;
     182               0 :     }
     183                 : 
     184                 :     T* ptr;
     185                 : 
     186               0 :     static MOZ_ALWAYS_INLINE T* ref(T* t) {
     187               0 :         if (t) {
     188               0 :             t->AddRef();
     189                 :         }
     190               0 :         return t;
     191                 :     }
     192                 : 
     193             294 :     static MOZ_ALWAYS_INLINE void unref(T* t) {
     194             294 :         if (t) {
     195               0 :             t->Release();
     196                 :         }
     197             294 :     }
     198                 : };
     199                 : 
     200                 : /**
     201                 :  * TemporaryRef<T> represents an object that holds a temporary
     202                 :  * reference to a T.  TemporaryRef objects can't be manually ref'd or
     203                 :  * unref'd (being temporaries, not lvalues), so can only relinquish
     204                 :  * references to other objects, or unref on destruction.
     205                 :  */
     206                 : template<typename T>
     207                 : class TemporaryRef
     208                 : {
     209                 :     // To allow it to construct TemporaryRef from a bare T*
     210                 :     friend class RefPtr<T>;
     211                 : 
     212                 :     typedef typename RefPtr<T>::dontRef dontRef;
     213                 : 
     214                 : public:
     215               0 :     TemporaryRef(T* t) : ptr(RefPtr<T>::ref(t)) {}
     216                 :     TemporaryRef(const TemporaryRef& o) : ptr(o.drop()) {}
     217                 : 
     218                 :     template<typename U>
     219                 :     TemporaryRef(const TemporaryRef<U>& o) : ptr(o.drop()) {}
     220                 : 
     221               0 :     ~TemporaryRef() { RefPtr<T>::unref(ptr); }
     222                 : 
     223               0 :     T* drop() const {
     224               0 :         T* tmp = ptr;
     225               0 :         ptr = 0;
     226               0 :         return tmp;
     227                 :     }
     228                 : 
     229                 : private:
     230               0 :     TemporaryRef(T* t, const dontRef&) : ptr(t) {}
     231                 : 
     232                 :     mutable T* ptr;
     233                 : 
     234                 :     TemporaryRef();
     235                 :     TemporaryRef& operator=(const TemporaryRef&);
     236                 : };
     237                 : 
     238                 : /**
     239                 :  * OutParamRef is a wrapper that tracks a refcounted pointer passed as
     240                 :  * an outparam argument to a function.  OutParamRef implements COM T**
     241                 :  * outparam semantics: this requires the callee to AddRef() the T*
     242                 :  * returned through the T** outparam on behalf of the caller.  This
     243                 :  * means the caller (through OutParamRef) must Release() the old
     244                 :  * object contained in the tracked RefPtr.  It's OK if the callee
     245                 :  * returns the same T* passed to it through the T** outparam, as long
     246                 :  * as the callee obeys the COM discipline.
     247                 :  *
     248                 :  * Prefer returning TemporaryRef<T> from functions over creating T**
     249                 :  * outparams and passing OutParamRef<T> to T**.  Prefer RefPtr<T>*
     250                 :  * outparams over T** outparams.
     251                 :  */
     252                 : template<typename T>
     253                 : class OutParamRef
     254                 : {
     255                 :     friend OutParamRef byRef<T>(RefPtr<T>&);
     256                 : 
     257                 : public:
     258                 :     ~OutParamRef() {
     259                 :         RefPtr<T>::unref(refPtr.ptr);
     260                 :         refPtr.ptr = tmp;
     261                 :     }
     262                 : 
     263                 :     operator T**() { return &tmp; }
     264                 : 
     265                 : private:
     266                 :     OutParamRef(RefPtr<T>& p) : refPtr(p), tmp(p.get()) {}
     267                 : 
     268                 :     RefPtr<T>& refPtr;
     269                 :     T* tmp;
     270                 : 
     271                 :     OutParamRef() MOZ_DELETE;
     272                 :     OutParamRef& operator=(const OutParamRef&) MOZ_DELETE;
     273                 : };
     274                 : 
     275                 : /**
     276                 :  * byRef cooperates with OutParamRef to implement COM outparam semantics.
     277                 :  */
     278                 : template<typename T>
     279                 : OutParamRef<T>
     280                 : byRef(RefPtr<T>& ptr)
     281                 : {
     282                 :     return OutParamRef<T>(ptr);
     283                 : }
     284                 : 
     285                 : } // namespace mozilla
     286                 : 
     287                 : #endif // mozilla_RefPtr_h_
     288                 : 
     289                 : 
     290                 : #if 0
     291                 : 
     292                 : // Command line that builds these tests
     293                 : //
     294                 : //   cp RefPtr.h test.cc && g++ -g -Wall -pedantic -DDEBUG -o test test.cc && ./test
     295                 : 
     296                 : using namespace mozilla;
     297                 : 
     298                 : struct Foo : public RefCounted<Foo>
     299                 : {
     300                 :     Foo() : dead(false) { }
     301                 :     ~Foo() {
     302                 :         MOZ_ASSERT(!dead);
     303                 :         dead = true;
     304                 :         numDestroyed++;
     305                 :     }
     306                 : 
     307                 :     bool dead;
     308                 :     static int numDestroyed;
     309                 : };
     310                 : int Foo::numDestroyed;
     311                 : 
     312                 : struct Bar : public Foo { };
     313                 : 
     314                 : TemporaryRef<Foo>
     315                 : NewFoo()
     316                 : {
     317                 :     return RefPtr<Foo>(new Foo());
     318                 : }
     319                 : 
     320                 : TemporaryRef<Foo>
     321                 : NewBar()
     322                 : {
     323                 :     return new Bar();
     324                 : }
     325                 : 
     326                 : void
     327                 : GetNewFoo(Foo** f)
     328                 : {
     329                 :     *f = new Bar();
     330                 :     // Kids, don't try this at home
     331                 :     (*f)->AddRef();
     332                 : }
     333                 : 
     334                 : void
     335                 : GetPassedFoo(Foo** f)
     336                 : {
     337                 :     // Kids, don't try this at home
     338                 :     (*f)->AddRef();
     339                 : }
     340                 : 
     341                 : void
     342                 : GetNewFoo(RefPtr<Foo>* f)
     343                 : {
     344                 :     *f = new Bar();
     345                 : }
     346                 : 
     347                 : void
     348                 : GetPassedFoo(RefPtr<Foo>* f)
     349                 : {}
     350                 : 
     351                 : TemporaryRef<Foo>
     352                 : GetNullFoo()
     353                 : {
     354                 :     return 0;
     355                 : }
     356                 : 
     357                 : int
     358                 : main(int argc, char** argv)
     359                 : {
     360                 :     // This should blow up
     361                 : //    Foo* f = new Foo(); delete f;
     362                 : 
     363                 :     MOZ_ASSERT(0 == Foo::numDestroyed);
     364                 :     {
     365                 :         RefPtr<Foo> f = new Foo();
     366                 :         MOZ_ASSERT(f->refCount() == 1);
     367                 :     }
     368                 :     MOZ_ASSERT(1 == Foo::numDestroyed);
     369                 : 
     370                 :     {
     371                 :         RefPtr<Foo> f1 = NewFoo();
     372                 :         RefPtr<Foo> f2(NewFoo());
     373                 :         MOZ_ASSERT(1 == Foo::numDestroyed);
     374                 :     }
     375                 :     MOZ_ASSERT(3 == Foo::numDestroyed);
     376                 : 
     377                 :     {
     378                 :         RefPtr<Foo> b = NewBar();
     379                 :         MOZ_ASSERT(3 == Foo::numDestroyed);
     380                 :     }
     381                 :     MOZ_ASSERT(4 == Foo::numDestroyed);
     382                 : 
     383                 :     {
     384                 :         RefPtr<Foo> f1;
     385                 :         {
     386                 :             f1 = new Foo();
     387                 :             RefPtr<Foo> f2(f1);
     388                 :             RefPtr<Foo> f3 = f2;
     389                 :             MOZ_ASSERT(4 == Foo::numDestroyed);
     390                 :         }
     391                 :         MOZ_ASSERT(4 == Foo::numDestroyed);
     392                 :     }
     393                 :     MOZ_ASSERT(5 == Foo::numDestroyed);
     394                 : 
     395                 :     {
     396                 :         RefPtr<Foo> f = new Foo();
     397                 :         f.forget();
     398                 :         MOZ_ASSERT(6 == Foo::numDestroyed);
     399                 :     }
     400                 : 
     401                 :     {
     402                 :         RefPtr<Foo> f = new Foo();
     403                 :         GetNewFoo(byRef(f));
     404                 :         MOZ_ASSERT(7 == Foo::numDestroyed);
     405                 :     }
     406                 :     MOZ_ASSERT(8 == Foo::numDestroyed);
     407                 : 
     408                 :     {
     409                 :         RefPtr<Foo> f = new Foo();
     410                 :         GetPassedFoo(byRef(f));
     411                 :         MOZ_ASSERT(8 == Foo::numDestroyed);
     412                 :     }
     413                 :     MOZ_ASSERT(9 == Foo::numDestroyed);
     414                 : 
     415                 :     {
     416                 :         RefPtr<Foo> f = new Foo();
     417                 :         GetNewFoo(&f);
     418                 :         MOZ_ASSERT(10 == Foo::numDestroyed);
     419                 :     }
     420                 :     MOZ_ASSERT(11 == Foo::numDestroyed);
     421                 : 
     422                 :     {
     423                 :         RefPtr<Foo> f = new Foo();
     424                 :         GetPassedFoo(&f);
     425                 :         MOZ_ASSERT(11 == Foo::numDestroyed);
     426                 :     }
     427                 :     MOZ_ASSERT(12 == Foo::numDestroyed);
     428                 : 
     429                 :     {
     430                 :         RefPtr<Foo> f1 = new Bar();
     431                 :     }
     432                 :     MOZ_ASSERT(13 == Foo::numDestroyed);
     433                 : 
     434                 :     {
     435                 :         RefPtr<Foo> f = GetNullFoo();
     436                 :         MOZ_ASSERT(13 == Foo::numDestroyed);
     437                 :     }
     438                 :     MOZ_ASSERT(13 == Foo::numDestroyed);
     439                 : 
     440                 :     return 0;
     441                 : }
     442                 : 
     443                 : #endif

Generated by: LCOV version 1.7