// // Copyright (c) 2000-2003 Brian McNamara and Yannis Smaragdakis // // Permission to use, copy, modify, distribute and sell this software // and its documentation for any purpose is granted without fee, // provided that the above copyright notice and this permission notice // appear in all source code copies and supporting documentation. The // software is provided "as is" without any express or implied // warranty. #ifndef FCPP_FUNCTION_DOT_H #define FCPP_FUNCTION_DOT_H ////////////////////////////////////////////////////////////////////////// // Here is where FunN and FunNImpl classes are declared. Also here are // - makeFunN turn a monomorphic direct functoid into an indirect // functoid // - convertN for implicit conversions (subtype polymorphism) // - explicit_convertN like convertN, but uses casts (non-implicit) ////////////////////////////////////////////////////////////////////////// #include "ref_count.h" #include "operator.h" #ifndef FCPP_NO_USE_NAMESPACE namespace fcpp { #endif // AnyType is the type to use when we don't care about the // instantiation of a template. This usually happens when we are // reading the signature of a monomorphic function as if it were // polymorphic. class AnyType {}; ////////////////////////////////////////////////////////////////////// // Ok, this file has been a mess, so I'm trying to clean it up. The // file is divided into 4 sections, for Fun0, Fun1, Fun2, and Fun3. // The sections are all pretty redundant, except that // - Fun2 implements its own currying (it was written before Curryables were) // - Fun3 uses Curryable3 to implement its currying // As a result, I'm removing some of the redundant comments from all the // sections except Fun0. So basically, use the comments in the Fun0 // section as a reference for the corresponding structures in the other // FunN classes. ////////////////////////////////////////////////////////////////////// template struct Fun0Impl; template struct Fun0; template // result of dest, result of src Fun0Impl* convert0( const IRef >& f ); template struct Fun0Constructor; template class Fun0 { typedef IRef > RefImpl; RefImpl ref; template friend class Fun0; template friend Fun0 explicit_convert0( const Fun0& f ); template friend struct Fun0Constructor; public: // See comment in Fun0Impl about g++2.95.2 typedef Result ResultType; template struct Sig : public FunType {}; template struct Sig : public FunType {}; template struct crazy_accepts { static const bool args = false; }; template struct crazy_accepts { static const bool args = true; }; static const int crazy_max_args = 0; typedef const Fun0Impl* Impl; // int is dummy arg to differentiate from the template constructor Fun0( int, Impl i ) : ref(i) {} Result operator()() const { return ref->operator()(); } template // direct functoid (or subtype polymorphism) Fun0( const DF& f ) : ref( Fun0Constructor::make(f) ) {} Fun0( const Fun0& x ) : ref(x.ref) {} Fun0& operator=( const Fun0& x ) { ref = x.ref; return *this; } #ifdef FCPP_ENABLE_LAMBDA typedef Fun0 This; template typename fcpp_lambda::BracketCallable::Result operator[]( const A& a ) const { return fcpp_lambda::BracketCallable::go( *this, a ); } #endif }; // See comments below template struct Inherits,CallableWithoutArguments> { static const bool value = true; }; template struct Inherits,::fcpp::SmartFunctoid> { static const bool value = true; }; template struct Fun0Impl : public IRefable { // g++2.95.2 doesn't implement the empty-base-class-optimization, so we // 'hand code' the Sig information rather than just inheriting it from a // CFunType class. Fun0s are on the 'critical path' for lists, and need // to be extra efficient. typedef Result ResultType; template struct Sig : public FunType {}; template struct Sig : public FunType {}; virtual Result operator()() const =0; virtual ~Fun0Impl() {} }; // Since we cheated inheritance above, we need to inform our inheritance // detector for the particular case of importance. template struct Inherits,CallableWithoutArguments> { static const bool value = true; }; template class Fun0Converter : public Fun0Impl { typedef IRef > MyFun; MyFun f; public: Fun0Converter( const MyFun& g ) : f(g) {} Rd operator()() const { return f->operator()(); } }; template Fun0Impl* convert0( const IRef >& f ) { return new Fun0Converter( f ); } template class Fun0ExplicitConverter : public Fun0Impl { typedef IRef > MyFun; MyFun f; public: Fun0ExplicitConverter( const MyFun& g ) : f(g) {} Rd operator()() const { return static_cast( f->operator()() ); } }; template Fun0 explicit_convert0( const Fun0& f ) { return Fun0( 1, new Fun0ExplicitConverter( f.ref ) ); } template class Gen0 : public Fun0Impl::ResultType> { Gen g; public: Gen0( Gen x ) : g(x) {} typename RT::ResultType operator()() const { return g(); } }; template Fun0::ResultType> makeFun0( const Gen& g ) { return Fun0::ResultType>(1,new Gen0(g)); } template Gen0* makeFun0Ref( const Nullary& g ) { return new Gen0(g); } // Note: conversion-from-direct-functoid and subtype-polymorphism are // really two different kinds of functionality. However, if we try to // create two separate constructors in the Fun0 class, we end up with // ambiguity (C++ can't tell which one to call). As a result, there is // one constructor that handles both cases by forwarding the work to // this class, which uses partial specialization to distinguish between // the two cases. template struct Fun0Constructor { static Fun0Impl* make( const DF& df ) { return makeFun0Ref( ::fcpp::monomorphize0(df) ); } }; template struct Fun0Constructor > { static Fun0Impl* make( const Fun0& f ) { return convert0(f.ref); } }; ////////////////////////////////////////////////////////////////////// template struct Fun1Impl; template Fun1Impl* convert1( const IRef >& f ); template struct Fun1Constructor; template class Fun1 : public CFunType, public ::fcpp::SmartFunctoid1 { typedef IRef > RefImpl; RefImpl ref; template friend class Fun1; template friend struct Fun1Constructor; template friend Fun1 explicit_convert1( const Fun1& f ); public: typedef Fun1Impl* Impl; Fun1( int, Impl i ) : ref(i) {} Result operator()( const Arg1& x ) const { return ref->operator()(x); } template Fun1( const DF& df ) : ref( Fun1Constructor::make(df) ) {} Fun1( const Fun1& x ) : ref(x.ref) {} Fun1& operator=( const Fun1& x ) { ref = x.ref; return *this; } #ifdef FCPP_ENABLE_LAMBDA typedef Fun1 This; template typename fcpp_lambda::BracketCallable::Result operator[]( const A& a ) const { return fcpp_lambda::BracketCallable::go( *this, a ); } #endif }; template struct Fun1Impl : public CFunType, public IRefable { virtual Result operator()( const Arg1& ) const =0; virtual ~Fun1Impl() {} }; template class Fun1Converter : public Fun1Impl { typedef IRef > MyFun; MyFun f; public: Fun1Converter( const MyFun& g ) : f(g) {} Rd operator()( const A1d& x ) const { return f->operator()( x ); } }; template Fun1Impl* convert1( const IRef >& f ) { return new Fun1Converter( f ); } template class Fun1ExplicitConverter : public Fun1Impl { typedef IRef > MyFun; MyFun f; public: Fun1ExplicitConverter( const MyFun& g ) : f(g) {} Rd operator()( const A1d& x ) const { return static_cast( f->operator()( static_cast(x) ) ); } }; template Fun1 explicit_convert1( const Fun1& f ) { return Fun1( 1, new Fun1ExplicitConverter(f.ref) ); } template class Gen1 : public Fun1Impl::Arg1Type, typename Gen::template Sig::ResultType> { Gen g; public: Gen1( Gen x ) : g(x) {} typename Gen::template Sig::ResultType operator()( const typename Gen::template Sig::Arg1Type& x ) const { return g(x); } }; template Fun1::Arg1Type, typename Unary::template Sig::ResultType> makeFun1( const Unary& g ) { return Fun1::Arg1Type, typename Unary::template Sig::ResultType> (1,new Gen1(g)); } template Gen1* makeFun1Ref( const Unary& g ) { return new Gen1(g); } template struct Fun1Constructor { static Fun1Impl* make( const DF& df ) { return makeFun1Ref( ::fcpp::monomorphize1(df) ); } }; template struct Fun1Constructor > { static Fun1Impl* make( const Fun1& f ) { return convert1(f.ref); } }; ////////////////////////////////////////////////////////////////////// template struct Fun2Impl; template Fun2Impl* convert2( const IRef >& f ); template struct Fun2Constructor; // Note that this class has two signatures: it can be used either as // a two argument function or as a single argument function (currying). template class Fun2 : public ::fcpp::SmartFunctoid2 { typedef IRef > RefImpl; RefImpl ref; template friend class Fun2; template friend Fun2 explicit_convert2( const Fun2& f ); template friend struct Fun2Constructor; // kludge while this file not in namepsace (FCPP_NO_USE_NAMESPACE) typedef fcpp::AutoCurryType AutoCurryType; public: // Signature for normal use of the functoid (2 args) template struct Sig : public FunType {}; // Signature for using this function with automatic currying (1-arg) template struct Sig : public FunType > {}; // Signatures for using this function with underscore currying (1-arg) template struct Sig : public FunType > {}; template struct Sig : public FunType > {}; typedef Fun2Impl* Impl; Fun2( int, Impl i ) : ref(i) {} template Fun2( const DF& df ) : ref( Fun2Constructor::make(df) ) {} Fun2( const Fun2& x ) : ref(x.ref) {} Fun2& operator=( const Fun2& x ) { ref = x.ref; return *this; } // normal call Result operator()( const Arg1& x, const Arg2& y ) const { return ref->operator()(x,y); } // inheritable underscore currying! Fun1 operator()( const AutoCurryType&, const Arg2& y ) const { return makeFun1(bind2of2(*this, y)); } Fun1 operator()( const Arg1& x, const AutoCurryType& ) const { return makeFun1(bind1of2(*this, x)); } // REVIEW: Note that this could return a direct functoid, too, which // might be more efficient. Same with other currying calls. // inheritable automatic currying! Fun1 operator()( const Arg1& x) const { return makeFun1(bind1of2(*this, x)); } #ifdef FCPP_ENABLE_LAMBDA typedef Fun2 This; template typename fcpp_lambda::BracketCallable::Result operator[]( const A& a ) const { return fcpp_lambda::BracketCallable::go( *this, a ); } #endif }; template struct Fun2Impl : public CFunType, public IRefable { virtual Result operator()( const Arg1&, const Arg2& ) const =0; virtual ~Fun2Impl() {} }; template class Fun2Converter : public Fun2Impl { typedef IRef > MyFun; MyFun f; public: Fun2Converter( const MyFun& g ) : f(g) {} Rd operator()( const A1d& x, const A2d& y ) const { return f->operator()( x, y ); } }; template Fun2Impl* convert2( const IRef >& f ) { return new Fun2Converter( f ); } template class Fun2ExplicitConverter : public Fun2Impl { typedef IRef > MyFun; MyFun f; public: Fun2ExplicitConverter( const MyFun& g ) : f(g) {} Rd operator()( const A1d& x, const A2d& y ) const { return static_cast( f->operator()( static_cast(x), static_cast(y) ) ); } }; template Fun2 explicit_convert2( const Fun2& f ) { return Fun2( 1, new Fun2ExplicitConverter(f.ref) ); } template class Gen2 : public Fun2Impl< typename Gen::template Sig::Arg1Type, typename Gen::template Sig::Arg2Type, typename Gen::template Sig::ResultType> { Gen g; public: Gen2( Gen x ) : g(x) {} typename Gen::template Sig::ResultType operator()( const typename Gen::template Sig::Arg1Type& x, const typename Gen::template Sig::Arg2Type& y ) const { return g(x,y); } }; template Fun2::Arg1Type, typename Binary::template Sig::Arg2Type, typename Binary::template Sig::ResultType> makeFun2( const Binary& g ) { return Fun2::Arg1Type, typename Binary::template Sig::Arg2Type, typename Binary::template Sig::ResultType> (1,new Gen2(g)); } template Gen2* makeFun2Ref( const Binary& g ) { return new Gen2(g); } template struct Fun2Constructor { static Fun2Impl* make( const DF& df ) { return makeFun2Ref( ::fcpp::monomorphize2(df) ); } }; template struct Fun2Constructor > { static Fun2Impl* make( const Fun2& f ) { return convert2(f.ref); } }; ////////////////////////////////////////////////////////////////////// template struct Fun3Impl; template struct Fun3; template Fun3Impl* convert3( const IRef >& f ); template struct Fun3Constructor; // The "Guts" class helps us implement currying; Fun3 floats gently atop // Fun3Guts and adds currying. template class Fun3Guts : public CFunType { typedef IRef > RefImpl; RefImpl ref; template friend class Fun3Guts; template friend class Fun3; template friend struct Fun3Constructor; template friend Fun3 explicit_convert3( const Fun3& f ); public: typedef Fun3Impl* Impl; Fun3Guts( int, Impl i ) : ref(i) {} Result operator()( const Arg1& x, const Arg2& y, const Arg3& z ) const { return ref->operator()(x,y,z); } template Fun3Guts( const DF& df ) : ref( Fun3Constructor::make(df) ) {} Fun3Guts( const Fun3Guts& x ) : ref(x.ref) {} Fun3Guts& operator=( const Fun3Guts& x ) { ref = x.ref; return *this; } }; template class Fun3 : public ::fcpp::SmartFunctoid3 { template friend struct Fun3Constructor; template friend Fun3 explicit_convert3( const Fun3& f ); Fun3Guts rep; public: typedef Fun3Impl* Impl; Fun3( int, Impl i ) : rep(1,i) {} template Fun3( const DF& df ) : rep(df) {} Fun3( const Fun3& x ) : rep(x.rep) {} Fun3& operator=( const Fun3& x ) { rep = x.rep; return *this; } typedef fcpp::Curryable3 > SigHelp; template struct Sig : public SigHelp::template Sig {}; template typename Sig::ResultType operator()( const A& x, const B& y, const C& z ) const { return ::fcpp::makeCurryable3(rep)(x,y,z); } template typename Sig::ResultType operator()( const A& x, const B& y ) const { return ::fcpp::curry3(rep,x,y); } template typename Sig::ResultType operator()( const A& x ) const { return ::fcpp::curry3(rep,x); } #ifdef FCPP_ENABLE_LAMBDA typedef Fun3 This; template typename fcpp_lambda::BracketCallable::Result operator[]( const A& a ) const { return fcpp_lambda::BracketCallable::go( *this, a ); } #endif }; template struct Fun3Impl : public CFunType, public IRefable { public: Fun3Impl() {} virtual Result operator()( const Arg1&, const Arg2&, const Arg3& ) const =0; virtual ~Fun3Impl() {} }; template class Fun3Converter : public Fun3Impl { typedef IRef > MyFun; MyFun f; public: Fun3Converter( const MyFun& g ) : f(g) {} Rd operator()( const A1d& x, const A2d& y, const A3d& z ) const { return f->operator()( x, y, z ); } }; template Fun3Impl* convert3( const IRef >& f ) { return new Fun3Converter( f ); } template class Fun3ExplicitConverter : public Fun3Impl { typedef IRef > MyFun; MyFun f; public: Fun3ExplicitConverter( const MyFun& g ) : f(g) {} Rd operator()( const A1d& x, const A2d& y, const A3d& z ) const { return static_cast( f->operator()( static_cast(x), static_cast(y), static_cast(z) ) ); } }; template Fun3 explicit_convert3( const Fun3& f ) { return Fun3( 1, new Fun3ExplicitConverter(f.rep.ref) ); } template class Gen3 : public Fun3Impl< typename Gen::template Sig::Arg1Type, typename Gen::template Sig::Arg2Type, typename Gen::template Sig::Arg3Type, typename Gen::template Sig::ResultType> { Gen g; public: Gen3( Gen x ) : g(x) {} typename Gen::template Sig::ResultType operator()( const typename Gen::template Sig::Arg1Type& x, const typename Gen::template Sig::Arg2Type& y, const typename Gen::template Sig::Arg3Type& z ) const { return g(x,y,z); } }; template Fun3::Arg1Type, typename Ternary::template Sig::Arg2Type, typename Ternary::template Sig::Arg3Type, typename Ternary::template Sig::ResultType> makeFun3( const Ternary& g ) { return Fun3::Arg1Type, typename Ternary::template Sig::Arg2Type, typename Ternary::template Sig::Arg3Type, typename Ternary::template Sig::ResultType> (1,new Gen3(g)); } template Gen3* makeFun3Ref( const Ternary& g ) { return new Gen3(g); } template struct Fun3Constructor { static Fun3Impl* make( const DF& df ) { return makeFun3Ref( ::fcpp::monomorphize3(df) ); } }; template struct Fun3Constructor > { static Fun3Impl* make( const Fun3& f ) { return convert3(f.rep.ref); } }; #ifndef FCPP_NO_USE_NAMESPACE } // end namespace fcpp #endif #endif