-
Notifications
You must be signed in to change notification settings - Fork 11
/
Copy pathfunction.h
128 lines (108 loc) · 2.79 KB
/
function.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
#pragma once
#include <utility>
template <typename F>
struct function;
class bad_function_call : std::exception {
};
template <typename F>
void delete_func(void* obj) {
delete static_cast<F*>(obj);
}
template <typename F, typename R, typename... Args>
R invoker_func(void* obj, Args... args) {
return (*static_cast<F*>(obj))(std::forward<Args>(args)...);
}
template <typename T>
void *copy_obj(void* obj) {
return new T(*static_cast<T*>(obj));
}
template <typename R, typename... Args>
struct function<R (Args...)>
{
function() noexcept :
copier(nullptr),
obj(nullptr),
deleter(nullptr),
invoker(nullptr),
id(typeid(void).name()) {
}
function(function const& other) :
copier(other.copier),
obj(other.obj ? copier(other.obj) : nullptr),
deleter(other.deleter),
invoker(other.invoker),
id(other.id) {
}
function(function&& other) noexcept : function() {
swap(std::move(other));
}
template <typename T>
function(T val) :
copier(©_obj<T>),
obj(new T(std::move(val))),
deleter(&delete_func<T>),
invoker(&invoker_func<T, R, Args...>),
id(typeid(T).name()) {
}
function& operator=(function const& rhs) {
if (this != &rhs) {
copier = rhs.copier;
if (rhs.obj) {
obj = copier(rhs.obj);
} else {
obj = nullptr;
}
deleter = rhs.deleter;
invoker = rhs.invoker;
id = rhs.id;
}
return *this;
}
function& operator=(function&& rhs) noexcept {
swap(std::move(rhs));
return *this;
}
~function() {
if (deleter) {
deleter(obj);
}
}
explicit operator bool() const noexcept {
return obj != nullptr;
}
R operator()(Args... args) const {
if (invoker == nullptr) {
throw bad_function_call();
}
return invoker(obj, std::forward<Args>(args)...);
}
template <typename T>
T* target() noexcept {
if (typeid(T).name() == id) {
return static_cast<T*>(obj);
} else {
return nullptr;
}
}
template <typename T>
T const* target() const noexcept {
if (typeid(T).name() == id) {
return static_cast<T*>(obj);
} else {
return nullptr;
}
}
private:
void* (*copier)(void*);
void* obj;
void (*deleter)(void*);
R (*invoker)(void*, Args...);
std::string id;
void swap(function&& rhs) {
std::swap(copier, rhs.copier);
std::swap(obj, rhs.obj);
std::swap(deleter, rhs.deleter);
std::swap(invoker, rhs.invoker);
std::swap(id, rhs.id);
}
};