/* Menes - C++ High-Level Utility Library * Copyright (C) 2003-2005 Jay Freeman (saurik) */ /* * 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. * 3. The name of the author may not be used to endorse * or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 THE AUTHOR 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 MENES_ETL_FNBIND_HPP #define MENES_ETL_FNBIND_HPP #include "cxx/platform.hpp" #ifdef MENES_PRAGMA_ONCE #pragma once #endif #include "hop/function.hpp" namespace hop { namespace be { template struct BindBase_ { typedef typename Function::Traits::Type InType; typedef typename etl::Erase::Result OutType; typedef Arg_ Arg; typedef Function::Prototype> Result; typedef typename FunctionManager::Value Value; typedef typename Function::Traits::Args ArgType; typedef typename etl::Head::Result PreArgs; typedef typename etl::At::Result BoundArg; typedef typename etl::Skip::Result PostArgs; struct Binder { Function function; Arg arg; // XXX: this used to be typename etl::ReferenceTo::Result arg Binder(const Function &function, const Arg &arg) : function(function), arg(arg) { } bool operator ==(const Binder &rhs) const { return function == rhs.function && arg == rhs.arg; } bool operator <(const Binder &rhs) const { if (!(function == rhs.function)) return function < rhs.function; if (!(arg == rhs.arg)) return arg < rhs.arg; return false; } }; }; template struct BindLength { static const unsigned value = etl::Length::Traits::Args>::value - Index_ - 1; }; template struct Bind : public BindBase_ { typedef BindBase_ Base_; static typename Function::Traits::Return InvokeBind(const typename Base_::Result *this_, ArgStruct pre, ArgStruct post) { typename Base_::Binder &binder(*reinterpret_cast(this_->GetValue().data)); #ifdef CFG_AGGREGATE_PASS_BY_REFERENCE typename Base_::BoundArg arg(binder.arg); ArgStruct args(pre, arg, post); typedef typename Function::Traits::Return (Function::*Target)(ArgStruct *); return (binder.function.*reinterpret_cast(&Function::InvokeValue))(&args); #else typedef typename Function::Traits::Return (Function::*Target)(ArgStruct, typename Base_::BoundArg, ArgStruct); return (binder.function.*reinterpret_cast(&Function::InvokeValue))(pre, binder.arg, post); #endif } }; template struct Bind<0, Prototype_, Arg_, Length_> : public BindBase_<0, Prototype_, Arg_> { typedef BindBase_<0, Prototype_, Arg_> Base_; static typename Function::Traits::Return InvokeBind(const typename Base_::Result *this_, ArgStruct post) { typename Base_::Binder &binder(*reinterpret_cast(this_->GetValue().data)); #ifdef CFG_AGGREGATE_PASS_BY_REFERENCE typename Base_::BoundArg arg(binder.arg); ArgStruct args(arg, post); typedef typename Function::Traits::Return (Function::*Target)(ArgStruct *); return (binder.function.*reinterpret_cast(&Function::InvokeValue))(&args); #else typedef typename Function::Traits::Return (Function::*Target)(typename Base_::BoundArg, ArgStruct); return (binder.function.*reinterpret_cast(&Function::InvokeValue))(binder.arg, post); #endif } }; template struct Bind : public BindBase_ { typedef BindBase_ Base_; static typename Function::Traits::Return InvokeBind(const typename Base_::Result *this_, ArgStruct pre) { typename Base_::Binder &binder(*reinterpret_cast(this_->GetValue().data)); #ifdef CFG_AGGREGATE_PASS_BY_REFERENCE typename Base_::BoundArg arg(binder.arg); ArgStruct args(pre, arg); typedef typename Function::Traits::Return (Function::*Target)(ArgStruct *); return (binder.function.*reinterpret_cast(&Function::InvokeValue))(&args); #else typedef typename Function::Traits::Return (Function::*Target)(ArgStruct, typename Base_::BoundArg); return (binder.function.*reinterpret_cast(&Function::InvokeValue))(pre, binder.arg); #endif } }; template struct Bind<0, Prototype_, Arg_, 0> : public BindBase_<0, Prototype_, Arg_> { typedef BindBase_<0, Prototype_, Arg_> Base_; static typename Function::Traits::Return InvokeBind(const typename Base_::Result *this_, ArgStruct) { typename Base_::Binder &binder(*reinterpret_cast(this_->GetValue().data)); #ifdef CFG_AGGREGATE_PASS_BY_REFERENCE typename Base_::BoundArg arg(binder.arg); ArgStruct args(arg); typedef typename Function::Traits::Return (Function::*Target)(ArgStruct *); return (binder.function.*reinterpret_cast(&Function::InvokeValue))(&args); #else typedef typename Function::Traits::Return (Function::*Target)(typename Base_::BoundArg); return (binder.function.*reinterpret_cast(&Function::InvokeValue))(binder.arg); #endif } }; template typename be::Bind::value>::Result Bind_(const Function &functor, Arg_ arg) { typedef be::Bind::value> Bind; typedef typename Bind::Result::Value Value; typedef typename Bind::Result::Value::Invoker Invoker; typedef typename Bind::Binder Binder; static const etl::TypeVTableImpl table; Binder binder(functor, arg); return typename Bind::Result(Value(reinterpret_cast(&Bind::InvokeBind), &binder), &table); } } template typename be::Bind::Prototype, Arg_, be::BindLength::Prototype>::value>::Result Bind(const Functor_ &functor, Arg_ arg) { return be::Bind_(Function::Prototype>(functor), arg); } template Function::Return ()> BindAll(const Functor_ &functor) { return functor; } template Function::Return ()> BindAll(const Functor_ &functor, Arg0_ arg0) { return Bind<0, Arg0_>(functor, arg0); } template Function::Return ()> BindAll(const Functor_ &functor, Arg0_ arg0, Arg1_ arg1) { return Bind<0, Arg1_>(Bind<0, Arg0_>(functor, arg0), arg1); } template Function::Return ()> BindAll(const Functor_ &functor, Arg0_ arg0, Arg1_ arg1, Arg2_ arg2) { return Bind<0, Arg2_>(Bind<0, Arg1_>(Bind<0, Arg0_>(functor, arg0), arg1), arg2); } template Function::Return ()> BindAll(const Functor_ &functor, Arg0_ arg0, Arg1_ arg1, Arg2_ arg2, Arg3_ arg3) { return Bind<0, Arg3_>(Bind<0, Arg2_>(Bind<0, Arg1_>(Bind<0, Arg0_>(functor, arg0), arg1), arg2), arg3); } template Function::Return ()> BindAll(const Functor_ &functor, Arg0_ arg0, Arg1_ arg1, Arg2_ arg2, Arg3_ arg3, Arg4_ arg4) { return Bind<0, Arg4_>(Bind<0, Arg3_>(Bind<0, Arg2_>(Bind<0, Arg1_>(Bind<0, Arg0_>(functor, arg0), arg1), arg2), arg3), arg4); } template Function::Return ()> BindAll(const Functor_ &functor, Arg0_ arg0, Arg1_ arg1, Arg2_ arg2, Arg3_ arg3, Arg4_ arg4, Arg5_ arg5) { return Bind<0, Arg5_>(Bind<0, Arg4_>(Bind<0, Arg3_>(Bind<0, Arg2_>(Bind<0, Arg1_>(Bind<0, Arg0_>(functor, arg0), arg1), arg2), arg3), arg4), arg5); } template Function::Return ()> BindAll(const Functor_ &functor, Arg0_ arg0, Arg1_ arg1, Arg2_ arg2, Arg3_ arg3, Arg4_ arg4, Arg5_ arg5, Arg6_ arg6) { return Bind<0, Arg6_>(Bind<0, Arg5_>(Bind<0, Arg4_>(Bind<0, Arg3_>(Bind<0, Arg2_>(Bind<0, Arg1_>(Bind<0, Arg0_>(functor, arg0), arg1), arg2), arg3), arg4), arg5), arg6); } namespace be { template class ConstReference { private: typedef ConstReference This_; private: const Type_ *value_; public: _finline ConstReference(const Type_ &value) : value_(&value) { } _finline operator const Type_ &() const { return *value_; } bool operator ==(const This_ &rhs) const { return value_ == rhs.value_; } bool operator <(const This_ &rhs) const { return value_ < rhs.value_; } }; } template be::ConstReference ConstReference(const Type_ &value) { return be::ConstReference(value); } } namespace ext { template hop::Function< typename hop::FunctionTraits< typename etl::Erase< typename hop::FunctionTraits::Type, 1 >::Result >::Prototype > operator ->*(const ext::SmartPointer &pointer, Right_ rhs) { return hop::Bind<0>(rhs, static_cast(pointer)); } } #endif//MENES_ETL_FNBIND_HPP