// Copyright (c) 2016-2018 Kiwano - Nomango // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal // in the Software without restriction, including without limitation the rights // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell // copies of the Software, and to permit persons to whom the Software is // furnished to do so, subject to the following conditions: // // The above copyright notice and this permission notice shall be included in // all copies or substantial portions of the Software. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN // THE SOFTWARE. #pragma once #include #include namespace kiwano { inline namespace core { // // function is a light weight ::std::function<>-like class // namespace __function_detail { // // is_callable // namespace __callable_detail { template struct helper { template static int test(...); template struct class_mem; template static char test(class_mem<_Uty, &_Uty::operator()>*); template struct class_const_mem; template static char test(class_const_mem<_Uty, &_Uty::operator()>*); template< typename _Uty, typename _Uret = typename ::std::decay().operator()(::std::declval<_Args>()...))>::type, typename = typename ::std::enable_if<::std::is_convertible<_Ret, _Uret>::value>::type> static char test(int); static constexpr bool value = sizeof(test<_Ty>(0)) == sizeof(char); }; } template struct is_callable : public ::std::bool_constant<__callable_detail::helper<_Ty, _Ret, _Args...>::value> { }; // // callable // template class callable { public: virtual ~callable() {} virtual void AddRef() = 0; virtual void Release() = 0; virtual _Ret Invoke(_Args... args) const = 0; }; template class ref_count_callable : public callable<_Ret, _Args...> { public: ref_count_callable() : ref_count_(0) {} virtual void AddRef() override { ++ref_count_; } virtual void Release() override { --ref_count_; if (ref_count_ <= 0) { delete this; } } private: int ref_count_; }; template class proxy_callable : public ref_count_callable<_Ret, _Args...> { public: proxy_callable(_Ty&& val) : callee_(::std::move(val)) { } virtual _Ret Invoke(_Args... args) const override { return callee_(::std::forward<_Args&&>(args)...); } static inline callable<_Ret, _Args...>* Make(_Ty&& val) { return new (::std::nothrow) proxy_callable<_Ty, _Ret, _Args...>(::std::move(val)); } private: _Ty callee_; }; template class proxy_mem_callable : public ref_count_callable<_Ret, _Args...> { public: typedef _Ret(_Ty::* _FuncType)(_Args...); virtual _Ret Invoke(_Args... args) const override { return (static_cast<_Ty*>(ptr_)->*func_)(::std::forward<_Args>(args)...); } static inline callable<_Ret, _Args...>* Make(void* ptr, _FuncType func) { return new (::std::nothrow) proxy_mem_callable<_Ty, _Ret, _Args...>(ptr, func); } protected: proxy_mem_callable(void* ptr, _FuncType func) : ptr_(ptr) , func_(func) { } protected: void* ptr_; _FuncType func_; }; template class proxy_const_mem_callable : public ref_count_callable<_Ret, _Args...> { public: typedef _Ret(_Ty::* _FuncType)(_Args...) const; virtual _Ret Invoke(_Args... args) const override { return (static_cast<_Ty*>(ptr_)->*func_)(::std::forward<_Args>(args)...); } static inline callable<_Ret, _Args...>* Make(void* ptr, _FuncType func) { return new (::std::nothrow) proxy_const_mem_callable<_Ty, _Ret, _Args...>(ptr, func); } protected: proxy_const_mem_callable(void* ptr, _FuncType func) : ptr_(ptr) , func_(func) { } protected: void* ptr_; _FuncType func_; }; } // // exceptions // class bad_function_call : public ::std::exception { public: bad_function_call() {} virtual const char* what() const override { return "bad function call"; } }; // // function details // template class function; template class function<_Ret(_Args...)> { public: function() : callable_(nullptr) { } function(::std::nullptr_t) : callable_(nullptr) { } function(const function& rhs) : callable_(rhs.callable_) { if (callable_) callable_->AddRef(); } function(function&& rhs) noexcept : callable_(rhs.callable_) { rhs.callable_ = nullptr; } function(_Ret(*func)(_Args...)) { callable_ = __function_detail::proxy_callable<_Ret(*)(_Args...), _Ret, _Args...>::Make(::std::move(func)); if (callable_) callable_->AddRef(); } template< typename _Ty, typename = typename ::std::enable_if<__function_detail::is_callable<_Ty, _Ret, _Args...>::value, int>::type> function(_Ty val) { callable_ = __function_detail::proxy_callable<_Ty, _Ret, _Args...>::Make(::std::move(val)); if (callable_) callable_->AddRef(); } template::value || ::std::is_base_of<_Ty, _Uty>::value, int>::type> function(_Uty* ptr, _Ret(_Ty::* func)(_Args...)) { callable_ = __function_detail::proxy_mem_callable<_Ty, _Ret, _Args...>::Make(ptr, func); if (callable_) callable_->AddRef(); } template::value || ::std::is_base_of<_Ty, _Uty>::value, int>::type> function(_Uty* ptr, _Ret(_Ty::* func)(_Args...) const) { callable_ = __function_detail::proxy_const_mem_callable<_Ty, _Ret, _Args...>::Make(ptr, func); if (callable_) callable_->AddRef(); } ~function() { tidy(); } inline void swap(const function& rhs) { ::std::swap(callable_, rhs.callable_); } inline _Ret operator()(_Args... args) const { if (!callable_) throw bad_function_call(); return callable_->Invoke(::std::forward<_Args>(args)...); } inline operator bool() const { return !!callable_; } inline function& operator=(const function& rhs) { tidy(); callable_ = rhs.callable_; if (callable_) callable_->AddRef(); return (*this); } inline function& operator=(function&& rhs) { tidy(); callable_ = rhs.callable_; rhs.callable_ = nullptr; return (*this); } private: inline void tidy() { if (callable_) { callable_->Release(); callable_ = nullptr; } } private: __function_detail::callable<_Ret, _Args...>* callable_; }; } // inline namespace core } // namespace kiwano namespace kiwano { template::value || std::is_base_of<_Ty, _Uty>::value, int >::type, typename _Ret, typename... _Args> inline function<_Ret(_Args...)> bind_func(_Uty* ptr, _Ret(_Ty::* func)(_Args...)) { return function<_Ret(_Args...)>(ptr, func); } template::value || std::is_base_of<_Ty, _Uty>::value, int >::type, typename _Ret, typename... _Args> inline function<_Ret(_Args...)> bind_func(_Uty* ptr, _Ret(_Ty::* func)(_Args...) const) { return function<_Ret(_Args...)>(ptr, func); } }