blob: b56188dfebf113dbef9af4262e79945a7dd1481b [file] [log] [blame]
[email protected]b9e13442011-12-14 03:12:151/*
2 * Copyright (C) 2011 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#ifndef WTF_Functional_h
27#define WTF_Functional_h
28
yutak2a02e482016-02-09 05:55:0529#include "base/tuple.h"
tasak4faca4c42016-01-19 08:38:5530#include "wtf/Allocator.h"
[email protected]a71b3132013-06-27 17:54:1531#include "wtf/Assertions.h"
[email protected]1cf642d2014-11-14 05:28:0432#include "wtf/PassOwnPtr.h"
[email protected]a71b3132013-06-27 17:54:1533#include "wtf/PassRefPtr.h"
34#include "wtf/RefPtr.h"
35#include "wtf/ThreadSafeRefCounted.h"
36#include "wtf/WeakPtr.h"
yutak2a02e482016-02-09 05:55:0537#include <tuple>
yutakfbbd4c942016-02-26 07:07:3238#include <utility>
[email protected]b9e13442011-12-14 03:12:1539
40namespace WTF {
41
42// Functional.h provides a very simple way to bind a function pointer and arguments together into a function object
43// that can be stored, copied and invoked, similar to how boost::bind and std::bind in C++11.
hiroshige960a5f52016-03-07 19:46:3444
45// Thread Safety:
yutakfbbd4c942016-02-26 07:07:3246//
hiroshige960a5f52016-03-07 19:46:3447// WTF::bind() and SameThreadClosure should be used for same-thread closures
48// only, i.e. the closures must be created, executed and destructed on
49// the same thread.
50// Use threadSafeBind() and CrossThreadClosure if the function/task is called
51// or destructed on a (potentially) different thread from the current thread.
[email protected]42ce3982015-04-22 11:35:2152
finnur54fbc8362016-03-03 10:41:0453// WTF::bind() and move semantics
54// ==============================
yutakfbbd4c942016-02-26 07:07:3255//
finnur54fbc8362016-03-03 10:41:0456// For unbound parameters (arguments supplied later on the bound functor directly), there are two ways to pass movable
57// arguments:
58//
59// 1) Pass by rvalue reference.
60//
61// void yourFunction(Argument&& argument) { ... }
62// OwnPtr<Function<void(Argument&&)>> functor = bind<Argument&&>(yourFunction);
63//
64// 2) Pass by value.
65//
66// void yourFunction(Argument argument) { ... }
67// OwnPtr<Function<void(Argument)>> functor = bind<Argument>(yourFunction);
68//
69// Note that with the latter there will be *two* move constructions happening, because there needs to be at least one
70// intermediary function call taking an argument of type "Argument" (i.e. passed by value). The former case does not
71// require any move constructions inbetween.
yutakfbbd4c942016-02-26 07:07:3272//
73// For bound parameters (arguments supplied on the creation of a functor), you can move your argument into the internal
74// storage of the functor by supplying an rvalue to that argument (this is done in wrap() of ParamStorageTraits).
75// However, to make the functor be able to get called multiple times, the stored object does not get moved out
76// automatically when the underlying function is actually invoked. If you want to move the argument throughout the
77// process, you can do so by receiving the argument as a non-const lvalue reference and applying std::move() to it:
78//
79// void yourFunction(Argument& argument)
80// {
81// std::move(argument); // Move out the argument from the internal storage.
82// ...
83// }
84//
85// ...
86// OwnPtr<Function<void()>> functor = bind(yourFunction, Argument()); // Pass the argument by rvalue.
87// ...
88// (*functor)();
89
[email protected]b9e13442011-12-14 03:12:1590// A FunctionWrapper is a class template that can wrap a function pointer or a member function pointer and
91// provide a unified interface for calling that function.
yutakfbbd4c942016-02-26 07:07:3292template <typename>
[email protected]f97e2662011-12-28 01:31:1693class FunctionWrapper;
[email protected]b9e13442011-12-14 03:12:1594
[email protected]d0d93152013-01-25 20:18:5895// Bound static functions:
yutakfbbd4c942016-02-26 07:07:3296template <typename R, typename... Parameters>
97class FunctionWrapper<R(*)(Parameters...)> {
tasak4faca4c42016-01-19 08:38:5598 DISALLOW_NEW();
[email protected]b9e13442011-12-14 03:12:1599public:
100 typedef R ResultType;
101
yutakfbbd4c942016-02-26 07:07:32102 explicit FunctionWrapper(R(*function)(Parameters...))
[email protected]b9e13442011-12-14 03:12:15103 : m_function(function)
104 {
105 }
106
yutakfbbd4c942016-02-26 07:07:32107 template <typename... IncomingParameters>
108 R operator()(IncomingParameters&&... parameters)
[email protected]b9e13442011-12-14 03:12:15109 {
yutakfbbd4c942016-02-26 07:07:32110 return m_function(std::forward<IncomingParameters>(parameters)...);
[email protected]b9e13442011-12-14 03:12:15111 }
112
113private:
yutakfbbd4c942016-02-26 07:07:32114 R(*m_function)(Parameters...);
[email protected]c8b1ad82014-07-24 14:52:23115};
116
[email protected]d0d93152013-01-25 20:18:58117// Bound member functions:
118
yutakfbbd4c942016-02-26 07:07:32119template <typename R, typename C, typename... Parameters>
120class FunctionWrapper<R(C::*)(Parameters...)> {
tasak4faca4c42016-01-19 08:38:55121 DISALLOW_NEW();
[email protected]d1e1d5ab2011-12-14 20:59:53122public:
123 typedef R ResultType;
124
yutakfbbd4c942016-02-26 07:07:32125 explicit FunctionWrapper(R(C::*function)(Parameters...))
[email protected]d1e1d5ab2011-12-14 20:59:53126 : m_function(function)
127 {
128 }
129
yutakfbbd4c942016-02-26 07:07:32130 template <typename... IncomingParameters>
131 R operator()(C* c, IncomingParameters&&... parameters)
[email protected]d1e1d5ab2011-12-14 20:59:53132 {
yutakfbbd4c942016-02-26 07:07:32133 return (c->*m_function)(std::forward<IncomingParameters>(parameters)...);
[email protected]d1e1d5ab2011-12-14 20:59:53134 }
135
yutakfbbd4c942016-02-26 07:07:32136 template <typename... IncomingParameters>
137 R operator()(PassOwnPtr<C> c, IncomingParameters&&... parameters)
[email protected]cc685f12015-04-30 14:49:29138 {
yutakfbbd4c942016-02-26 07:07:32139 return (c.get()->*m_function)(std::forward<IncomingParameters>(parameters)...);
[email protected]cc685f12015-04-30 14:49:29140 }
141
yutakfbbd4c942016-02-26 07:07:32142 template <typename... IncomingParameters>
143 R operator()(const WeakPtr<C>& c, IncomingParameters&&... parameters)
[email protected]262e1c52013-01-23 22:15:54144 {
145 C* obj = c.get();
146 if (!obj)
147 return R();
yutakfbbd4c942016-02-26 07:07:32148 return (obj->*m_function)(std::forward<IncomingParameters>(parameters)...);
[email protected]262e1c52013-01-23 22:15:54149 }
150
[email protected]d1e1d5ab2011-12-14 20:59:53151private:
yutakfbbd4c942016-02-26 07:07:32152 R(C::*m_function)(Parameters...);
[email protected]f07bf2fe2011-12-28 19:16:31153};
154
yutakfbbd4c942016-02-26 07:07:32155template <typename T>
156struct ParamStorageTraits {
[email protected]e8ff03612011-12-27 21:39:43157 typedef T StorageType;
158
yutakfbbd4c942016-02-26 07:07:32159 static StorageType wrap(const T& value) { return value; } // Copy.
160 static StorageType wrap(T&& value) { return std::move(value); }
161
162 // Don't move out, because the functor may be called multiple times.
163 static T& unwrap(StorageType& value) { return value; }
[email protected]e8ff03612011-12-27 21:39:43164};
165
yutakfbbd4c942016-02-26 07:07:32166template <typename T>
167struct ParamStorageTraits<PassRefPtr<T>> {
[email protected]e8ff03612011-12-27 21:39:43168 typedef RefPtr<T> StorageType;
169
170 static StorageType wrap(PassRefPtr<T> value) { return value; }
171 static T* unwrap(const StorageType& value) { return value.get(); }
172};
173
yutakfbbd4c942016-02-26 07:07:32174template <typename T>
175struct ParamStorageTraits<RefPtr<T>> {
[email protected]e8ff03612011-12-27 21:39:43176 typedef RefPtr<T> StorageType;
177
[email protected]f07bf2fe2011-12-28 19:16:31178 static StorageType wrap(RefPtr<T> value) { return value.release(); }
[email protected]c12b3c32013-01-17 22:17:12179 static T* unwrap(const StorageType& value) { return value.get(); }
180};
181
yutakfbbd4c942016-02-26 07:07:32182template <typename> class RetainPtr;
[email protected]20b29022011-12-30 19:08:03183
yutakfbbd4c942016-02-26 07:07:32184template <typename T>
185struct ParamStorageTraits<RetainPtr<T>> {
[email protected]20b29022011-12-30 19:08:03186 typedef RetainPtr<T> StorageType;
187
188 static StorageType wrap(const RetainPtr<T>& value) { return value; }
189 static typename RetainPtr<T>::PtrType unwrap(const StorageType& value) { return value.get(); }
190};
191
hiroshigebbe710f2016-02-26 18:21:15192template<> struct ParamStorageTraits<void*> {
193 typedef void* StorageType;
194
195 static StorageType wrap(void* value) { return value; }
196 static void* unwrap(const StorageType& value) { return value; }
197};
198
hiroshige960a5f52016-03-07 19:46:34199enum FunctionThreadAffinity {
200 CrossThreadAffinity,
201 SameThreadAffinity
202};
203
204template<typename, FunctionThreadAffinity threadAffinity = SameThreadAffinity>
[email protected]fc19020d2015-05-08 08:52:23205class Function;
[email protected]b9e13442011-12-14 03:12:15206
hiroshige960a5f52016-03-07 19:46:34207template<FunctionThreadAffinity threadAffinity, typename R, typename... Args>
208class Function<R(Args...), threadAffinity> {
tasak4faca4c42016-01-19 08:38:55209 USING_FAST_MALLOC(Function);
[email protected]fc19020d2015-05-08 08:52:23210 WTF_MAKE_NONCOPYABLE(Function);
[email protected]b9e13442011-12-14 03:12:15211public:
[email protected]fc19020d2015-05-08 08:52:23212 virtual ~Function() { }
[email protected]8beee83e2015-04-21 22:49:05213 virtual R operator()(Args... args) = 0;
[email protected]fc19020d2015-05-08 08:52:23214protected:
215 Function() = default;
hiroshige960a5f52016-03-07 19:46:34216 void checkThread() { }
[email protected]b9e13442011-12-14 03:12:15217};
218
hiroshige960a5f52016-03-07 19:46:34219#if ENABLE(ASSERT)
220template<typename R, typename... Args>
221class Function<R(Args...), SameThreadAffinity> {
222 USING_FAST_MALLOC(Function);
223 WTF_MAKE_NONCOPYABLE(Function);
224public:
225 virtual ~Function()
226 {
227 checkThread();
228 }
229 virtual R operator()(Args... args) = 0;
230protected:
231 Function()
232 : m_createdThread(currentThread())
233 {
234 }
235
236 void NEVER_INLINE checkThread()
237 {
238 // Function with SameThreadAffinity, including SameThreadClosure
239 // created by WTF::bind() or blink::createSameThreadTask(),
240 // must be called and destructed on the thread where it is created.
241 // If it is intended to be used cross-thread, use
242 // blink::threadSafeBind() or blink::createCrossThreadTask() instead.
243 RELEASE_ASSERT(m_createdThread == currentThread());
244 }
245
246private:
247 const ThreadIdentifier m_createdThread;
248};
249#endif
250
251template <FunctionThreadAffinity threadAffinity, typename BoundParametersTuple, typename FunctionWrapper, typename... UnboundParameters>
[email protected]d7a681a2014-09-30 12:34:59252class PartBoundFunctionImpl;
[email protected]c8b1ad82014-07-24 14:52:23253
hiroshige960a5f52016-03-07 19:46:34254template <FunctionThreadAffinity threadAffinity, typename... BoundParameters, typename FunctionWrapper, typename... UnboundParameters>
255class PartBoundFunctionImpl<threadAffinity, std::tuple<BoundParameters...>, FunctionWrapper, UnboundParameters...> final : public Function<typename FunctionWrapper::ResultType(UnboundParameters...), threadAffinity> {
[email protected]c8b1ad82014-07-24 14:52:23256public:
yutakfbbd4c942016-02-26 07:07:32257 // We would like to use StorageTraits<UnboundParameters>... with StorageTraits defined as below in order to obtain
258 // storage traits of UnboundParameters, but unfortunately MSVC can't handle template using declarations correctly.
259 // So, sadly, we have write down the full type signature in all places where storage traits are needed.
260 //
261 // template <typename T>
262 // using StorageTraits = ParamStorageTraits<typename std::decay<T>::type>;
263
264 // Note that BoundParameters can be const T&, T&& or a mix of these.
265 explicit PartBoundFunctionImpl(FunctionWrapper functionWrapper, BoundParameters... bound)
[email protected]c8b1ad82014-07-24 14:52:23266 : m_functionWrapper(functionWrapper)
yutakfbbd4c942016-02-26 07:07:32267 , m_bound(ParamStorageTraits<typename std::decay<BoundParameters>::type>::wrap(std::forward<BoundParameters>(bound))...)
[email protected]c8b1ad82014-07-24 14:52:23268 {
269 }
270
yutak2a02e482016-02-09 05:55:05271 typename FunctionWrapper::ResultType operator()(UnboundParameters... unbound) override
[email protected]c8b1ad82014-07-24 14:52:23272 {
yutak2a02e482016-02-09 05:55:05273 // What we really want to do is to call m_functionWrapper(m_bound..., unbound...), but to do that we need to
274 // pass a list of indices to a worker function template.
finnur54fbc8362016-03-03 10:41:04275 return callInternal(base::MakeIndexSequence<sizeof...(BoundParameters)>(), std::forward<UnboundParameters>(unbound)...);
[email protected]c8b1ad82014-07-24 14:52:23276 }
277
278private:
finnur54fbc8362016-03-03 10:41:04279 template <std::size_t... boundIndices, typename... IncomingUnboundParameters>
280 typename FunctionWrapper::ResultType callInternal(const base::IndexSequence<boundIndices...>&, IncomingUnboundParameters&&... unbound)
yutak2a02e482016-02-09 05:55:05281 {
hiroshige960a5f52016-03-07 19:46:34282 this->checkThread();
yutak2a02e482016-02-09 05:55:05283 // Get each element in m_bound, unwrap them, and call the function with the desired arguments.
finnur54fbc8362016-03-03 10:41:04284 return m_functionWrapper(ParamStorageTraits<typename std::decay<BoundParameters>::type>::unwrap(std::get<boundIndices>(m_bound))..., std::forward<IncomingUnboundParameters>(unbound)...);
yutak2a02e482016-02-09 05:55:05285 }
286
[email protected]c8b1ad82014-07-24 14:52:23287 FunctionWrapper m_functionWrapper;
yutakfbbd4c942016-02-26 07:07:32288 std::tuple<typename ParamStorageTraits<typename std::decay<BoundParameters>::type>::StorageType...> m_bound;
lushnikov1466f352015-11-18 03:53:06289};
290
hiroshige960a5f52016-03-07 19:46:34291template <FunctionThreadAffinity threadAffinity, typename... UnboundParameters, typename FunctionType, typename... BoundParameters>
292PassOwnPtr<Function<typename FunctionWrapper<FunctionType>::ResultType(UnboundParameters...), threadAffinity>> bindInternal(FunctionType function, BoundParameters&&... boundParameters)
[email protected]c8b1ad82014-07-24 14:52:23293{
yutak2a02e482016-02-09 05:55:05294 // Bound parameters' types are wrapped with std::tuple so we can pass two template parameter packs (bound
295 // parameters and unbound) to PartBoundFunctionImpl. Note that a tuple of this type isn't actually created;
296 // std::tuple<> is just for carrying the bound parameters' types. Any other class template taking a type parameter
297 // pack can be used instead of std::tuple. std::tuple is used just because it's most convenient for this purpose.
hiroshige960a5f52016-03-07 19:46:34298 using BoundFunctionType = PartBoundFunctionImpl<threadAffinity, std::tuple<BoundParameters&&...>, FunctionWrapper<FunctionType>, UnboundParameters...>;
yutakfbbd4c942016-02-26 07:07:32299 return adoptPtr(new BoundFunctionType(FunctionWrapper<FunctionType>(function), std::forward<BoundParameters>(boundParameters)...));
[email protected]c8b1ad82014-07-24 14:52:23300}
301
hiroshige960a5f52016-03-07 19:46:34302template <typename... UnboundParameters, typename FunctionType, typename... BoundParameters>
303PassOwnPtr<Function<typename FunctionWrapper<FunctionType>::ResultType(UnboundParameters...), SameThreadAffinity>> bind(FunctionType function, BoundParameters&&... boundParameters)
304{
305 return bindInternal<SameThreadAffinity, UnboundParameters...>(function, std::forward<BoundParameters>(boundParameters)...);
306}
307
308typedef Function<void(), SameThreadAffinity> SameThreadClosure;
309typedef Function<void(), CrossThreadAffinity> CrossThreadClosure;
[email protected]2105a9b2013-05-16 20:04:15310
thakise7149692016-01-23 23:19:00311} // namespace WTF
[email protected]b9e13442011-12-14 03:12:15312
313using WTF::Function;
314using WTF::bind;
hiroshige960a5f52016-03-07 19:46:34315using WTF::SameThreadClosure;
316using WTF::CrossThreadClosure;
[email protected]b9e13442011-12-14 03:12:15317
318#endif // WTF_Functional_h