summaryrefslogtreecommitdiff
path: root/layout/style/HandleRefPtr.h
blob: 0a73a4cf701106137d0d44e0c04ca676f88dc367 (plain)
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
/* -*- 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 objects through pointer-like
 * "handle" objects */

#include <algorithm>
#include "mozilla/Assertions.h"

#ifndef mozilla_HandleRefPtr_h
#define mozilla_HandleRefPtr_h

namespace mozilla {

/**
 * A class for holding strong references to handle-managed objects.
 *
 * This is intended for use with objects like RestyleManagerHandle,
 * where the handle type is not a pointer but which can still have
 * ->AddRef() and ->Release() called on it.
 */
template<typename T>
class HandleRefPtr
{
public:
  HandleRefPtr() {}

  HandleRefPtr(HandleRefPtr<T>& aRhs)
  {
    assign(aRhs.mHandle);
  }

  HandleRefPtr(HandleRefPtr<T>&& aRhs)
  {
    std::swap(mHandle, aRhs.mHandle);
  }

  MOZ_IMPLICIT HandleRefPtr(T aRhs)
  {
    assign(aRhs);
  }

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

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

  ~HandleRefPtr() { assign(nullptr); }

  explicit operator bool() const { return !!mHandle; }
  bool operator!() const { return !mHandle; }

  operator T() const { return mHandle; }
  T operator->() const { return mHandle; }

  void swap(HandleRefPtr<T>& aOther)
  {
    std::swap(mHandle, aOther.mHandle);
  }

private:
  void assign(T aPtr)
  {
    // AddRef early so |aPtr| can't disappear underneath us.
    if (aPtr) {
      aPtr->AddRef();
    }

    // Don't release |mHandle| yet: if |mHandle| indirectly owns |this|,
    // releasing would invalidate |this|.  Swap |aPtr| for |mHandle| so that
    // |aPtr| lives as long as |this|, then release the new |aPtr| (really the
    // original |mHandle|) so that if |this| is invalidated, we're not using it
    // any more.
    std::swap(mHandle, aPtr);

    if (aPtr) {
      aPtr->Release();
    }
  }

  T mHandle;
};

template<typename T>
inline bool operator==(const HandleRefPtr<T>& aLHS, const HandleRefPtr<T>& aRHS)
{
  return static_cast<T>(aLHS) == static_cast<T>(aRHS);
}

template<typename T>
inline bool operator==(const HandleRefPtr<T>& aLHS, T aRHS)
{
  return static_cast<T>(aLHS) == aRHS;
}

template<typename T>
inline bool operator==(T aLHS, const HandleRefPtr<T>& aRHS)
{
  return aLHS == static_cast<T>(aRHS);
}

template<typename T>
inline bool operator!=(const HandleRefPtr<T>& aLHS, const HandleRefPtr<T>& aRHS)
{
  return !(aLHS == aRHS);
}

template<typename T>
inline bool operator!=(const HandleRefPtr<T>& aLHS, T aRHS)
{
  return !(aLHS == aRHS);
}

template<typename T>
inline bool operator!=(T aLHS, const HandleRefPtr<T>& aRHS)
{
  return !(aLHS == aRHS);
}

} // namespace mozilla

#endif // mozilla_HandleRefPtr_h