1/*
2 * Copyright (C) 2009, 2010 Google Inc. All rights reserved.
3 * Copyright (C) 2014-2019 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 are
7 * met:
8 *
9 * * Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * * Redistributions in binary form must reproduce the above
12 * copyright notice, this list of conditions and the following disclaimer
13 * in the documentation and/or other materials provided with the
14 * distribution.
15 * * Neither the name of Google Inc. nor the names of its
16 * contributors may be used to endorse or promote products derived from
17 * this software without specific prior written permission.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
22 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
23 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
24 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
25 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
26 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
27 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30 */
31
32#pragma once
33
34#include <type_traits>
35#include <wtf/Assertions.h>
36#include <wtf/Forward.h>
37#include <wtf/HashSet.h>
38#include <wtf/RefPtr.h>
39#include <wtf/ThreadSafeRefCounted.h>
40#include <wtf/text/WTFString.h>
41
42namespace WTF {
43
44struct CrossThreadCopierBaseHelper {
45 template<typename T> struct RemovePointer {
46 typedef T Type;
47 };
48 template<typename T> struct RemovePointer<T*> {
49 typedef T Type;
50 };
51
52 template<typename T> struct RemovePointer<RefPtr<T>> {
53 typedef T Type;
54 };
55
56 template<typename T> struct IsEnumOrConvertibleToInteger {
57 static constexpr bool value = std::is_integral<T>::value || std::is_enum<T>::value || std::is_convertible<T, long double>::value;
58 };
59
60 template<typename T> struct IsThreadSafeRefCountedPointer {
61 static constexpr bool value = std::is_convertible<typename RemovePointer<T>::Type*, ThreadSafeRefCounted<typename RemovePointer<T>::Type>*>::value;
62 };
63};
64
65template<typename T> struct CrossThreadCopierPassThrough {
66 typedef T Type;
67 static Type copy(const T& parameter)
68 {
69 return parameter;
70 }
71};
72
73template<bool isEnumOrConvertibleToInteger, bool isThreadSafeRefCounted, typename T> struct CrossThreadCopierBase;
74
75// Integers get passed through without any changes.
76template<typename T> struct CrossThreadCopierBase<true, false, T> : public CrossThreadCopierPassThrough<T> {
77};
78
79// Classes that have an isolatedCopy() method get a default specialization.
80template<class T> struct CrossThreadCopierBase<false, false, T> {
81 template<typename U> static auto copy(U&& value)
82 {
83 return std::forward<U>(value).isolatedCopy();
84 }
85};
86
87// Custom copy methods.
88template<typename T> struct CrossThreadCopierBase<false, true, T> {
89 typedef typename CrossThreadCopierBaseHelper::RemovePointer<T>::Type RefCountedType;
90 static_assert(std::is_convertible<RefCountedType*, ThreadSafeRefCounted<RefCountedType>*>::value, "T is not convertible to ThreadSafeRefCounted!");
91
92 typedef RefPtr<RefCountedType> Type;
93 static Type copy(const T& refPtr)
94 {
95 return refPtr;
96 }
97};
98
99template<> struct CrossThreadCopierBase<false, false, WTF::ASCIILiteral> {
100 typedef WTF::ASCIILiteral Type;
101 static Type copy(const Type& source)
102 {
103 return source;
104 }
105};
106
107template<typename T>
108struct CrossThreadCopier : public CrossThreadCopierBase<CrossThreadCopierBaseHelper::IsEnumOrConvertibleToInteger<T>::value, CrossThreadCopierBaseHelper::IsThreadSafeRefCountedPointer<T>::value, T> {
109};
110
111// Default specialization for Vectors of CrossThreadCopyable classes.
112template<typename T, size_t inlineCapacity, typename OverflowHandler, size_t minCapacity> struct CrossThreadCopierBase<false, false, Vector<T, inlineCapacity, OverflowHandler, minCapacity>> {
113 using Type = Vector<T, inlineCapacity, OverflowHandler, minCapacity>;
114 static Type copy(const Type& source)
115 {
116 Type destination;
117 destination.reserveInitialCapacity(source.size());
118 for (auto& object : source)
119 destination.uncheckedAppend(CrossThreadCopier<T>::copy(object));
120 return destination;
121 }
122};
123
124// Default specialization for HashSets of CrossThreadCopyable classes
125template<typename T> struct CrossThreadCopierBase<false, false, HashSet<T> > {
126 typedef HashSet<T> Type;
127 static Type copy(const Type& source)
128 {
129 Type destination;
130 for (auto& object : source)
131 destination.add(CrossThreadCopier<T>::copy(object));
132 return destination;
133 }
134};
135
136// Default specialization for HashMaps of CrossThreadCopyable classes
137template<typename K, typename V> struct CrossThreadCopierBase<false, false, HashMap<K, V> > {
138 typedef HashMap<K, V> Type;
139 static Type copy(const Type& source)
140 {
141 Type destination;
142 for (auto& keyValue : source)
143 destination.add(CrossThreadCopier<K>::copy(keyValue.key), CrossThreadCopier<V>::copy(keyValue.value));
144 return destination;
145 }
146};
147
148// Default specialization for pairs of CrossThreadCopyable classes
149template<typename F, typename S> struct CrossThreadCopierBase<false, false, std::pair<F, S> > {
150 typedef std::pair<F, S> Type;
151 static Type copy(const Type& source)
152 {
153 return std::make_pair(CrossThreadCopier<F>::copy(source.first), CrossThreadCopier<S>::copy(source.second));
154 }
155};
156
157// Default specialization for Optional of CrossThreadCopyable class.
158template<typename T> struct CrossThreadCopierBase<false, false, Optional<T>> {
159 template<typename U> static Optional<T> copy(U&& source)
160 {
161 if (!source)
162 return WTF::nullopt;
163 return CrossThreadCopier<T>::copy(std::forward<U>(source).value());
164 }
165};
166
167template<typename T> auto crossThreadCopy(T&& source)
168{
169 return CrossThreadCopier<std::remove_cv_t<std::remove_reference_t<T>>>::copy(std::forward<T>(source));
170}
171
172} // namespace WTF
173
174using WTF::CrossThreadCopierBaseHelper;
175using WTF::CrossThreadCopierBase;
176using WTF::CrossThreadCopier;
177using WTF::crossThreadCopy;
178