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
36// Testing interface for TestWebKitAPI
37#ifndef DID_CREATE_WEAK_PTR_IMPL
38#define DID_CREATE_WEAK_PTR_IMPL(p)
39#endif
40#ifndef WILL_DESTROY_WEAK_PTR_IMPL
41#define WILL_DESTROY_WEAK_PTR_IMPL(p)
42#endif
43
44template<typename> class WeakHashSet;
45template<typename> class WeakPtr;
46template<typename> class WeakPtrFactory;
47
48class WeakPtrImpl : public ThreadSafeRefCounted<WeakPtrImpl> {
49 WTF_MAKE_NONCOPYABLE(WeakPtrImpl);
50 WTF_MAKE_FAST_ALLOCATED;
51public:
52 template<typename T> static Ref<WeakPtrImpl> create(T* ptr)
53 {
54 return adoptRef(*new WeakPtrImpl(ptr));
55 }
56
57 ~WeakPtrImpl()
58 {
59 WILL_DESTROY_WEAK_PTR_IMPL(m_ptr);
60 }
61
62 template<typename T> typename T::WeakValueType* get()
63 {
64 return static_cast<typename T::WeakValueType*>(m_ptr);
65 }
66
67 explicit operator bool() const { return m_ptr; }
68 void clear() { m_ptr = nullptr; }
69
70private:
71 template<typename T> explicit WeakPtrImpl(T* ptr)
72 : m_ptr(static_cast<typename T::WeakValueType*>(ptr))
73 {
74 DID_CREATE_WEAK_PTR_IMPL(ptr);
75 }
76
77 void* m_ptr;
78};
79
80template<typename T>
81class WeakPtr {
82 WTF_MAKE_FAST_ALLOCATED;
83public:
84 WeakPtr() { }
85 WeakPtr(std::nullptr_t) { }
86 template<typename U> WeakPtr(const WeakPtr<U>&);
87 template<typename U> WeakPtr(WeakPtr<U>&&);
88
89 T* get() const { return m_impl ? static_cast<T*>(m_impl->get<T>()) : nullptr; }
90 explicit operator bool() const { return m_impl && *m_impl; }
91
92 WeakPtr& operator=(std::nullptr_t) { m_impl = nullptr; return *this; }
93 template<typename U> WeakPtr& operator=(const WeakPtr<U>&);
94 template<typename U> WeakPtr& operator=(WeakPtr<U>&&);
95
96 T* operator->() const { return get(); }
97 T& operator*() const { return *get(); }
98
99 void clear() { m_impl = nullptr; }
100
101private:
102 explicit WeakPtr(Ref<WeakPtrImpl>&& ref) : m_impl(WTFMove(ref)) { }
103 template<typename> friend class WeakHashSet;
104 template<typename> friend class WeakPtr;
105 template<typename> friend class WeakPtrFactory;
106 template<typename U> friend WeakPtr<U> makeWeakPtr(U&);
107
108 RefPtr<WeakPtrImpl> m_impl;
109};
110
111// Note: you probably want to inherit from CanMakeWeakPtr rather than use this directly.
112template<typename T>
113class WeakPtrFactory {
114 WTF_MAKE_NONCOPYABLE(WeakPtrFactory<T>);
115 WTF_MAKE_FAST_ALLOCATED;
116public:
117 WeakPtrFactory() = default;
118 ~WeakPtrFactory()
119 {
120 if (!m_impl)
121 return;
122 m_impl->clear();
123 }
124
125 WeakPtr<T> createWeakPtr(T& object) const
126 {
127 if (!m_impl)
128 m_impl = WeakPtrImpl::create(&object);
129
130 ASSERT(&object == m_impl->get<T>());
131 return WeakPtr<T>(makeRef(*m_impl));
132 }
133
134 WeakPtr<const T> createWeakPtr(const T& object) const
135 {
136 if (!m_impl)
137 m_impl = WeakPtrImpl::create(const_cast<T*>(&object));
138
139 ASSERT(&object == m_impl->get<T>());
140 return WeakPtr<T>(makeRef(*m_impl));
141 }
142
143 void revokeAll()
144 {
145 if (!m_impl)
146 return;
147
148 m_impl->clear();
149 m_impl = nullptr;
150 }
151
152private:
153 template<typename> friend class WeakHashSet;
154
155 mutable RefPtr<WeakPtrImpl> m_impl;
156};
157
158template<typename T> class CanMakeWeakPtr {
159public:
160 typedef T WeakValueType;
161
162 const WeakPtrFactory<T>& weakPtrFactory() const { return m_weakPtrFactory; }
163 WeakPtrFactory<T>& weakPtrFactory() { return m_weakPtrFactory; }
164
165private:
166 WeakPtrFactory<T> m_weakPtrFactory;
167};
168
169template<typename T, typename U> inline WeakPtrImpl* weak_ptr_impl_cast(WeakPtrImpl* impl)
170{
171 static_assert(std::is_same<typename T::WeakValueType, typename U::WeakValueType>::value, "Invalid weak pointer cast");
172 return impl;
173}
174
175template<typename T> template<typename U> inline WeakPtr<T>::WeakPtr(const WeakPtr<U>& o)
176 : m_impl(weak_ptr_impl_cast<T, U>(o.m_impl.get()))
177{
178}
179
180template<typename T> template<typename U> inline WeakPtr<T>::WeakPtr(WeakPtr<U>&& o)
181 : m_impl(adoptRef(weak_ptr_impl_cast<T, U>(o.m_impl.leakRef())))
182{
183}
184
185template<typename T> template<typename U> inline WeakPtr<T>& WeakPtr<T>::operator=(const WeakPtr<U>& o)
186{
187 m_impl = weak_ptr_impl_cast<T, U>(o.m_impl.get());
188 return *this;
189}
190
191template<typename T> template<typename U> inline WeakPtr<T>& WeakPtr<T>::operator=(WeakPtr<U>&& o)
192{
193 m_impl = adoptRef(weak_ptr_impl_cast<T, U>(o.m_impl.leakRef()));
194 return *this;
195}
196
197template<typename T> inline WeakPtr<T> makeWeakPtr(T& object)
198{
199 return { object.weakPtrFactory().createWeakPtr(object) };
200}
201
202template<typename T> inline WeakPtr<T> makeWeakPtr(T* ptr)
203{
204 if (!ptr)
205 return { };
206 return makeWeakPtr(*ptr);
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
224template<typename T, typename U> inline bool operator!=(const WeakPtr<T>& a, const WeakPtr<U>& b)
225{
226 return a.get() != b.get();
227}
228
229template<typename T, typename U> inline bool operator!=(const WeakPtr<T>& a, U* b)
230{
231 return a.get() != b;
232}
233
234template<typename T, typename U> inline bool operator!=(T* a, const WeakPtr<U>& b)
235{
236 return a != b.get();
237}
238
239} // namespace WTF
240
241using WTF::CanMakeWeakPtr;
242using WTF::WeakPtr;
243using WTF::WeakPtrFactory;
244using WTF::makeWeakPtr;
245