/*
 * 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 <wtf/Assertions.h>
#include <wtf/PassRefPtr.h>
#include <wtf/RefPtr.h>
#include <wtf/ThreadSafeRefCounted.h>
#include <wtf/WeakPtr.h>

#if OS(DARWIN) && COMPILER_SUPPORTS(BLOCKS)
#include <Block.h>
#include <wtf/ObjcRuntimeExtras.h>
#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<typename T>
class HasRefAndDeref {
    typedef char YesType;
    struct NoType {
        char padding[8];
    };

    struct BaseMixin {
        void deref();
        void ref();
    };

    struct Base : public T, public BaseMixin { };

    template<typename U, U> struct
    TypeChecker { };

    template<typename U>
    static NoType refCheck(U*, TypeChecker<void (BaseMixin::*)(), &U::ref>* = 0);
    static YesType refCheck(...);

    template<typename U>
    static NoType derefCheck(U*, TypeChecker<void (BaseMixin::*)(), &U::deref>* = 0);
    static YesType derefCheck(...);

public:
    static const bool value = sizeof(refCheck(static_cast<Base*>(0))) == sizeof(YesType) && sizeof(derefCheck(static_cast<Base*>(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<typename>
class FunctionWrapper;

// Bound static functions:

template<typename R>
class FunctionWrapper<R (*)()> {
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<typename R, typename P1>
class FunctionWrapper<R (*)(P1)> {
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<typename R, typename P1, typename P2>
class FunctionWrapper<R (*)(P1, P2)> {
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<typename R, typename P1, typename P2, typename P3>
class FunctionWrapper<R (*)(P1, P2, P3)> {
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<typename R, typename P1, typename P2, typename P3, typename P4>
class FunctionWrapper<R (*)(P1, P2, P3, P4)> {
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<typename R, typename P1, typename P2, typename P3, typename P4, typename P5>
class FunctionWrapper<R (*)(P1, P2, P3, P4, P5)> {
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<typename R, typename C>
class FunctionWrapper<R (C::*)()> {
public:
    typedef R ResultType;
    static const bool shouldRefFirstParameter = HasRefAndDeref<C>::value;

    explicit FunctionWrapper(R (C::*function)())
        : m_function(function)
    {
    }

    R operator()(C* c)
    {
        return (c->*m_function)();
    }

    R operator()(const WeakPtr<C>& c)
    {
        C* obj = c.get();
        if (!obj)
            return R();
        return (obj->*m_function)();
    }

private:
    R (C::*m_function)();
};

template<typename R, typename C, typename P1>
class FunctionWrapper<R (C::*)(P1)> {
public:
    typedef R ResultType;
    static const bool shouldRefFirstParameter = HasRefAndDeref<C>::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>& c, P1 p1)
    {
        C* obj = c.get();
        if (!obj)
            return R();
        return (obj->*m_function)(p1);
    }

private:
    R (C::*m_function)(P1);
};

template<typename R, typename C, typename P1, typename P2>
class FunctionWrapper<R (C::*)(P1, P2)> {
public:
    typedef R ResultType;
    static const bool shouldRefFirstParameter = HasRefAndDeref<C>::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>& 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<typename R, typename C, typename P1, typename P2, typename P3>
class FunctionWrapper<R (C::*)(P1, P2, P3)> {
public:
    typedef R ResultType;
    static const bool shouldRefFirstParameter = HasRefAndDeref<C>::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>& 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<typename R, typename C, typename P1, typename P2, typename P3, typename P4>
class FunctionWrapper<R (C::*)(P1, P2, P3, P4)> {
public:
    typedef R ResultType;
    static const bool shouldRefFirstParameter = HasRefAndDeref<C>::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>& 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<typename R, typename C, typename P1, typename P2, typename P3, typename P4, typename P5>
class FunctionWrapper<R (C::*)(P1, P2, P3, P4, P5)> {
public:
    typedef R ResultType;
    static const bool shouldRefFirstParameter = HasRefAndDeref<C>::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>& 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<typename R>
class FunctionWrapper<R (^)()> {
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<typename T, bool shouldRefAndDeref> struct RefAndDeref {
    static void ref(T) { }
    static void deref(T) { }
};

template<typename T> struct RefAndDeref<T*, true> {
    static void ref(T* t) { t->ref(); }
    static void deref(T* t) { t->deref(); }
};

template<typename T> struct ParamStorageTraits {
    typedef T StorageType;

    static StorageType wrap(const T& value) { return value; }
    static const T& unwrap(const StorageType& value) { return value; }
};

template<typename T> struct ParamStorageTraits<PassRefPtr<T>> {
    typedef RefPtr<T> StorageType;

    static StorageType wrap(PassRefPtr<T> value) { return value; }
    static T* unwrap(const StorageType& value) { return value.get(); }
};

template<typename T> struct ParamStorageTraits<RefPtr<T>> {
    typedef RefPtr<T> StorageType;

    static StorageType wrap(RefPtr<T> value) { return value.release(); }
    static T* unwrap(const StorageType& value) { return value.get(); }
};

template<typename> class RetainPtr;

template<typename T> struct ParamStorageTraits<RetainPtr<T>> {
    typedef RetainPtr<T> StorageType;

    static StorageType wrap(const RetainPtr<T>& value) { return value; }
    static typename RetainPtr<T>::PtrType unwrap(const StorageType& value) { return value.get(); }
};

class FunctionImplBase : public ThreadSafeRefCounted<FunctionImplBase> {
public:
    virtual ~FunctionImplBase() { }
};

template<typename>
class FunctionImpl;

template<typename R>
class FunctionImpl<R ()> : public FunctionImplBase {
public:
    virtual R operator()() = 0;
};

template<typename FunctionWrapper, typename FunctionType>
class BoundFunctionImpl;

template<typename FunctionWrapper, typename R>
class BoundFunctionImpl<FunctionWrapper, R ()> : public FunctionImpl<typename FunctionWrapper::ResultType ()> {
public:
    explicit BoundFunctionImpl(FunctionWrapper functionWrapper)
        : m_functionWrapper(functionWrapper)
    {
    }

    virtual typename FunctionWrapper::ResultType operator()()
    {
        return m_functionWrapper();
    }

private:
    FunctionWrapper m_functionWrapper;
};

template<typename FunctionWrapper, typename R, typename P1>
class BoundFunctionImpl<FunctionWrapper, R (P1)> : public FunctionImpl<typename FunctionWrapper::ResultType ()> {
public:
    BoundFunctionImpl(FunctionWrapper functionWrapper, const P1& p1)
        : m_functionWrapper(functionWrapper)
        , m_p1(ParamStorageTraits<P1>::wrap(p1))
    {
        RefAndDeref<P1, FunctionWrapper::shouldRefFirstParameter>::ref(m_p1);
    }

    ~BoundFunctionImpl()
    {
        RefAndDeref<P1, FunctionWrapper::shouldRefFirstParameter>::deref(m_p1);
    }

    virtual typename FunctionWrapper::ResultType operator()()
    {
        return m_functionWrapper(ParamStorageTraits<P1>::unwrap(m_p1));
    }

private:
    FunctionWrapper m_functionWrapper;
    typename ParamStorageTraits<P1>::StorageType m_p1;
};

template<typename FunctionWrapper, typename R, typename P1, typename P2>
class BoundFunctionImpl<FunctionWrapper, R (P1, P2)> : public FunctionImpl<typename FunctionWrapper::ResultType ()> {
public:
    BoundFunctionImpl(FunctionWrapper functionWrapper, const P1& p1, const P2& p2)
        : m_functionWrapper(functionWrapper)
        , m_p1(ParamStorageTraits<P1>::wrap(p1))
        , m_p2(ParamStorageTraits<P2>::wrap(p2))
    {
        RefAndDeref<P1, FunctionWrapper::shouldRefFirstParameter>::ref(m_p1);
    }
    
    ~BoundFunctionImpl()
    {
        RefAndDeref<P1, FunctionWrapper::shouldRefFirstParameter>::deref(m_p1);
    }

    virtual typename FunctionWrapper::ResultType operator()()
    {
        return m_functionWrapper(ParamStorageTraits<P1>::unwrap(m_p1), ParamStorageTraits<P2>::unwrap(m_p2));
    }

private:
    FunctionWrapper m_functionWrapper;
    typename ParamStorageTraits<P1>::StorageType m_p1;
    typename ParamStorageTraits<P2>::StorageType m_p2;
};

template<typename FunctionWrapper, typename R, typename P1, typename P2, typename P3>
class BoundFunctionImpl<FunctionWrapper, R (P1, P2, P3)> : public FunctionImpl<typename FunctionWrapper::ResultType ()> {
public:
    BoundFunctionImpl(FunctionWrapper functionWrapper, const P1& p1, const P2& p2, const P3& p3)
        : m_functionWrapper(functionWrapper)
        , m_p1(ParamStorageTraits<P1>::wrap(p1))
        , m_p2(ParamStorageTraits<P2>::wrap(p2))
        , m_p3(ParamStorageTraits<P3>::wrap(p3))
    {
        RefAndDeref<P1, FunctionWrapper::shouldRefFirstParameter>::ref(m_p1);
    }
    
    ~BoundFunctionImpl()
    {
        RefAndDeref<P1, FunctionWrapper::shouldRefFirstParameter>::deref(m_p1);
    }

    virtual typename FunctionWrapper::ResultType operator()()
    {
        return m_functionWrapper(ParamStorageTraits<P1>::unwrap(m_p1), ParamStorageTraits<P2>::unwrap(m_p2), ParamStorageTraits<P3>::unwrap(m_p3));
    }

private:
    FunctionWrapper m_functionWrapper;
    typename ParamStorageTraits<P1>::StorageType m_p1;
    typename ParamStorageTraits<P2>::StorageType m_p2;
    typename ParamStorageTraits<P3>::StorageType m_p3;
};

template<typename FunctionWrapper, typename R, typename P1, typename P2, typename P3, typename P4>
class BoundFunctionImpl<FunctionWrapper, R (P1, P2, P3, P4)> : public FunctionImpl<typename FunctionWrapper::ResultType ()> {
public:
    BoundFunctionImpl(FunctionWrapper functionWrapper, const P1& p1, const P2& p2, const P3& p3, const P4& p4)
        : m_functionWrapper(functionWrapper)
        , m_p1(ParamStorageTraits<P1>::wrap(p1))
        , m_p2(ParamStorageTraits<P2>::wrap(p2))
        , m_p3(ParamStorageTraits<P3>::wrap(p3))
        , m_p4(ParamStorageTraits<P4>::wrap(p4))
    {
        RefAndDeref<P1, FunctionWrapper::shouldRefFirstParameter>::ref(m_p1);
    }
    
    ~BoundFunctionImpl()
    {
        RefAndDeref<P1, FunctionWrapper::shouldRefFirstParameter>::deref(m_p1);
    }

    virtual typename FunctionWrapper::ResultType operator()()
    {
        return m_functionWrapper(ParamStorageTraits<P1>::unwrap(m_p1), ParamStorageTraits<P2>::unwrap(m_p2), ParamStorageTraits<P3>::unwrap(m_p3), ParamStorageTraits<P4>::unwrap(m_p4));
    }

private:
    FunctionWrapper m_functionWrapper;
    typename ParamStorageTraits<P1>::StorageType m_p1;
    typename ParamStorageTraits<P2>::StorageType m_p2;
    typename ParamStorageTraits<P3>::StorageType m_p3;
    typename ParamStorageTraits<P4>::StorageType m_p4;
};

template<typename FunctionWrapper, typename R, typename P1, typename P2, typename P3, typename P4, typename P5>
class BoundFunctionImpl<FunctionWrapper, R (P1, P2, P3, P4, P5)> : public FunctionImpl<typename FunctionWrapper::ResultType ()> {
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<P1>::wrap(p1))
        , m_p2(ParamStorageTraits<P2>::wrap(p2))
        , m_p3(ParamStorageTraits<P3>::wrap(p3))
        , m_p4(ParamStorageTraits<P4>::wrap(p4))
        , m_p5(ParamStorageTraits<P5>::wrap(p5))
    {
        RefAndDeref<P1, FunctionWrapper::shouldRefFirstParameter>::ref(m_p1);
    }
    
    ~BoundFunctionImpl()
    {
        RefAndDeref<P1, FunctionWrapper::shouldRefFirstParameter>::deref(m_p1);
    }

    virtual typename FunctionWrapper::ResultType operator()()
    {
        return m_functionWrapper(ParamStorageTraits<P1>::unwrap(m_p1), ParamStorageTraits<P2>::unwrap(m_p2), ParamStorageTraits<P3>::unwrap(m_p3), ParamStorageTraits<P4>::unwrap(m_p4), ParamStorageTraits<P5>::unwrap(m_p5));
    }

private:
    FunctionWrapper m_functionWrapper;
    typename ParamStorageTraits<P1>::StorageType m_p1;
    typename ParamStorageTraits<P2>::StorageType m_p2;
    typename ParamStorageTraits<P3>::StorageType m_p3;
    typename ParamStorageTraits<P4>::StorageType m_p4;
    typename ParamStorageTraits<P5>::StorageType m_p5;
};

template<typename FunctionWrapper, typename R, typename P1, typename P2, typename P3, typename P4, typename P5, typename P6>
class BoundFunctionImpl<FunctionWrapper, R (P1, P2, P3, P4, P5, P6)> : public FunctionImpl<typename FunctionWrapper::ResultType ()> {
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<P1>::wrap(p1))
        , m_p2(ParamStorageTraits<P2>::wrap(p2))
        , m_p3(ParamStorageTraits<P3>::wrap(p3))
        , m_p4(ParamStorageTraits<P4>::wrap(p4))
        , m_p5(ParamStorageTraits<P5>::wrap(p5))
        , m_p6(ParamStorageTraits<P6>::wrap(p6))
    {
        RefAndDeref<P1, FunctionWrapper::shouldRefFirstParameter>::ref(m_p1);
    }

    ~BoundFunctionImpl()
    {
        RefAndDeref<P1, FunctionWrapper::shouldRefFirstParameter>::deref(m_p1);
    }

    virtual typename FunctionWrapper::ResultType operator()()
    {
        return m_functionWrapper(ParamStorageTraits<P1>::unwrap(m_p1), ParamStorageTraits<P2>::unwrap(m_p2), ParamStorageTraits<P3>::unwrap(m_p3), ParamStorageTraits<P4>::unwrap(m_p4), ParamStorageTraits<P5>::unwrap(m_p5), ParamStorageTraits<P6>::unwrap(m_p6));
    }

private:
    FunctionWrapper m_functionWrapper;
    typename ParamStorageTraits<P1>::StorageType m_p1;
    typename ParamStorageTraits<P2>::StorageType m_p2;
    typename ParamStorageTraits<P3>::StorageType m_p3;
    typename ParamStorageTraits<P4>::StorageType m_p4;
    typename ParamStorageTraits<P5>::StorageType m_p5;
    typename ParamStorageTraits<P6>::StorageType m_p6;
};

class FunctionBase {
public:
    bool isNull() const
    {
        return !m_impl;
    }

protected:
    FunctionBase()
    {
    }

    explicit FunctionBase(PassRefPtr<FunctionImplBase> impl)
        : m_impl(impl)
    {
    }

    template<typename FunctionType> FunctionImpl<FunctionType>* impl() const
    { 
        return static_cast<FunctionImpl<FunctionType>*>(m_impl.get());
    }

private:
    RefPtr<FunctionImplBase> m_impl;
};

template<typename>
class Function;

template<typename R>
class Function<R ()> : public FunctionBase {
public:
    Function()
    {
    }

    Function(PassRefPtr<FunctionImpl<R ()>> impl)
        : FunctionBase(impl)
    {
    }

    R operator()() const
    {
        ASSERT(!isNull());

        return impl<R ()>()->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<R ()>> functionImpl = impl<R ()>();
        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>((id)block, sel_registerName("copy"));
        id autoreleasedBlock = wtfObjcMsgSend<id>(copiedBlock, sel_registerName("autorelease"));
        return (BlockType)autoreleasedBlock;
    }
#endif
};

template<typename FunctionType>
Function<typename FunctionWrapper<FunctionType>::ResultType ()> bind(FunctionType function)
{
    return Function<typename FunctionWrapper<FunctionType>::ResultType ()>(adoptRef(new BoundFunctionImpl<FunctionWrapper<FunctionType>, typename FunctionWrapper<FunctionType>::ResultType ()>(FunctionWrapper<FunctionType>(function))));
}

template<typename FunctionType, typename A1>
Function<typename FunctionWrapper<FunctionType>::ResultType ()> bind(FunctionType function, const A1& a1)
{
    return Function<typename FunctionWrapper<FunctionType>::ResultType ()>(adoptRef(new BoundFunctionImpl<FunctionWrapper<FunctionType>, typename FunctionWrapper<FunctionType>::ResultType (A1)>(FunctionWrapper<FunctionType>(function), a1)));
}

template<typename FunctionType, typename A1, typename A2>
Function<typename FunctionWrapper<FunctionType>::ResultType ()> bind(FunctionType function, const A1& a1, const A2& a2)
{
    return Function<typename FunctionWrapper<FunctionType>::ResultType ()>(adoptRef(new BoundFunctionImpl<FunctionWrapper<FunctionType>, typename FunctionWrapper<FunctionType>::ResultType (A1, A2)>(FunctionWrapper<FunctionType>(function), a1, a2)));
}

template<typename FunctionType, typename A1, typename A2, typename A3>
Function<typename FunctionWrapper<FunctionType>::ResultType ()> bind(FunctionType function, const A1& a1, const A2& a2, const A3& a3)
{
    return Function<typename FunctionWrapper<FunctionType>::ResultType ()>(adoptRef(new BoundFunctionImpl<FunctionWrapper<FunctionType>, typename FunctionWrapper<FunctionType>::ResultType (A1, A2, A3)>(FunctionWrapper<FunctionType>(function), a1, a2, a3)));
}

template<typename FunctionType, typename A1, typename A2, typename A3, typename A4>
Function<typename FunctionWrapper<FunctionType>::ResultType ()> bind(FunctionType function, const A1& a1, const A2& a2, const A3& a3, const A4& a4)
{
    return Function<typename FunctionWrapper<FunctionType>::ResultType ()>(adoptRef(new BoundFunctionImpl<FunctionWrapper<FunctionType>, typename FunctionWrapper<FunctionType>::ResultType (A1, A2, A3, A4)>(FunctionWrapper<FunctionType>(function), a1, a2, a3, a4)));
}

template<typename FunctionType, typename A1, typename A2, typename A3, typename A4, typename A5>
Function<typename FunctionWrapper<FunctionType>::ResultType ()> bind(FunctionType function, const A1& a1, const A2& a2, const A3& a3, const A4& a4, const A5& a5)
{
    return Function<typename FunctionWrapper<FunctionType>::ResultType ()>(adoptRef(new BoundFunctionImpl<FunctionWrapper<FunctionType>, typename FunctionWrapper<FunctionType>::ResultType (A1, A2, A3, A4, A5)>(FunctionWrapper<FunctionType>(function), a1, a2, a3, a4, a5)));
}

template<typename FunctionType, typename A1, typename A2, typename A3, typename A4, typename A5, typename A6>
Function<typename FunctionWrapper<FunctionType>::ResultType ()> bind(FunctionType function, const A1& a1, const A2& a2, const A3& a3, const A4& a4, const A5& a5, const A6& a6)
{
    return Function<typename FunctionWrapper<FunctionType>::ResultType ()>(adoptRef(new BoundFunctionImpl<FunctionWrapper<FunctionType>, typename FunctionWrapper<FunctionType>::ResultType (A1, A2, A3, A4, A5, A6)>(FunctionWrapper<FunctionType>(function), a1, a2, a3, a4, a5, a6)));
}

}

using WTF::Function;
using WTF::bind;

#endif // WTF_Functional_h
