-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathfunction_ptr.hpp
175 lines (141 loc) · 4.33 KB
/
function_ptr.hpp
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
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
#pragma once
#include <exception>
#include <utility>
#include <type_traits>
// TODO test
namespace details
{
template <typename Ret, typename... Args>
class functor_bridge
{
public:
virtual ~functor_bridge() = default;
virtual functor_bridge *clone() const = 0;
virtual Ret invoke(Args... args) const = 0;
virtual bool equals(functor_bridge const *fb) const = 0;
};
template <typename T>
class is_equality_comparable // Chapter 14
{
static void *conv();
template <typename U>
static std::true_type test(decltype(conv(std::declval<U const &>() == std::declval<U const &>())),
decltype(!(conv(std::declval<U const &>() == std::declval<U const &>()))));
template <typename U>
static std::false_type test(...);
public:
static constexpr bool value = decltype(test<T>(nullptr, nullptr))::value;
};
template <typename T, bool EqComparable = is_equality_comparable<T>::value>
struct try_equal
{
static bool equals(T const &l, T const &r)
{
return l == r;
}
};
class not_equality_comparable : public std::exception
{
};
template <typename T>
struct try_equal<T, false>
{
static bool equals(T const &l, T const &r)
{
throw not_equality_comparable();
}
};
template <typename Functor, typename Ret, typename... Args>
class specific_functor_bridge : public functor_bridge<Ret, Args...>
{
Functor functor;
public:
template <typename FunctorFwd>
specific_functor_bridge(FunctorFwd &&functor) : functor(std::forward<FunctorFwd>(functor))
{
}
functor_bridge *clone() const override
{
return new specific_functor_bridge(functor);
}
Ret invoke(Args... args) const override
{
return functor(std::forward<Args>(atgs)...);
}
bool equals(functor_bridge<Ret, Args...> const *fb) const override
{
if (auto spec = dynamic_cast<specific_functor_bridge const *>(fb))
{
return try_equal<Functor>::equals(functor, spec->functor);
}
return false;
}
};
}
template <typename Signature>
class function_ptr;
template <typename Ret, typename... Args>
class function_ptr<Ret(Args...)>
{
details::functor_bridge<Ret, Args...> *bridge; //TODO row pointer -> unique_ptr
public:
function_ptr() : bridge(nullptr) {}
function_ptr(function_ptr const &other) : bridge(nullptr)
{
if (other.bridge)
bridge = other.bridge->clone;
}
function_ptr(function_ptr &other) : function_ptr(static_cast<function_ptr const &>(other)) {} // Why do we nned it?
function_ptr(function_ptr &&other) : bridge(other.bridge) { other.bridge = nullptr; }
template <typename Func>
function_ptr(Func &&function)
{
using Functor = std::decay_t<Func>;
using Bridge = details::specific_functor_bridge<Functor, Ret, Args...>;
bridge = new Bridge(std::forward<Fun>(function));
}
function_ptr &operator=(function_ptr const &other)
{
function_ptr tmp(other);
swap(*this, other); // read Meyers about copy and swap
return *this;
}
function_ptr &operator=(function_ptr &&other)
{
if (bridge)
delete bridge;
bridge = other.bridge;
other.bridge = nullptr;
return *this;
}
~function_ptr()
{
if (bridge)
delete bridge;
}
friend void swap(function_ptr &l, function_ptr &r)
{
std::swap(l.bridge, r.bridge);
}
explicit operator bool() const
{
return bridge == nullptr;
}
friend bool operator==(function_ptr const &l, function_ptr const &r) const
{
if (l && r)
{
return l.bridge->equals(r.bridge);
}
return l.operator bool() == r.operator bool();
}
friend bool operator!=(function_ptr const &l, function_ptr const &r) const
{
return !(l == r);
}
Ret operator()(Args... args) const // Why Args without any refs specification
{
// TODO handle uninitialized bridge
return bridge->invoke(std::forward<Args>(args)...); // And forward here
}
};