386552ce2efea90d75938ffa3ca24626bd03cae4
[WebKit-https.git] / Source / WTF / wtf / SharedTask.h
1 /*
2  * Copyright (C) 2015-2017 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 SharedTask_h
27 #define SharedTask_h
28
29 #include <wtf/Ref.h>
30 #include <wtf/ThreadSafeRefCounted.h>
31
32 namespace WTF {
33
34 // SharedTask is a replacement for std::function for cases where:
35 //
36 // - You'd like to avoid the cost of copying, and would prefer to have reference semantics rather
37 //   than value semantics.
38 // - You want to use FastMalloc rather than system malloc. Note that std::function may avoid malloc
39 //   entirely in some cases, but that's hard to guarantee.
40 // - You intend to share the task with other threads and so want thread-safe reference counting.
41 //
42 // Here's an example of how SharedTask can be better than std::function. If you do:
43 //
44 // std::function<int(double)> a = b;
45 //
46 // Then "a" will get its own copy of all captured by-value variables. The act of copying may
47 // require calls to system malloc, and it may be linear time in the total size of captured
48 // variables. On the other hand, if you do:
49 //
50 // RefPtr<SharedTask<int(double)> a = b;
51 //
52 // Then "a" will point to the same task as b, and the only work involved is the CAS to increase the
53 // reference count.
54 //
55 // Also, SharedTask allows for more flexibility when sharing state between everyone who runs the
56 // task. With std::function, you can only share state using by-reference captured variables.
57 // SharedTask supports this since, like std::function, it can be built from a lambda (see
58 // createSharedTask(), below). But SharedTask also allows you to create your own subclass and put
59 // state in member fields. This can be more natural if you want fine-grained control over what
60 // state is shared between instances of the task.
61 template<typename FunctionType> class SharedTask;
62 template<typename ResultType, typename... ArgumentTypes>
63 class SharedTask<ResultType (ArgumentTypes...)> : public ThreadSafeRefCounted<SharedTask<ResultType (ArgumentTypes...)>> {
64 public:
65     SharedTask() { }
66     virtual ~SharedTask() { }
67
68     virtual ResultType run(ArgumentTypes...) = 0;
69 };
70
71 // This is a utility class that allows you to create a SharedTask subclass using a lambda. Usually,
72 // you don't want to use this class directly. Use createSharedTask() instead.
73 template<typename FunctionType, typename Functor> class SharedTaskFunctor;
74 template<typename ResultType, typename... ArgumentTypes, typename Functor>
75 class SharedTaskFunctor<ResultType (ArgumentTypes...), Functor> : public SharedTask<ResultType (ArgumentTypes...)> {
76 public:
77     SharedTaskFunctor(const Functor& functor)
78         : m_functor(functor)
79     {
80     }
81
82     SharedTaskFunctor(Functor&& functor)
83         : m_functor(WTFMove(functor))
84     {
85     }
86
87 private:
88     ResultType run(ArgumentTypes... arguments) override
89     {
90         return m_functor(std::forward<ArgumentTypes>(arguments)...);
91     }
92
93     Functor m_functor;
94 };
95
96 // Create a SharedTask from a functor, such as a lambda. You can use this like so:
97 //
98 // RefPtr<SharedTask<void()>> task = createSharedTask<void()>(
99 //     [=] () {
100 //         do things;
101 //     });
102 //
103 // Note that if you use the [&] capture list, then you're probably doing it wrong. That's because
104 // [&] will lead to pointers to the stack (the only exception is if you do something like &x where
105 // x is a reference to the heap - but in that case, it's better to use [=, &x] to be explicit). You
106 // probably don't want pointers to the stack if you will have tasks running on other threads.
107 // Probably the best way to be sure that you're not making a horrible mistake is to always use
108 // explicit capture lists. In many cases, [this] is sufficient.
109 //
110 // On the other hand, if you use something like ParallelHelperClient::runTaskInParallel() (or its
111 // helper, runFunctionInParallel(), which does createSharedTask() for you), then it can be OK to
112 // use [&], since the stack frame will remain live for the entire duration of the task's lifetime.
113 template<typename FunctionType, typename Functor>
114 Ref<SharedTask<FunctionType>> createSharedTask(const Functor& functor)
115 {
116     return adoptRef(*new SharedTaskFunctor<FunctionType, Functor>(functor));
117 }
118 template<typename FunctionType, typename Functor>
119 Ref<SharedTask<FunctionType>> createSharedTask(Functor&& functor)
120 {
121     return adoptRef(*new SharedTaskFunctor<FunctionType, Functor>(WTFMove(functor)));
122 }
123
124 } // namespace WTF
125
126 using WTF::createSharedTask;
127 using WTF::SharedTask;
128 using WTF::SharedTaskFunctor;
129
130 #endif // SharedTask_h
131