DXR is a code search and navigation tool aimed at making sense of large projects. It supports full-text and regex searches as well as structural queries.

Mercurial (d38398e5144e)

VCS Links

ArenaRefPtr

Macros

Line Code
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
 * vim: set ts=2 sw=2 et tw=78:
 * 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/.
 */

/* smart pointer for strong references to nsPresArena-allocated objects
   that might be held onto until the arena's destruction */

#include "mozilla/Assertions.h"
#include "mozilla/RefPtr.h"

#ifndef mozilla_ArenaRefPtr_h
#define mozilla_ArenaRefPtr_h

class nsPresArena;

namespace mozilla {

/**
 * A class for holding strong references to nsPresArena-allocated
 * objects.
 *
 * Since the arena's lifetime is not related to the refcounts
 * of the objects allocated within it, it is possible to have a strong
 * reference to an arena-allocated object that lives until the
 * destruction of the arena.  An ArenaRefPtr acts like a weak reference
 * in that it will clear its referent if the arena is about to go away.
 *
 * T must be a class that has these two methods:
 *
 *   static mozilla::ArenaObjectID ArenaObjectID();
 *   U* Arena();
 *
 * where U is a class that has these two methods:
 *
 *   void RegisterArenaRefPtr(ArenaRefPtr<T>*);
 *   void DeregisterArenaRefPtr(ArenaRefPtr<T>*);
 *
 * Currently, both nsPresArena and nsIPresShell can be used as U.
 *
 * The ArenaObjectID method must return the mozilla::ArenaObjectID that
 * uniquely identifies T, and the Arena method must return the nsPresArena
 * (or a proxy for it) in which the object was allocated.
 */
template<typename T>
class ArenaRefPtr
{
  friend class ::nsPresArena;

public:
  ArenaRefPtr()
  {
    AssertValidType();
  }

  template<typename I>
  MOZ_IMPLICIT ArenaRefPtr(already_AddRefed<I>& aRhs)
  {
    AssertValidType();
    assign(aRhs);
  }

  template<typename I>
  MOZ_IMPLICIT ArenaRefPtr(already_AddRefed<I>&& aRhs)
  {
    AssertValidType();
    assign(aRhs);
  }

  MOZ_IMPLICIT ArenaRefPtr(T* aRhs)
  {
    AssertValidType();
    assign(aRhs);
  }

  template<typename I>
  ArenaRefPtr<T>& operator=(already_AddRefed<I>& aRhs)
  {
    assign(aRhs);
    return *this;
  }

  template<typename I>
  ArenaRefPtr<T>& operator=(already_AddRefed<I>&& aRhs)
  {
    assign(aRhs);
    return *this;
  }

  ArenaRefPtr<T>& operator=(T* aRhs)
  {
    assign(aRhs);
    return *this;
  }

  ~ArenaRefPtr() { assign(nullptr); }

  operator T*() const & { return get(); }
  operator T*() const && = delete;
  explicit operator bool() const { return !!mPtr; }
  bool operator!() const { return !mPtr; }
  T* operator->() const { return mPtr.operator->(); }
  T& operator*() const { return *get(); }

  T* get() const { return mPtr; }

private:
  void AssertValidType();

  /**
   * Clears the pointer to the arena-allocated object but skips the usual
   * step of deregistering the ArenaRefPtr from the nsPresArena.  This
   * method is called by nsPresArena when clearing all registered ArenaRefPtrs
   * so that it can deregister them all at once, avoiding hash table churn.
   */
  void ClearWithoutDeregistering()
  {
    mPtr = nullptr;
  }

  template<typename I>
  void assign(already_AddRefed<I>& aSmartPtr)
  {
    RefPtr<T> newPtr(aSmartPtr);
    assignFrom(newPtr);
  }

  template<typename I>
  void assign(already_AddRefed<I>&& aSmartPtr)
  {
    RefPtr<T> newPtr(aSmartPtr);
    assignFrom(newPtr);
  }

  void assign(T* aPtr) { assignFrom(aPtr); }

  template<typename I>
  void assignFrom(I& aPtr)
  {
    if (aPtr == mPtr) {
      return;
    }
    bool sameArena = mPtr && aPtr && mPtr->Arena() == aPtr->Arena();
    if (mPtr && !sameArena) {
      MOZ_ASSERT(mPtr->Arena());
      mPtr->Arena()->DeregisterArenaRefPtr(this);
    }
    mPtr = Move(aPtr);
    if (mPtr && !sameArena) {
      MOZ_ASSERT(mPtr->Arena());
      mPtr->Arena()->RegisterArenaRefPtr(this);
    }
  }

  RefPtr<T> mPtr;
};

} // namespace mozilla

#endif // mozilla_ArenaRefPtr_h