/* * Copyright (C) 2011 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF * THE POSSIBILITY OF SUCH DAMAGE. */ #ifndef WTF_Functional_h #define WTF_Functional_h #include #include #include #include #include #if OS(DARWIN) && COMPILER_SUPPORTS(BLOCKS) #include #include #endif namespace WTF { // Functional.h provides a very simple way to bind a function pointer and arguments together into a function object // that can be stored, copied and invoked, similar to how boost::bind and std::bind in C++11. // Helper class template to determine whether a given type has ref and deref member functions // with the right type signature. template class HasRefAndDeref { typedef char YesType; struct NoType { char padding[8]; }; struct BaseMixin { void deref(); void ref(); }; struct Base : public T, public BaseMixin { }; template struct TypeChecker { }; template static NoType refCheck(U*, TypeChecker* = 0); static YesType refCheck(...); template static NoType derefCheck(U*, TypeChecker* = 0); static YesType derefCheck(...); public: static const bool value = sizeof(refCheck(static_cast(0))) == sizeof(YesType) && sizeof(derefCheck(static_cast(0))) == sizeof(YesType); }; // A FunctionWrapper is a class template that can wrap a function pointer or a member function pointer and // provide a unified interface for calling that function. template class FunctionWrapper; // Bound static functions: template class FunctionWrapper { public: typedef R ResultType; static const bool shouldRefFirstParameter = false; explicit FunctionWrapper(R (*function)()) : m_function(function) { } R operator()() { return m_function(); } private: R (*m_function)(); }; template class FunctionWrapper { public: typedef R ResultType; static const bool shouldRefFirstParameter = false; explicit FunctionWrapper(R (*function)(P1)) : m_function(function) { } R operator()(P1 p1) { return m_function(p1); } private: R (*m_function)(P1); }; template class FunctionWrapper { public: typedef R ResultType; static const bool shouldRefFirstParameter = false; explicit FunctionWrapper(R (*function)(P1, P2)) : m_function(function) { } R operator()(P1 p1, P2 p2) { return m_function(p1, p2); } private: R (*m_function)(P1, P2); }; template class FunctionWrapper { public: typedef R ResultType; static const bool shouldRefFirstParameter = false; explicit FunctionWrapper(R (*function)(P1, P2, P3)) : m_function(function) { } R operator()(P1 p1, P2 p2, P3 p3) { return m_function(p1, p2, p3); } private: R (*m_function)(P1, P2, P3); }; template class FunctionWrapper { public: typedef R ResultType; static const bool shouldRefFirstParameter = false; explicit FunctionWrapper(R (*function)(P1, P2, P3, P4)) : m_function(function) { } R operator()(P1 p1, P2 p2, P3 p3, P4 p4) { return m_function(p1, p2, p3, p4); } private: R (*m_function)(P1, P2, P3, P4); }; template class FunctionWrapper { public: typedef R ResultType; static const bool shouldRefFirstParameter = false; explicit FunctionWrapper(R (*function)(P1, P2, P3, P4, P5)) : m_function(function) { } R operator()(P1 p1, P2 p2, P3 p3, P4 p4, P5 p5) { return m_function(p1, p2, p3, p4, p5); } private: R (*m_function)(P1, P2, P3, P4, P5); }; // Bound member functions: template class FunctionWrapper { public: typedef R ResultType; static const bool shouldRefFirstParameter = HasRefAndDeref::value; explicit FunctionWrapper(R (C::*function)()) : m_function(function) { } R operator()(C* c) { return (c->*m_function)(); } R operator()(const WeakPtr& c) { C* obj = c.get(); if (!obj) return R(); return (obj->*m_function)(); } private: R (C::*m_function)(); }; template class FunctionWrapper { public: typedef R ResultType; static const bool shouldRefFirstParameter = HasRefAndDeref::value; explicit FunctionWrapper(R (C::*function)(P1)) : m_function(function) { } R operator()(C* c, P1 p1) { return (c->*m_function)(p1); } R operator()(const WeakPtr& c, P1 p1) { C* obj = c.get(); if (!obj) return R(); return (obj->*m_function)(p1); } private: R (C::*m_function)(P1); }; template class FunctionWrapper { public: typedef R ResultType; static const bool shouldRefFirstParameter = HasRefAndDeref::value; explicit FunctionWrapper(R (C::*function)(P1, P2)) : m_function(function) { } R operator()(C* c, P1 p1, P2 p2) { return (c->*m_function)(p1, p2); } R operator()(const WeakPtr& c, P1 p1, P2 p2) { C* obj = c.get(); if (!obj) return R(); return (obj->*m_function)(p1, p2); } private: R (C::*m_function)(P1, P2); }; template class FunctionWrapper { public: typedef R ResultType; static const bool shouldRefFirstParameter = HasRefAndDeref::value; explicit FunctionWrapper(R (C::*function)(P1, P2, P3)) : m_function(function) { } R operator()(C* c, P1 p1, P2 p2, P3 p3) { return (c->*m_function)(p1, p2, p3); } R operator()(const WeakPtr& c, P1 p1, P2 p2, P3 p3) { C* obj = c.get(); if (!obj) return R(); return (obj->*m_function)(p1, p2, p3); } private: R (C::*m_function)(P1, P2, P3); }; template class FunctionWrapper { public: typedef R ResultType; static const bool shouldRefFirstParameter = HasRefAndDeref::value; explicit FunctionWrapper(R (C::*function)(P1, P2, P3, P4)) : m_function(function) { } R operator()(C* c, P1 p1, P2 p2, P3 p3, P4 p4) { return (c->*m_function)(p1, p2, p3, p4); } R operator()(const WeakPtr& c, P1 p1, P2 p2, P3 p3, P4 p4) { C* obj = c.get(); if (!obj) return R(); return (obj->*m_function)(p1, p2, p3, p4); } private: R (C::*m_function)(P1, P2, P3, P4); }; template class FunctionWrapper { public: typedef R ResultType; static const bool shouldRefFirstParameter = HasRefAndDeref::value; explicit FunctionWrapper(R (C::*function)(P1, P2, P3, P4, P5)) : m_function(function) { } R operator()(C* c, P1 p1, P2 p2, P3 p3, P4 p4, P5 p5) { return (c->*m_function)(p1, p2, p3, p4, p5); } R operator()(const WeakPtr& c, P1 p1, P2 p2, P3 p3, P4 p4, P5 p5) { C* obj = c.get(); if (!obj) return R(); return (obj->*m_function)(p1, p2, p3, p4, p5); } private: R (C::*m_function)(P1, P2, P3, P4, P5); }; #if OS(DARWIN) && COMPILER_SUPPORTS(BLOCKS) template class FunctionWrapper { public: typedef R ResultType; static const bool shouldRefFirstParameter = false; explicit FunctionWrapper(R (^block)()) : m_block(Block_copy(block)) { } FunctionWrapper(const FunctionWrapper& other) : m_block(Block_copy(other.m_block)) { } ~FunctionWrapper() { Block_release(m_block); } R operator()() { return m_block(); } private: R (^m_block)(); }; #endif template struct RefAndDeref { static void ref(T) { } static void deref(T) { } }; template struct RefAndDeref { static void ref(T* t) { t->ref(); } static void deref(T* t) { t->deref(); } }; template struct ParamStorageTraits { typedef T StorageType; static StorageType wrap(const T& value) { return value; } static const T& unwrap(const StorageType& value) { return value; } }; template struct ParamStorageTraits> { typedef RefPtr StorageType; static StorageType wrap(PassRefPtr value) { return value; } static T* unwrap(const StorageType& value) { return value.get(); } }; template struct ParamStorageTraits> { typedef RefPtr StorageType; static StorageType wrap(RefPtr value) { return value.release(); } static T* unwrap(const StorageType& value) { return value.get(); } }; template class RetainPtr; template struct ParamStorageTraits> { typedef RetainPtr StorageType; static StorageType wrap(const RetainPtr& value) { return value; } static typename RetainPtr::PtrType unwrap(const StorageType& value) { return value.get(); } }; class FunctionImplBase : public ThreadSafeRefCounted { public: virtual ~FunctionImplBase() { } }; template class FunctionImpl; template class FunctionImpl : public FunctionImplBase { public: virtual R operator()() = 0; }; template class BoundFunctionImpl; template class BoundFunctionImpl : public FunctionImpl { public: explicit BoundFunctionImpl(FunctionWrapper functionWrapper) : m_functionWrapper(functionWrapper) { } virtual typename FunctionWrapper::ResultType operator()() { return m_functionWrapper(); } private: FunctionWrapper m_functionWrapper; }; template class BoundFunctionImpl : public FunctionImpl { public: BoundFunctionImpl(FunctionWrapper functionWrapper, const P1& p1) : m_functionWrapper(functionWrapper) , m_p1(ParamStorageTraits::wrap(p1)) { RefAndDeref::ref(m_p1); } ~BoundFunctionImpl() { RefAndDeref::deref(m_p1); } virtual typename FunctionWrapper::ResultType operator()() { return m_functionWrapper(ParamStorageTraits::unwrap(m_p1)); } private: FunctionWrapper m_functionWrapper; typename ParamStorageTraits::StorageType m_p1; }; template class BoundFunctionImpl : public FunctionImpl { public: BoundFunctionImpl(FunctionWrapper functionWrapper, const P1& p1, const P2& p2) : m_functionWrapper(functionWrapper) , m_p1(ParamStorageTraits::wrap(p1)) , m_p2(ParamStorageTraits::wrap(p2)) { RefAndDeref::ref(m_p1); } ~BoundFunctionImpl() { RefAndDeref::deref(m_p1); } virtual typename FunctionWrapper::ResultType operator()() { return m_functionWrapper(ParamStorageTraits::unwrap(m_p1), ParamStorageTraits::unwrap(m_p2)); } private: FunctionWrapper m_functionWrapper; typename ParamStorageTraits::StorageType m_p1; typename ParamStorageTraits::StorageType m_p2; }; template class BoundFunctionImpl : public FunctionImpl { public: BoundFunctionImpl(FunctionWrapper functionWrapper, const P1& p1, const P2& p2, const P3& p3) : m_functionWrapper(functionWrapper) , m_p1(ParamStorageTraits::wrap(p1)) , m_p2(ParamStorageTraits::wrap(p2)) , m_p3(ParamStorageTraits::wrap(p3)) { RefAndDeref::ref(m_p1); } ~BoundFunctionImpl() { RefAndDeref::deref(m_p1); } virtual typename FunctionWrapper::ResultType operator()() { return m_functionWrapper(ParamStorageTraits::unwrap(m_p1), ParamStorageTraits::unwrap(m_p2), ParamStorageTraits::unwrap(m_p3)); } private: FunctionWrapper m_functionWrapper; typename ParamStorageTraits::StorageType m_p1; typename ParamStorageTraits::StorageType m_p2; typename ParamStorageTraits::StorageType m_p3; }; template class BoundFunctionImpl : public FunctionImpl { public: BoundFunctionImpl(FunctionWrapper functionWrapper, const P1& p1, const P2& p2, const P3& p3, const P4& p4) : m_functionWrapper(functionWrapper) , m_p1(ParamStorageTraits::wrap(p1)) , m_p2(ParamStorageTraits::wrap(p2)) , m_p3(ParamStorageTraits::wrap(p3)) , m_p4(ParamStorageTraits::wrap(p4)) { RefAndDeref::ref(m_p1); } ~BoundFunctionImpl() { RefAndDeref::deref(m_p1); } virtual typename FunctionWrapper::ResultType operator()() { return m_functionWrapper(ParamStorageTraits::unwrap(m_p1), ParamStorageTraits::unwrap(m_p2), ParamStorageTraits::unwrap(m_p3), ParamStorageTraits::unwrap(m_p4)); } private: FunctionWrapper m_functionWrapper; typename ParamStorageTraits::StorageType m_p1; typename ParamStorageTraits::StorageType m_p2; typename ParamStorageTraits::StorageType m_p3; typename ParamStorageTraits::StorageType m_p4; }; template class BoundFunctionImpl : public FunctionImpl { public: BoundFunctionImpl(FunctionWrapper functionWrapper, const P1& p1, const P2& p2, const P3& p3, const P4& p4, const P5& p5) : m_functionWrapper(functionWrapper) , m_p1(ParamStorageTraits::wrap(p1)) , m_p2(ParamStorageTraits::wrap(p2)) , m_p3(ParamStorageTraits::wrap(p3)) , m_p4(ParamStorageTraits::wrap(p4)) , m_p5(ParamStorageTraits::wrap(p5)) { RefAndDeref::ref(m_p1); } ~BoundFunctionImpl() { RefAndDeref::deref(m_p1); } virtual typename FunctionWrapper::ResultType operator()() { return m_functionWrapper(ParamStorageTraits::unwrap(m_p1), ParamStorageTraits::unwrap(m_p2), ParamStorageTraits::unwrap(m_p3), ParamStorageTraits::unwrap(m_p4), ParamStorageTraits::unwrap(m_p5)); } private: FunctionWrapper m_functionWrapper; typename ParamStorageTraits::StorageType m_p1; typename ParamStorageTraits::StorageType m_p2; typename ParamStorageTraits::StorageType m_p3; typename ParamStorageTraits::StorageType m_p4; typename ParamStorageTraits::StorageType m_p5; }; template class BoundFunctionImpl : public FunctionImpl { public: BoundFunctionImpl(FunctionWrapper functionWrapper, const P1& p1, const P2& p2, const P3& p3, const P4& p4, const P5& p5, const P6& p6) : m_functionWrapper(functionWrapper) , m_p1(ParamStorageTraits::wrap(p1)) , m_p2(ParamStorageTraits::wrap(p2)) , m_p3(ParamStorageTraits::wrap(p3)) , m_p4(ParamStorageTraits::wrap(p4)) , m_p5(ParamStorageTraits::wrap(p5)) , m_p6(ParamStorageTraits::wrap(p6)) { RefAndDeref::ref(m_p1); } ~BoundFunctionImpl() { RefAndDeref::deref(m_p1); } virtual typename FunctionWrapper::ResultType operator()() { return m_functionWrapper(ParamStorageTraits::unwrap(m_p1), ParamStorageTraits::unwrap(m_p2), ParamStorageTraits::unwrap(m_p3), ParamStorageTraits::unwrap(m_p4), ParamStorageTraits::unwrap(m_p5), ParamStorageTraits::unwrap(m_p6)); } private: FunctionWrapper m_functionWrapper; typename ParamStorageTraits::StorageType m_p1; typename ParamStorageTraits::StorageType m_p2; typename ParamStorageTraits::StorageType m_p3; typename ParamStorageTraits::StorageType m_p4; typename ParamStorageTraits::StorageType m_p5; typename ParamStorageTraits::StorageType m_p6; }; class FunctionBase { public: bool isNull() const { return !m_impl; } protected: FunctionBase() { } explicit FunctionBase(PassRefPtr impl) : m_impl(impl) { } template FunctionImpl* impl() const { return static_cast*>(m_impl.get()); } private: RefPtr m_impl; }; template class Function; template class Function : public FunctionBase { public: Function() { } Function(PassRefPtr> impl) : FunctionBase(impl) { } R operator()() const { ASSERT(!isNull()); return impl()->operator()(); } #if OS(DARWIN) && COMPILER_SUPPORTS(BLOCKS) typedef void (^BlockType)(); operator BlockType() const { // Declare a RefPtr here so we'll be sure that the underlying FunctionImpl object's // lifecycle is managed correctly. RefPtr> functionImpl = impl(); BlockType block = ^{ functionImpl->operator()(); }; // This is equivalent to: // // return [[block copy] autorelease]; // // We're using manual objc_msgSend calls here because we don't want to make the entire // file Objective-C. It's useful to be able to implicitly convert a Function to // a block even in C++ code, since that allows us to do things like: // // dispatch_async(queue, bind(...)); // id copiedBlock = wtfObjcMsgSend((id)block, sel_registerName("copy")); id autoreleasedBlock = wtfObjcMsgSend(copiedBlock, sel_registerName("autorelease")); return (BlockType)autoreleasedBlock; } #endif }; template Function::ResultType ()> bind(FunctionType function) { return Function::ResultType ()>(adoptRef(new BoundFunctionImpl, typename FunctionWrapper::ResultType ()>(FunctionWrapper(function)))); } template Function::ResultType ()> bind(FunctionType function, const A1& a1) { return Function::ResultType ()>(adoptRef(new BoundFunctionImpl, typename FunctionWrapper::ResultType (A1)>(FunctionWrapper(function), a1))); } template Function::ResultType ()> bind(FunctionType function, const A1& a1, const A2& a2) { return Function::ResultType ()>(adoptRef(new BoundFunctionImpl, typename FunctionWrapper::ResultType (A1, A2)>(FunctionWrapper(function), a1, a2))); } template Function::ResultType ()> bind(FunctionType function, const A1& a1, const A2& a2, const A3& a3) { return Function::ResultType ()>(adoptRef(new BoundFunctionImpl, typename FunctionWrapper::ResultType (A1, A2, A3)>(FunctionWrapper(function), a1, a2, a3))); } template Function::ResultType ()> bind(FunctionType function, const A1& a1, const A2& a2, const A3& a3, const A4& a4) { return Function::ResultType ()>(adoptRef(new BoundFunctionImpl, typename FunctionWrapper::ResultType (A1, A2, A3, A4)>(FunctionWrapper(function), a1, a2, a3, a4))); } template Function::ResultType ()> bind(FunctionType function, const A1& a1, const A2& a2, const A3& a3, const A4& a4, const A5& a5) { return Function::ResultType ()>(adoptRef(new BoundFunctionImpl, typename FunctionWrapper::ResultType (A1, A2, A3, A4, A5)>(FunctionWrapper(function), a1, a2, a3, a4, a5))); } template Function::ResultType ()> bind(FunctionType function, const A1& a1, const A2& a2, const A3& a3, const A4& a4, const A5& a5, const A6& a6) { return Function::ResultType ()>(adoptRef(new BoundFunctionImpl, typename FunctionWrapper::ResultType (A1, A2, A3, A4, A5, A6)>(FunctionWrapper(function), a1, a2, a3, a4, a5, a6))); } } using WTF::Function; using WTF::bind; #endif // WTF_Functional_h