/** \file SRDelegate.hpp * * This is a C++11 implementation by janezz55(code.google) for the original "The Impossibly Fast C++ Delegates" authored by Sergey Ryazanov. * * This is a copy checkouted from https://code.google.com/p/cpppractice/source/browse/trunk/delegate.hpp on 2014/06/07. * Last change in the chunk was r370 on Feb 9, 2014. * * The following modifications were added by Benjamin YanXiang Huang * - replace light_ptr with std::shared_ptr * - renamed src file * * Reference: * - http://codereview.stackexchange.com/questions/14730/impossibly-fast-delegate-in-c11 * - http://www.codeproject.com/Articles/11015/The-Impossibly-Fast-C-Delegates * - https://code.google.com/p/cpppractice/source/browse/trunk/delegate.hpp */ #pragma once #ifndef SRDELEGATE_HPP #define SRDELEGATE_HPP #include #include #include #include #include #include // VC work around for constexpr and noexcept: VC2013 and below do not support these 2 keywords #if defined(_MSC_VER) && (_MSC_VER <= 1800) #define constexpr const #define noexcept throw() #endif namespace fastdelegate { template class delegate; template class delegate { using stub_ptr_type = R(*)(void *, A&&...); delegate(void * const o, stub_ptr_type const m) noexcept : object_ptr_(o), stub_ptr_(m) {} public: delegate(void) = default; delegate(delegate const &) = default; delegate(delegate && d) : object_ptr_(d.object_ptr_), stub_ptr_(d.stub_ptr_), deleter_(d.deleter_), store_(d.store_), store_size_(d.store_size_) { d.object_ptr_ = nullptr; d.stub_ptr_ = nullptr; d.deleter_ = nullptr; d.store_ = nullptr; d.store_size_ = 0; } delegate(::std::nullptr_t const) noexcept : delegate() { } template ::value, C>::type> explicit delegate(C const * const o) noexcept : object_ptr_(const_cast(o)) {} template {}>::type> explicit delegate(C const & o) noexcept : object_ptr_(const_cast(&o)) {} template delegate(C * const object_ptr, R(C::* const method_ptr)(A...)) { *this = from(object_ptr, method_ptr); } template delegate(C * const object_ptr, R(C::* const method_ptr)(A...) const) { *this = from(object_ptr, method_ptr); } template delegate(C & object, R(C::* const method_ptr)(A...)) { *this = from(object, method_ptr); } template delegate(C const & object, R(C::* const method_ptr)(A...) const) { *this = from(object, method_ptr); } template < typename T, typename = typename ::std::enable_if::type>::value>::type > delegate(T&& f) : store_(operator new(sizeof(typename ::std::decay::type)) , functor_deleter::type>) , store_size_(sizeof(typename ::std::decay::type)) { using functor_type = typename ::std::decay::type; new(store_.get()) functor_type(::std::forward(f)); object_ptr_ = store_.get(); stub_ptr_ = functor_stub; deleter_ = deleter_stub; } delegate & operator=(delegate const &) = default; delegate & operator=(delegate&& d) { object_ptr_ = d.object_ptr_; stub_ptr_ = d.stub_ptr_; deleter_ = d.deleter_; store_ = d.store_; store_size_ = d.store_size_; d.object_ptr_ = nullptr; d.stub_ptr_ = nullptr; d.deleter_ = nullptr; d.store_ = nullptr; d.store_size_ = 0; return *this; } template delegate & operator=(R(C::* const rhs)(A...)) { return *this = from(static_cast(object_ptr_), rhs); } template delegate & operator=(R(C::* const rhs)(A...) const) { return *this = from(static_cast(object_ptr_), rhs); } template < typename T , typename = typename ::std::enable_if::type>::value>::type > delegate & operator=(T&& f) { using functor_type = typename ::std::decay::type; if ((sizeof(functor_type) > store_size_) || !store_.unique()) { store_.reset(operator new(sizeof(functor_type)), functor_deleter); store_size_ = sizeof(functor_type); } else deleter_(store_.get()); new(store_.get()) functor_type(::std::forward(f)); object_ptr_ = store_.get(); stub_ptr_ = functor_stub; deleter_ = deleter_stub; return *this; } template static delegate from(void) noexcept { return { nullptr, function_stub }; } template static delegate from(C * const object_ptr) noexcept { return { object_ptr, method_stub }; } template static delegate from(C const * const object_ptr) noexcept { return { const_cast(object_ptr), const_method_stub }; } template static delegate from(C & object) noexcept { return { &object, method_stub }; } template static delegate from(C const & object) noexcept { return { const_cast(&object), const_method_stub }; } template static delegate from(T && f) { return ::std::forward(f); } static delegate from(R(* const function_ptr)(A...)) { return function_ptr; } template using member_pair = ::std::pair; template using const_member_pair = ::std::pair; template static delegate from(C * const object_ptr, R(C::* const method_ptr)(A...)) { return member_pair(object_ptr, method_ptr); } template static delegate from(C const * const object_ptr, R(C::* const method_ptr)(A...) const) { return const_member_pair(object_ptr, method_ptr); } template static delegate from(C & object, R(C::* const method_ptr)(A...)) { return member_pair(&object, method_ptr); } template static delegate from(C const & object, R(C::* const method_ptr)(A...) const) { return const_member_pair(&object, method_ptr); } void reset(void) { stub_ptr_ = nullptr; store_.reset(); } void reset_stub(void) noexcept { stub_ptr_ = nullptr; } void swap(delegate & other) noexcept { ::std::swap(*this, other); } bool operator==(delegate const & rhs) const noexcept { // comparison between functor and non-functor is left as undefined at the moment. if (store_size_ && rhs.store_size_) // both functors return (std::memcmp(store_.get(), rhs.store_.get(), store_size_) == 0) && (stub_ptr_ == rhs.stub_ptr_); return (object_ptr_ == rhs.object_ptr_) && (stub_ptr_ == rhs.stub_ptr_); } bool operator!=(delegate const & rhs) const noexcept { return !operator==(rhs); } bool operator<(delegate const & rhs) const noexcept { return (object_ptr_ < rhs.object_ptr_) || ((object_ptr_ == rhs.object_ptr_) && (stub_ptr_ < rhs.stub_ptr_)); } bool operator==(::std::nullptr_t const) const noexcept { return !stub_ptr_; } bool operator!=(::std::nullptr_t const) const noexcept { return stub_ptr_; } explicit operator bool() const noexcept { return stub_ptr_; } R operator()(A... args) const { // assert(stub_ptr); return stub_ptr_(object_ptr_, ::std::forward(args)...); } private: friend struct ::std::hash; using deleter_type = void (*)(void *); void * object_ptr_ = nullptr; stub_ptr_type stub_ptr_ {}; deleter_type deleter_ = nullptr; ::std::shared_ptr store_ = nullptr; ::std::size_t store_size_ = 0; template static void functor_deleter(void * const p) { static_cast(p)->~T(); operator delete(p); } template static void deleter_stub(void * const p) { static_cast(p)->~T(); } template static R function_stub(void * const, A && ... args) { return function_ptr(::std::forward(args)...); } template static R method_stub(void * const object_ptr, A && ... args) { return (static_cast(object_ptr)->*method_ptr)(::std::forward(args)...); } template static R const_method_stub(void * const object_ptr, A && ... args) { return (static_cast(object_ptr)->*method_ptr)(::std::forward(args)...); } template struct is_member_pair : ::std::false_type { }; template struct is_member_pair< ::std::pair > : ::std::true_type {}; template struct is_const_member_pair : ::std::false_type { }; template struct is_const_member_pair< ::std::pair > : ::std::true_type {}; template static typename ::std::enable_if::value || is_const_member_pair::value), R>::type functor_stub(void * const object_ptr, A && ... args) { return (*static_cast(object_ptr))(::std::forward(args)...); } template static typename ::std::enable_if::value || is_const_member_pair::value, R>::type functor_stub(void * const object_ptr, A && ... args) { return (static_cast(object_ptr)->first->*static_cast(object_ptr)->second)(::std::forward(args)...); } }; } namespace std { template struct hash<::fastdelegate::delegate > { size_t operator()(::fastdelegate::delegate const & d) const noexcept { auto const seed(hash()(d.object_ptr_)); return hash()(d.stub_ptr_) + 0x9e3779b9 + (seed << 6) + (seed >> 2); } }; } #endif // SRDELEGATE_HPP