1/*
2 * Copyright (C) 2012, 2013 Apple Inc. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
6 * are met:
7 * 1. Redistributions of source code must retain the above copyright
8 *    notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 *    notice, this list of conditions and the following disclaimer in the
11 *    documentation and/or other materials provided with the distribution.
12 *
13 * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
14 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16 * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
17 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
18 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
19 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
20 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
21 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24 */
25
26#ifndef PassWeak_h
27#define PassWeak_h
28
29#include "JSCell.h"
30#include "WeakSetInlines.h"
31#include <wtf/Assertions.h>
32#include <wtf/NullPtr.h>
33#include <wtf/TypeTraits.h>
34
35namespace JSC {
36
37template<typename T> class PassWeak;
38template<typename T> PassWeak<T> adoptWeak(WeakImpl*);
39
40template<typename T> class PassWeak {
41public:
42    PassWeak();
43    PassWeak(std::nullptr_t);
44    PassWeak(T*, WeakHandleOwner* = 0, void* context = 0);
45
46    // It somewhat breaks the type system to allow transfer of ownership out of
47    // a const PassWeak. However, it makes it much easier to work with PassWeak
48    // temporaries, and we don't have a need to use real const PassWeaks anyway.
49    PassWeak(const PassWeak&);
50    template<typename U> PassWeak(const PassWeak<U>&);
51
52    ~PassWeak();
53
54    T* operator->() const;
55    T& operator*() const;
56    T* get() const;
57
58    bool operator!() const;
59
60    // This conversion operator allows implicit conversion to bool but not to other integer types.
61    typedef void* (PassWeak::*UnspecifiedBoolType);
62    operator UnspecifiedBoolType*() const;
63
64    WeakImpl* leakImpl() const WARN_UNUSED_RETURN;
65
66private:
67    friend PassWeak adoptWeak<T>(WeakImpl*);
68    explicit PassWeak(WeakImpl*);
69
70    WeakImpl* m_impl;
71};
72
73template<typename T> inline PassWeak<T>::PassWeak()
74    : m_impl(0)
75{
76}
77
78template<typename T> inline PassWeak<T>::PassWeak(std::nullptr_t)
79    : m_impl(0)
80{
81}
82
83template<typename T> inline PassWeak<T>::PassWeak(T* cell, WeakHandleOwner* weakOwner, void* context)
84    : m_impl(cell ? WeakSet::allocate(cell, weakOwner, context) : 0)
85{
86}
87
88template<typename T> inline PassWeak<T>::PassWeak(const PassWeak& o)
89    : m_impl(o.leakImpl())
90{
91}
92
93template<typename T> template<typename U> inline PassWeak<T>::PassWeak(const PassWeak<U>& o)
94    : m_impl(o.leakImpl())
95{
96}
97
98template<typename T> inline PassWeak<T>::~PassWeak()
99{
100    if (!m_impl)
101        return;
102    WeakSet::deallocate(m_impl);
103}
104
105template<typename T> inline T* PassWeak<T>::operator->() const
106{
107    ASSERT(m_impl && m_impl->state() == WeakImpl::Live);
108    return jsCast<T*>(m_impl->jsValue().asCell());
109}
110
111template<typename T> inline T& PassWeak<T>::operator*() const
112{
113    ASSERT(m_impl && m_impl->state() == WeakImpl::Live);
114    return *jsCast<T*>(m_impl->jsValue().asCell());
115}
116
117template<typename T> inline T* PassWeak<T>::get() const
118{
119    if (!m_impl || m_impl->state() != WeakImpl::Live)
120        return 0;
121    return jsCast<T*>(m_impl->jsValue().asCell());
122}
123
124template<typename T> inline bool PassWeak<T>::operator!() const
125{
126    return !m_impl || m_impl->state() != WeakImpl::Live || !m_impl->jsValue();
127}
128
129template<typename T> inline PassWeak<T>::operator UnspecifiedBoolType*() const
130{
131    return reinterpret_cast<UnspecifiedBoolType*>(!!*this);
132}
133
134template<typename T> inline PassWeak<T>::PassWeak(WeakImpl* impl)
135: m_impl(impl)
136{
137}
138
139template<typename T> inline WeakImpl* PassWeak<T>::leakImpl() const
140{
141    WeakImpl* tmp = 0;
142    std::swap(tmp, const_cast<WeakImpl*&>(m_impl));
143    return tmp;
144}
145
146template<typename T> PassWeak<T> inline adoptWeak(WeakImpl* impl)
147{
148    return PassWeak<T>(impl);
149}
150
151template<typename T, typename U> inline bool operator==(const PassWeak<T>& a, const PassWeak<U>& b)
152{
153    return a.get() == b.get();
154}
155
156template<typename T, typename U> inline bool operator==(const PassWeak<T>& a, const Weak<U>& b)
157{
158    return a.get() == b.get();
159}
160
161template<typename T, typename U> inline bool operator==(const Weak<T>& a, const PassWeak<U>& b)
162{
163    return a.get() == b.get();
164}
165
166template<typename T, typename U> inline bool operator==(const PassWeak<T>& a, U* b)
167{
168    return a.get() == b;
169}
170
171template<typename T, typename U> inline bool operator==(T* a, const PassWeak<U>& b)
172{
173    return a == b.get();
174}
175
176template<typename T, typename U> inline bool operator!=(const PassWeak<T>& a, const PassWeak<U>& b)
177{
178    return a.get() != b.get();
179}
180
181template<typename T, typename U> inline bool operator!=(const PassWeak<T>& a, const Weak<U>& b)
182{
183    return a.get() != b.get();
184}
185
186template<typename T, typename U> inline bool operator!=(const Weak<T>& a, const PassWeak<U>& b)
187{
188    return a.get() != b.get();
189}
190
191template<typename T, typename U> inline bool operator!=(const PassWeak<T>& a, U* b)
192{
193    return a.get() != b;
194}
195
196template<typename T, typename U> inline bool operator!=(T* a, const PassWeak<U>& b)
197{
198    return a != b.get();
199}
200
201} // namespace JSC
202
203#endif // PassWeak_h
204