1/*
2 * Copyright (C) 2009, 2012, 2013, 2016 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. AND ITS CONTRIBUTORS ``AS IS''
14 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
15 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
17 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
18 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
19 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
20 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
21 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
22 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
23 * THE POSSIBILITY OF SUCH DAMAGE.
24 */
25
26#pragma once
27
28#include "JSCast.h"
29#include "WeakSetInlines.h"
30#include <wtf/Assertions.h>
31
32namespace JSC {
33
34template<typename T> inline Weak<T>::Weak(T* cell, WeakHandleOwner* weakOwner, void* context)
35 : m_impl(cell ? WeakSet::allocate(cell, weakOwner, context) : 0)
36{
37}
38
39template<typename T> inline bool Weak<T>::isHashTableDeletedValue() const
40{
41 return m_impl == hashTableDeletedValue();
42}
43
44template<typename T> inline Weak<T>::Weak(typename Weak<T>::HashTableDeletedValueTag)
45 : m_impl(hashTableDeletedValue())
46{
47}
48
49template<typename T> inline Weak<T>::Weak(Weak&& other)
50 : m_impl(other.leakImpl())
51{
52}
53
54template<class T> inline void swap(Weak<T>& a, Weak<T>& b)
55{
56 a.swap(b);
57}
58
59template<typename T> inline void Weak<T>::swap(Weak& other)
60{
61 std::swap(m_impl, other.m_impl);
62}
63
64template<typename T> inline auto Weak<T>::operator=(Weak&& other) -> Weak&
65{
66 Weak weak = WTFMove(other);
67 swap(weak);
68 return *this;
69}
70
71template<typename T> inline T* Weak<T>::operator->() const
72{
73 ASSERT(m_impl && m_impl->state() == WeakImpl::Live);
74 // We can't use jsCast here since we could be called in a finalizer.
75 return static_cast<T*>(m_impl->jsValue().asCell());
76}
77
78template<typename T> inline T& Weak<T>::operator*() const
79{
80 ASSERT(m_impl && m_impl->state() == WeakImpl::Live);
81 // We can't use jsCast here since we could be called in a finalizer.
82 return *static_cast<T*>(m_impl->jsValue().asCell());
83}
84
85template<typename T> inline T* Weak<T>::get() const
86{
87 if (!m_impl || m_impl->state() != WeakImpl::Live)
88 return nullptr;
89 // We can't use jsCast here since we could be called in a finalizer.
90 return static_cast<T*>(m_impl->jsValue().asCell());
91}
92
93template<typename T> inline bool Weak<T>::was(T* other) const
94{
95 return static_cast<T*>(m_impl->jsValue().asCell()) == other;
96}
97
98template<typename T> inline bool Weak<T>::operator!() const
99{
100 return !m_impl || !m_impl->jsValue() || m_impl->state() != WeakImpl::Live;
101}
102
103template<typename T> inline Weak<T>::operator bool() const
104{
105 return !!*this;
106}
107
108template<typename T> inline WeakImpl* Weak<T>::leakImpl()
109{
110 WeakImpl* impl = m_impl;
111 m_impl = nullptr;
112 return impl;
113}
114
115template<typename T> inline WeakImpl* Weak<T>::hashTableDeletedValue()
116{
117 return reinterpret_cast<WeakImpl*>(-1);
118}
119
120template <typename T> inline bool operator==(const Weak<T>& lhs, const Weak<T>& rhs)
121{
122 return lhs.get() == rhs.get();
123}
124
125// This function helps avoid modifying a weak table while holding an iterator into it. (Object allocation
126// can run a finalizer that modifies the table. We avoid that by requiring a pre-constructed object as our value.)
127template<typename Map, typename Key, typename Value> inline void weakAdd(Map& map, const Key& key, Value&& value)
128{
129 ASSERT(!map.get(key));
130 map.set(key, std::forward<Value>(value)); // The table may still have a zombie for value.
131}
132
133template<typename Map, typename Key, typename Value> inline void weakRemove(Map& map, const Key& key, Value value)
134{
135 typename Map::iterator it = map.find(key);
136 ASSERT_UNUSED(value, value);
137 ASSERT(it != map.end());
138 ASSERT(it->value.was(value));
139 ASSERT(!it->value);
140 map.remove(it);
141}
142
143template<typename T> inline void weakClear(Weak<T>& weak, T* cell)
144{
145 ASSERT_UNUSED(cell, cell);
146 ASSERT(weak.was(cell));
147 ASSERT(!weak);
148 weak.clear();
149}
150
151} // namespace JSC
152