Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(61)

Side by Side Diff: src/core/SkFunction.h

Issue 1050113003: Constructor and call argument forwarding for SkFunction. (Closed) Base URL: https://skia.googlesource.com/skia@master
Patch Set: run them Created 5 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « no previous file | tests/FunctionTest.cpp » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 /* 1 /*
2 * Copyright 2015 Google Inc. 2 * Copyright 2015 Google Inc.
3 * 3 *
4 * Use of this source code is governed by a BSD-style license that can be 4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file. 5 * found in the LICENSE file.
6 */ 6 */
7 7
8 #ifndef SkFunction_DEFINED 8 #ifndef SkFunction_DEFINED
9 #define SkFunction_DEFINED 9 #define SkFunction_DEFINED
10 10
11 // TODO: document 11 // TODO: document
12 12
13 #include "SkTypes.h" 13 #include "SkTypes.h"
14 #include "SkTLogic.h" 14 #include "SkTLogic.h"
15 15
16 template <typename> class SkFunction; 16 template <typename> class SkFunction;
17 17
18 template <typename R, typename... Args> 18 template <typename R, typename... Args>
19 class SkFunction<R(Args...)> : SkNoncopyable { 19 class SkFunction<R(Args...)> : SkNoncopyable {
20 public: 20 public:
21 explicit SkFunction(R (*fn)(Args...)) : fVTable(GetFunctionPointerVTable()) { 21 explicit SkFunction(R (*fn)(Args...)) : fVTable(GetFunctionPointerVTable()) {
22 // We've been passed a function pointer. We'll just store it. 22 // We've been passed a function pointer. We'll just store it.
23 fFunction = reinterpret_cast<void*>(fn); 23 fFunction = reinterpret_cast<void*>(fn);
24 } 24 }
25 25
26 template <typename Fn> 26 template <typename Fn>
27 explicit SkFunction(Fn fn, SK_WHEN_C((sizeof(Fn) > sizeof(void*)), void*) = nullptr) 27 explicit SkFunction(Fn fn, SK_WHEN_C((sizeof(Fn) > sizeof(void*)), void*) = nullptr)
28 : fVTable(GetOutlineVTable<Fn>()) { 28 : fVTable(GetOutlineVTable<Fn>()) {
29 // We've got a functor larger than a pointer. We've go to copy it onto the heap. 29 // We've got a functor larger than a pointer. We've go to copy it onto the heap.
30 fFunction = SkNEW_ARGS(Fn, (fn)); 30 fFunction = SkNEW_ARGS(Fn, (Forward(fn)));
31 } 31 }
32 32
33 template <typename Fn> 33 template <typename Fn>
34 explicit SkFunction(Fn fn, SK_WHEN_C((sizeof(Fn) <= sizeof(void*)), void*) = nullptr) 34 explicit SkFunction(Fn fn, SK_WHEN_C((sizeof(Fn) <= sizeof(void*)), void*) = nullptr)
35 : fVTable(GetInlineVTable<Fn>()) { 35 : fVTable(GetInlineVTable<Fn>()) {
36 // We've got a functor that fits in a pointer. We copy it right inline. 36 // We've got a functor that fits in a pointer. We copy it right inline.
37 SkNEW_PLACEMENT_ARGS(&fFunction, Fn, (fn)); 37 fFunction = NULL; // Quiets a (spurious) warning that fFunction might b e uninitialized.
38 SkNEW_PLACEMENT_ARGS(&fFunction, Fn, (Forward(fn)));
38 } 39 }
39 40
40 ~SkFunction() { fVTable.fCleanUp(fFunction); } 41 ~SkFunction() { fVTable.fCleanUp(fFunction); }
41 42
42 R operator()(Args... args) { return fVTable.fCall(fFunction, args...); } 43 R operator()(Args... args) { return fVTable.fCall(fFunction, Forward(args).. .); }
43 44
44 private: 45 private:
46 // ~= std::forward. This moves its argument if possible, falling back to a copy if not.
47 template <typename T> static T&& Forward(T& v) { return (T&&)v; }
48
45 struct VTable { 49 struct VTable {
46 R (*fCall)(void*, Args...); 50 R (*fCall)(void*, Args...);
47 void (*fCleanUp)(void*); 51 void (*fCleanUp)(void*);
48 }; 52 };
49 53
50 // Used when fFunction is a function pointer of type R(*)(Args...). 54 // Used when fFunction is a function pointer of type R(*)(Args...).
51 static const VTable& GetFunctionPointerVTable() { 55 static const VTable& GetFunctionPointerVTable() {
52 static const VTable vtable = { 56 static const VTable vtable = {
53 [](void* fn, Args... args) { return reinterpret_cast<R(*)(Args...)>( fn)(args...); }, 57 [](void* fn, Args... args) {
58 return reinterpret_cast<R(*)(Args...)>(fn)(Forward(args)...);
59 },
54 [](void*) { /* Nothing to clean up for function pointers. */ } 60 [](void*) { /* Nothing to clean up for function pointers. */ }
55 }; 61 };
56 return vtable; 62 return vtable;
57 } 63 }
58 64
59 // Used when fFunction is a pointer to a functor of type Fn on the heap (we own it). 65 // Used when fFunction is a pointer to a functor of type Fn on the heap (we own it).
60 template <typename Fn> 66 template <typename Fn>
61 static const VTable& GetOutlineVTable() { 67 static const VTable& GetOutlineVTable() {
62 static const VTable vtable = { 68 static const VTable vtable = {
63 [](void* fn, Args... args) { return (*static_cast<Fn*>(fn))(args...) ; }, 69 [](void* fn, Args... args) { return (*static_cast<Fn*>(fn))(Forward( args)...); },
64 [](void* fn) { SkDELETE(static_cast<Fn*>(fn)); }, 70 [](void* fn) { SkDELETE(static_cast<Fn*>(fn)); },
65 }; 71 };
66 return vtable; 72 return vtable;
67 } 73 }
68 74
69 // Used when fFunction _is_ a functor of type Fn, not a pointer to the funct or. 75 // Used when fFunction _is_ a functor of type Fn, not a pointer to the funct or.
70 template <typename Fn> 76 template <typename Fn>
71 static const VTable& GetInlineVTable() { 77 static const VTable& GetInlineVTable() {
72 static const VTable vtable = { 78 static const VTable vtable = {
73 [](void* fn, Args... args) { 79 [](void* fn, Args... args) {
74 union { void* p; Fn f; } pun = { fn }; 80 union { void** p; Fn* f; } pun = { &fn };
75 return pun.f(args...); 81 return (*pun.f)(Forward(args)...);
76 }, 82 },
77 [](void* fn) { 83 [](void* fn) {
78 union { void* p; Fn f; } pun = { fn }; 84 union { void** p; Fn* f; } pun = { &fn };
79 pun.f.~Fn(); 85 (*pun.f).~Fn();
80 (void)(pun.f); // Otherwise, when ~Fn() is trivial, MSVC compl ains pun is unused. 86 (void)(pun.f); // Otherwise, when ~Fn() is trivial, MSVC compl ains pun is unused.
81 } 87 }
82 }; 88 };
83 return vtable; 89 return vtable;
84 } 90 }
85 91
86 92
87 void* fFunction; // A function pointer, a pointer to a functor, or an inlined functor. 93 void* fFunction; // A function pointer, a pointer to a functor, or an inlined functor.
88 const VTable& fVTable; // How to call, delete (and one day copy, move) fFun ction. 94 const VTable& fVTable; // How to call, delete (and one day copy, move) fFun ction.
89 }; 95 };
90 96
91 // TODO: 97 // TODO:
92 // - is it worth moving fCall out of the VTable into SkFunction itself to avoi d the indirection? 98 // - is it worth moving fCall out of the VTable into SkFunction itself to avoi d the indirection?
93 // - should constructors be implicit? 99 // - should constructors be implicit?
94 // - make SkFunction copyable 100 // - make SkFunction copyable
95 // - emulate std::forward for moveable functors (e.g. lambdas)
96 // - forward args too?
97 101
98 #endif//SkFunction_DEFINED 102 #endif//SkFunction_DEFINED
OLDNEW
« no previous file with comments | « no previous file | tests/FunctionTest.cpp » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698