Kiwano Engine v1.3.x
Function.h
1// Copyright (c) 2016-2018 Kiwano - Nomango
2//
3// Permission is hereby granted, free of charge, to any person obtaining a copy
4// of this software and associated documentation files (the "Software"), to deal
5// in the Software without restriction, including without limitation the rights
6// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7// copies of the Software, and to permit persons to whom the Software is
8// furnished to do so, subject to the following conditions:
9//
10// The above copyright notice and this permission notice shall be included in
11// all copies or substantial portions of the Software.
12//
13// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
19// THE SOFTWARE.
20
21#pragma once
22#include <typeinfo>
23#include <type_traits>
24#include <stdexcept>
25#include <functional>
26
27namespace kiwano
28{
29namespace details
30{
31
32template <typename _Ty, typename _Ret, typename... _Args>
34{
35 template <typename _Uty, _Ret (_Uty::*)(_Args...)>
37
38 template <typename _Uty, _Ret (_Uty::*)(_Args...) const>
40
41 template <typename _Uty>
42 static int Test(...);
43
44 template <typename _Uty>
45 static char Test(ClassMember<_Uty, &_Uty::operator()>*);
46
47 template <typename _Uty>
48 static char Test(ClassConstMember<_Uty, &_Uty::operator()>*);
49
50 template <
51 typename _Uty,
52 typename _Uret = typename std::decay<decltype(std::declval<_Uty>().operator()(std::declval<_Args>()...))>::type,
53 typename = typename std::enable_if<std::is_convertible<_Ret, _Uret>::value>::type>
54 static char Test(int);
55
56 static constexpr bool value = sizeof(Test<_Ty>(0)) == sizeof(char);
57};
58
59template <typename _Ty, typename _Ret, typename... _Args>
60struct IsCallable : public std::bool_constant<IsCallableHelper<_Ty, _Ret, _Args...>::value>
61{
62};
63
64//
65// Callable
66//
67
68template <typename _Ret, typename... _Args>
70{
71public:
72 virtual ~Callable() {}
73
74 virtual void Retain() = 0;
75 virtual void Release() = 0;
76 virtual _Ret Invoke(_Args&&... args) const = 0;
77
78 virtual const std::type_info& TargetType() const noexcept = 0;
79
80 virtual const void* Target(const std::type_info& type) const noexcept = 0;
81};
82
83template <typename _Ret, typename... _Args>
84class RefCountCallable : public Callable<_Ret, _Args...>
85{
86public:
88 : ref_count_(0)
89 {
90 }
91
92 virtual void Retain() override
93 {
94 ++ref_count_;
95 }
96
97 virtual void Release() override
98 {
99 --ref_count_;
100 if (ref_count_ <= 0)
101 {
102 delete this;
103 }
104 }
105
106private:
107 int ref_count_;
108};
109
110template <typename _Ty, typename _Ret, typename... _Args>
111class ProxyCallable : public RefCountCallable<_Ret, _Args...>
112{
113public:
114 ProxyCallable(_Ty&& val)
115 : callee_(std::move(val))
116 {
117 }
118
119 virtual _Ret Invoke(_Args&&... args) const override
120 {
121 return std::invoke(callee_, std::forward<_Args>(args)...);
122 }
123
124 virtual const std::type_info& TargetType() const noexcept
125 {
126 return typeid(_Ty);
127 }
128
129 virtual const void* Target(const std::type_info& type) const noexcept
130 {
131 if (type == this->TargetType())
132 return &callee_;
133 return nullptr;
134 }
135
136 static inline Callable<_Ret, _Args...>* Make(_Ty&& val)
137 {
138 return new (std::nothrow) ProxyCallable<_Ty, _Ret, _Args...>(std::move(val));
139 }
140
141private:
142 _Ty callee_;
143};
144
145template <typename _Ty, typename _Ret, typename... _Args>
146class ProxyMemCallable : public RefCountCallable<_Ret, _Args...>
147{
148public:
149 typedef _Ret (_Ty::*_FuncType)(_Args...);
150
151 virtual _Ret Invoke(_Args&&... args) const override
152 {
153 return std::invoke(func_, ptr_, std::forward<_Args>(args)...);
154 }
155
156 virtual const std::type_info& TargetType() const noexcept
157 {
158 return typeid(ProxyMemCallable);
159 }
160
161 virtual const void* Target(const std::type_info& type) const noexcept
162 {
163 if (type == this->TargetType())
164 return this;
165 return nullptr;
166 }
167
168 static inline Callable<_Ret, _Args...>* Make(_Ty* ptr, _FuncType func)
169 {
170 return new (std::nothrow) ProxyMemCallable<_Ty, _Ret, _Args...>(ptr, func);
171 }
172
173protected:
174 ProxyMemCallable(_Ty* ptr, _FuncType func)
175 : ptr_(ptr)
176 , func_(func)
177 {
178 }
179
180protected:
181 _Ty* ptr_;
182 _FuncType func_;
183};
184
185template <typename _Ty, typename _Ret, typename... _Args>
186class ProxyConstMemCallable : public RefCountCallable<_Ret, _Args...>
187{
188public:
189 typedef _Ret (_Ty::*_FuncType)(_Args...) const;
190
191 virtual _Ret Invoke(_Args&&... args) const override
192 {
193 return std::invoke(func_, ptr_, std::forward<_Args>(args)...);
194 }
195
196 virtual const std::type_info& TargetType() const noexcept
197 {
198 return typeid(ProxyConstMemCallable);
199 }
200
201 virtual const void* Target(const std::type_info& type) const noexcept
202 {
203 if (type == this->TargetType())
204 return this;
205 return nullptr;
206 }
207
208 static inline Callable<_Ret, _Args...>* Make(_Ty* ptr, _FuncType func)
209 {
210 return new (std::nothrow) ProxyConstMemCallable<_Ty, _Ret, _Args...>(ptr, func);
211 }
212
213protected:
214 ProxyConstMemCallable(_Ty* ptr, _FuncType func)
215 : ptr_(ptr)
216 , func_(func)
217 {
218 }
219
220protected:
221 _Ty* ptr_;
222 _FuncType func_;
223};
224
225} // namespace details
226
227template <typename _Ty>
229
230template <typename _Ret, typename... _Args>
231class Function<_Ret(_Args...)>
232{
233public:
234 Function()
235 : callable_(nullptr)
236 {
237 }
238
239 Function(std::nullptr_t)
240 : callable_(nullptr)
241 {
242 }
243
244 Function(const Function& rhs)
245 : callable_(nullptr)
246 {
247 SetCallable(rhs.callable_);
248 }
249
250 Function(Function&& rhs) noexcept
251 : callable_(rhs.callable_)
252 {
253 rhs.callable_ = nullptr;
254 }
255
256 Function(_Ret (*func)(_Args...))
257 : callable_(nullptr)
258 {
259 SetCallable(details::ProxyCallable<_Ret (*)(_Args...), _Ret, _Args...>::Make(std::move(func)));
260 }
261
262 template <typename _Ty,
263 typename = typename std::enable_if<details::IsCallable<_Ty, _Ret, _Args...>::value, int>::type>
264 Function(_Ty val)
265 : callable_(nullptr)
266 {
267 SetCallable(details::ProxyCallable<_Ty, _Ret, _Args...>::Make(std::move(val)));
268 }
269
270 template <typename _Ty, typename _Uty,
271 typename = typename std::enable_if<std::is_same<_Ty, _Uty>::value || std::is_base_of<_Ty, _Uty>::value,
272 int>::type>
273 Function(_Uty* ptr, _Ret (_Ty::*func)(_Args...))
274 : callable_(nullptr)
275 {
277 }
278
279 template <typename _Ty, typename _Uty,
280 typename = typename std::enable_if<std::is_same<_Ty, _Uty>::value || std::is_base_of<_Ty, _Uty>::value,
281 int>::type>
282 Function(_Uty* ptr, _Ret (_Ty::*func)(_Args...) const)
283 : callable_(nullptr)
284 {
286 }
287
288 ~Function()
289 {
290 SetCallable(nullptr);
291 }
292
293 inline _Ret operator()(_Args... args) const
294 {
295 if (!callable_)
296 throw std::bad_function_call();
297 return callable_->Invoke(std::forward<_Args>(args)...);
298 }
299
300 inline operator bool() const
301 {
302 return !!callable_;
303 }
304
305 inline Function& operator=(const Function& rhs)
306 {
307 SetCallable(rhs.callable_);
308 return (*this);
309 }
310
311 inline Function& operator=(Function&& rhs)
312 {
313 SetCallable(nullptr);
314 callable_ = rhs.callable_;
315 rhs.callable_ = nullptr;
316 return (*this);
317 }
318
319 inline void swap(const Function& rhs)
320 {
321 std::swap(callable_, rhs.callable_);
322 }
323
324 const std::type_info& target_type() const noexcept
325 {
326 return callable_->TargetType();
327 }
328
329 template <class _Fx>
330 _Fx* target() noexcept
331 {
332 return reinterpret_cast<_Fx*>(const_cast<void*>(callable_->Target(typeid(_Fx))));
333 }
334
335 template <class _Fx>
336 const _Fx* target() const noexcept
337 {
338 return reinterpret_cast<const _Fx*>(callable_->Target(typeid(_Fx)));
339 }
340
341private:
342 inline void SetCallable(details::Callable<_Ret, _Args...>* callable)
343 {
344 if (callable_ != callable)
345 {
346 if (callable_)
347 {
348 callable_->Release();
349 callable_ = nullptr;
350 }
351
352 callable_ = callable;
353 if (callable_)
354 {
355 callable_->Retain();
356 }
357 }
358 }
359
360private:
361 details::Callable<_Ret, _Args...>* callable_;
362};
363
364template <
365 typename _Ty, typename _Uty,
366 typename = typename std::enable_if<std::is_same<_Ty, _Uty>::value || std::is_base_of<_Ty, _Uty>::value, int>::type,
367 typename _Ret, typename... _Args>
368inline Function<_Ret(_Args...)> Closure(_Uty* ptr, _Ret (_Ty::*func)(_Args...))
369{
370 return Function<_Ret(_Args...)>(ptr, func);
371}
372
373template <
374 typename _Ty, typename _Uty,
375 typename = typename std::enable_if<std::is_same<_Ty, _Uty>::value || std::is_base_of<_Ty, _Uty>::value, int>::type,
376 typename _Ret, typename... _Args>
377inline Function<_Ret(_Args...)> Closure(_Uty* ptr, _Ret (_Ty::*func)(_Args...) const)
378{
379 return Function<_Ret(_Args...)>(ptr, func);
380}
381
382template <typename _Ret, typename... _Args>
383inline void swap(kiwano::Function<_Ret(_Args...)>& lhs, kiwano::Function<_Ret(_Args...)>& rhs) noexcept
384{
385 lhs.swap(rhs);
386}
387
388} // namespace kiwano
Definition: Function.h:228
Definition: Function.h:70
Definition: Function.h:112
Definition: Function.h:187
Definition: Function.h:147
Definition: Function.h:85
Definition: Function.h:34
Definition: Function.h:61