mfbt/WeakPtr.h

Tue, 06 Jan 2015 21:39:09 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Tue, 06 Jan 2015 21:39:09 +0100
branch
TOR_BUG_9701
changeset 8
97036ab72558
permissions
-rw-r--r--

Conditionally force memory storage according to privacy.thirdparty.isolate;
This solves Tor bug #9701, complying with disk avoidance documented in
https://www.torproject.org/projects/torbrowser/design/#disk-avoidance.

     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/. */
     7 /* Weak pointer functionality, implemented as a mixin for use with any class. */
     9 /**
    10  * SupportsWeakPtr lets you have a pointer to an object 'Foo' without affecting
    11  * its lifetime. It works by creating a single shared reference counted object
    12  * (WeakReference) that each WeakPtr will access 'Foo' through. This lets 'Foo'
    13  * clear the pointer in the WeakReference without having to know about all of
    14  * the WeakPtrs to it and allows the WeakReference to live beyond the lifetime
    15  * of 'Foo'.
    16  *
    17  * PLEASE NOTE: This weak pointer implementation is not thread-safe.
    18  *
    19  * Note that when deriving from SupportsWeakPtr you should add
    20  * MOZ_DECLARE_REFCOUNTED_TYPENAME(ClassName) to the public section of your
    21  * class, where ClassName is the name of your class.
    22  *
    23  * The overhead of WeakPtr is that accesses to 'Foo' becomes an additional
    24  * dereference, and an additional heap allocated pointer sized object shared
    25  * between all of the WeakPtrs.
    26  *
    27  * Example of usage:
    28  *
    29  *   // To have a class C support weak pointers, inherit from SupportsWeakPtr<C>.
    30  *   class C : public SupportsWeakPtr<C>
    31  *   {
    32  *    public:
    33  *      MOZ_DECLARE_REFCOUNTED_TYPENAME(C)
    34  *      int num;
    35  *      void act();
    36  *   };
    37  *
    38  *   C* ptr =  new C();
    39  *
    40  *   // Get weak pointers to ptr. The first time asWeakPtr is called
    41  *   // a reference counted WeakReference object is created that
    42  *   // can live beyond the lifetime of 'ptr'. The WeakReference
    43  *   // object will be notified of 'ptr's destruction.
    44  *   WeakPtr<C> weak = ptr->asWeakPtr();
    45  *   WeakPtr<C> other = ptr->asWeakPtr();
    46  *
    47  *   // Test a weak pointer for validity before using it.
    48  *   if (weak) {
    49  *     weak->num = 17;
    50  *     weak->act();
    51  *   }
    52  *
    53  *   // Destroying the underlying object clears weak pointers to it.
    54  *   delete ptr;
    55  *
    56  *   MOZ_ASSERT(!weak, "Deleting |ptr| clears weak pointers to it.");
    57  *   MOZ_ASSERT(!other, "Deleting |ptr| clears all weak pointers to it.");
    58  *
    59  * WeakPtr is typesafe and may be used with any class. It is not required that
    60  * the class be reference-counted or allocated in any particular way.
    61  *
    62  * The API was loosely inspired by Chromium's weak_ptr.h:
    63  * http://src.chromium.org/svn/trunk/src/base/memory/weak_ptr.h
    64  */
    66 #ifndef mozilla_WeakPtr_h
    67 #define mozilla_WeakPtr_h
    69 #include "mozilla/ArrayUtils.h"
    70 #include "mozilla/Assertions.h"
    71 #include "mozilla/NullPtr.h"
    72 #include "mozilla/RefPtr.h"
    73 #include "mozilla/TypeTraits.h"
    75 #include <string.h>
    77 namespace mozilla {
    79 template <typename T, class WeakReference> class WeakPtrBase;
    80 template <typename T, class WeakReference> class SupportsWeakPtrBase;
    82 namespace detail {
    84 // This can live beyond the lifetime of the class derived from SupportsWeakPtrBase.
    85 template<class T>
    86 class WeakReference : public ::mozilla::RefCounted<WeakReference<T> >
    87 {
    88   public:
    89     explicit WeakReference(T* p) : ptr(p) {}
    90     T* get() const {
    91       return ptr;
    92     }
    94 #ifdef MOZ_REFCOUNTED_LEAK_CHECKING
    95 #ifdef XP_WIN
    96 #define snprintf _snprintf
    97 #endif
    98     const char* typeName() const {
    99       static char nameBuffer[1024];
   100       const char* innerType = ptr->typeName();
   101       // We could do fancier length checks at runtime, but innerType is
   102       // controlled by us so we can ensure that this never causes a buffer
   103       // overflow by this assertion.
   104       MOZ_ASSERT(strlen(innerType) + sizeof("WeakReference<>") < ArrayLength(nameBuffer),
   105                  "Exceedingly large type name");
   106       snprintf(nameBuffer, ArrayLength(nameBuffer), "WeakReference<%s>", innerType);
   107       // This is usually not OK, but here we are returning a pointer to a static
   108       // buffer which will immediately be used by the caller.
   109       return nameBuffer;
   110     }
   111     size_t typeSize() const {
   112       return sizeof(*this);
   113     }
   114 #undef snprintf
   115 #endif
   117   private:
   118     friend class WeakPtrBase<T, WeakReference<T> >;
   119     friend class SupportsWeakPtrBase<T, WeakReference<T> >;
   120     void detach() {
   121       ptr = nullptr;
   122     }
   123     T* ptr;
   124 };
   126 } // namespace detail
   128 template <typename T, class WeakReference>
   129 class SupportsWeakPtrBase
   130 {
   131   public:
   132     WeakPtrBase<T, WeakReference> asWeakPtr() {
   133       if (!weakRef)
   134         weakRef = new WeakReference(static_cast<T*>(this));
   135       return WeakPtrBase<T, WeakReference>(weakRef);
   136     }
   138   protected:
   139     ~SupportsWeakPtrBase() {
   140       static_assert(IsBaseOf<SupportsWeakPtrBase<T, WeakReference>, T>::value,
   141                     "T must derive from SupportsWeakPtrBase<T, WeakReference>");
   142       if (weakRef)
   143         weakRef->detach();
   144     }
   146   private:
   147     friend class WeakPtrBase<T, WeakReference>;
   149     RefPtr<WeakReference> weakRef;
   150 };
   152 template <typename T>
   153 class SupportsWeakPtr : public SupportsWeakPtrBase<T, detail::WeakReference<T> >
   154 {
   155 };
   157 template <typename T, class WeakReference>
   158 class WeakPtrBase
   159 {
   160   public:
   161     WeakPtrBase(const WeakPtrBase<T, WeakReference>& o) : ref(o.ref) {}
   162     // Ensure that ref is dereferenceable in the uninitialized state
   163     WeakPtrBase() : ref(new WeakReference(nullptr)) {}
   165     operator T*() const {
   166       return ref->get();
   167     }
   168     T& operator*() const {
   169       return *ref->get();
   170     }
   172     T* operator->() const {
   173       return ref->get();
   174     }
   176     T* get() const {
   177       return ref->get();
   178     }
   180   private:
   181     friend class SupportsWeakPtrBase<T, WeakReference>;
   183     explicit WeakPtrBase(const RefPtr<WeakReference> &o) : ref(o) {}
   185     RefPtr<WeakReference> ref;
   186 };
   188 template <typename T>
   189 class WeakPtr : public WeakPtrBase<T, detail::WeakReference<T> >
   190 {
   191     typedef WeakPtrBase<T, detail::WeakReference<T> > Base;
   192   public:
   193     WeakPtr(const WeakPtr<T>& o) : Base(o) {}
   194     WeakPtr(const Base& o) : Base(o) {}
   195     WeakPtr() {}
   196 };
   198 } // namespace mozilla
   200 #endif /* mozilla_WeakPtr_h */

mercurial