1/*
2 * Copyright (C) 2013 Google, Inc. All Rights Reserved.
3 * Copyright (C) 2015, 2017 Apple Inc. All Rights Reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 *
14 * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
15 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
17 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
18 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
19 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
20 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
21 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
22 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
24 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25 */
26
27#pragma once
28
29#include <wtf/Noncopyable.h>
30#include <wtf/Ref.h>
31#include <wtf/ThreadSafeRefCounted.h>
32#include <wtf/Threading.h>
33
34namespace WTF {
35
36template<typename> class WeakHashSet;
37template<typename> class WeakPtr;
38template<typename> class WeakPtrFactory;
39
40// Note: WeakReference is an implementation detail, and should not be used directly.
41template<typename T>
42class WeakReference : public ThreadSafeRefCounted<WeakReference<T>> {
43 WTF_MAKE_NONCOPYABLE(WeakReference<T>);
44 WTF_MAKE_FAST_ALLOCATED;
45public:
46 ~WeakReference() { } // So that we can use a template specialization for testing purposes to detect leaks.
47
48 T* get() const { return m_ptr; }
49
50 void clear() { m_ptr = nullptr; }
51
52private:
53 friend class WeakPtr<T>;
54 friend class WeakPtrFactory<T>;
55
56 static Ref<WeakReference<T>> create(T* ptr) { return adoptRef(*new WeakReference(ptr)); }
57
58 explicit WeakReference(T* ptr)
59 : m_ptr(ptr)
60 {
61 }
62
63 T* m_ptr;
64};
65
66template<typename T>
67class WeakPtr {
68 WTF_MAKE_FAST_ALLOCATED;
69public:
70 WeakPtr() { }
71 WeakPtr(std::nullptr_t) { }
72 WeakPtr(Ref<WeakReference<T>>&& ref) : m_ref(std::forward<Ref<WeakReference<T>>>(ref)) { }
73 template<typename U> WeakPtr(const WeakPtr<U>&);
74 template<typename U> WeakPtr(WeakPtr<U>&&);
75
76 T* get() const { return m_ref ? m_ref->get() : nullptr; }
77 explicit operator bool() const { return m_ref && m_ref->get(); }
78
79 WeakPtr& operator=(std::nullptr_t) { m_ref = nullptr; return *this; }
80 template<typename U> WeakPtr& operator=(const WeakPtr<U>&);
81 template<typename U> WeakPtr& operator=(WeakPtr<U>&&);
82
83 T* operator->() const { return m_ref->get(); }
84 T& operator*() const { return *m_ref->get(); }
85
86 void clear() { m_ref = nullptr; }
87
88private:
89 template<typename> friend class WeakHashSet;
90 template<typename> friend class WeakPtr;
91 template<typename U> friend WeakPtr<U> makeWeakPtr(U&);
92
93 RefPtr<WeakReference<T>> m_ref;
94};
95
96// Note: you probably want to inherit from CanMakeWeakPtr rather than use this directly.
97template<typename T>
98class WeakPtrFactory {
99 WTF_MAKE_NONCOPYABLE(WeakPtrFactory<T>);
100 WTF_MAKE_FAST_ALLOCATED;
101public:
102 WeakPtrFactory() = default;
103 ~WeakPtrFactory()
104 {
105 if (!m_ref)
106 return;
107 m_ref->clear();
108 }
109
110 WeakPtr<T> createWeakPtr(T& ptr) const
111 {
112 if (!m_ref)
113 m_ref = WeakReference<T>::create(&ptr);
114 return { makeRef(*m_ref) };
115 }
116
117 WeakPtr<const T> createWeakPtr(const T& ptr) const
118 {
119 if (!m_ref)
120 m_ref = WeakReference<T>::create(const_cast<T*>(&ptr));
121 return { makeRef(reinterpret_cast<WeakReference<const T>&>(*m_ref)) };
122 }
123
124 void revokeAll()
125 {
126 if (!m_ref)
127 return;
128
129 m_ref->clear();
130 m_ref = nullptr;
131 }
132
133private:
134 template<typename> friend class WeakHashSet;
135
136 mutable RefPtr<WeakReference<T>> m_ref;
137};
138
139template<typename T> class CanMakeWeakPtr {
140public:
141 const WeakPtrFactory<T>& weakPtrFactory() const { return m_weakFactory; }
142 WeakPtrFactory<T>& weakPtrFactory() { return m_weakFactory; }
143
144private:
145 WeakPtrFactory<T> m_weakFactory;
146};
147
148template<typename T, typename U> inline WeakReference<T>* weak_reference_upcast(WeakReference<U>* weakReference)
149{
150 static_assert(std::is_convertible<U*, T*>::value, "U* must be convertible to T*");
151 return reinterpret_cast<WeakReference<T>*>(weakReference);
152}
153
154template<typename T, typename U> inline WeakReference<T>* weak_reference_downcast(WeakReference<U>* weakReference)
155{
156 static_assert(std::is_convertible<T*, U*>::value, "T* must be convertible to U*");
157 return reinterpret_cast<WeakReference<T>*>(weakReference);
158}
159
160template<typename T> template<typename U> inline WeakPtr<T>::WeakPtr(const WeakPtr<U>& o)
161 : m_ref(weak_reference_upcast<T>(o.m_ref.get()))
162{
163}
164
165template<typename T> template<typename U> inline WeakPtr<T>::WeakPtr(WeakPtr<U>&& o)
166 : m_ref(adoptRef(weak_reference_upcast<T>(o.m_ref.leakRef())))
167{
168}
169
170template<typename T> template<typename U> inline WeakPtr<T>& WeakPtr<T>::operator=(const WeakPtr<U>& o)
171{
172 m_ref = weak_reference_upcast<T>(o.m_ref.get());
173 return *this;
174}
175
176template<typename T> template<typename U> inline WeakPtr<T>& WeakPtr<T>::operator=(WeakPtr<U>&& o)
177{
178 m_ref = adoptRef(weak_reference_upcast<T>(o.m_ref.leakRef()));
179 return *this;
180}
181
182template<typename T> inline WeakPtr<T> makeWeakPtr(T& ref)
183{
184 return { adoptRef(*weak_reference_downcast<T>(ref.weakPtrFactory().createWeakPtr(ref).m_ref.leakRef())) };
185}
186
187template<typename T> inline WeakPtr<T> makeWeakPtr(T* ptr)
188{
189 if (!ptr)
190 return { };
191 return makeWeakPtr(*ptr);
192}
193
194template<typename T, typename U> inline bool operator==(const WeakPtr<T>& a, const WeakPtr<U>& b)
195{
196 return a.get() == b.get();
197}
198
199template<typename T, typename U> inline bool operator==(const WeakPtr<T>& a, U* b)
200{
201 return a.get() == b;
202}
203
204template<typename T, typename U> inline bool operator==(T* a, const WeakPtr<U>& b)
205{
206 return a == b.get();
207}
208
209template<typename T, typename U> inline bool operator!=(const WeakPtr<T>& a, const WeakPtr<U>& b)
210{
211 return a.get() != b.get();
212}
213
214template<typename T, typename U> inline bool operator!=(const WeakPtr<T>& a, U* b)
215{
216 return a.get() != b;
217}
218
219template<typename T, typename U> inline bool operator!=(T* a, const WeakPtr<U>& b)
220{
221 return a != b.get();
222}
223
224} // namespace WTF
225
226using WTF::CanMakeWeakPtr;
227using WTF::WeakPtr;
228using WTF::WeakPtrFactory;
229using WTF::WeakReference;
230using WTF::makeWeakPtr;
231