// // 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_OPERATOR_DOT_H #define FCPP_OPERATOR_DOT_H ////////////////////////////////////////////////////////////////////// // The goal here is to provide functoids for most C++ operators (e.g. // Plus, Greater, ...) as well as conversions between representations. // The conversions include ptr_to_fun, for turning function pointers into // functoids, stl_to_funN, for turning STL functoids into our functoids, // and monomophizeN, for converting polymorphic direct functoids into // monomorphic ones. // // There's also some miscellaneous stuff at both the beginning and the // end of this file, for lack of a better place to put it. ////////////////////////////////////////////////////////////////////// #include #include #include #include "lambda.h" namespace fcpp { ////////////////////////////////////////////////////////////////////// // syntactic sugar for infix operators ////////////////////////////////////////////////////////////////////// // The syntax // arg1 ^fun^ arg2 means fun( arg1, arg2 ) // like Haskell's backquotes. // // I feel justified in this convenient abuse of operator overloading in // that it's complete nonsense for someone to try to XOR a value with a // 2-argument full functoid. Put another way, I own Full2s; I can do // whatever I want with them, darn it! :) // // Note that it also works on Full3s (with currying). template struct InfixOpThingy { // Note that storing const&s here relies on the fact that temporaries // are guaranteed to live for the duration of the full-expression in // which they are created. There's no need to create copies. const LHS& lhs; const Fun& f; InfixOpThingy( const LHS& l, const Fun& ff ) : lhs(l), f(ff) {} }; template inline InfixOpThingy > operator^( const LHS& lhs, const Full2& f ) { return InfixOpThingy >(lhs,f); } template inline InfixOpThingy > operator^( const LHS& lhs, const Full3& f ) { return InfixOpThingy >(lhs,f); } template inline typename RT::ResultType operator^( const InfixOpThingy& x, const RHS& rhs ) { return x.f( x.lhs, rhs ); } template inline typename RT >::ResultType operator^( const InfixOpThingy& x, const Full2& rhs ) { return x.f( x.lhs, rhs ); } template inline typename RT >::ResultType operator^( const InfixOpThingy& x, const Full3& rhs ) { return x.f( x.lhs, rhs ); } // Furthermore, I just can't help myself from making // arg1 %fun% arg2 mean fun[ arg1 ][ arg2 ] // for use in lambda expressions. % is a good choice because it binds // more tightly than <=, so it's less likely to interfere with "gets" // bindings. #ifdef FCPP_ENABLE_LAMBDA template struct InfixOpWhatzit { // See comment in InfixOpThingy const LHS& lhs; const Fun& f; InfixOpWhatzit( const LHS& l, const Fun& ff ) : lhs(l), f(ff) {} }; template inline InfixOpWhatzit > operator%( const LHS& lhs, const Full2& f ) { return InfixOpWhatzit >(lhs,f); } template inline InfixOpWhatzit > operator%( const LHS& lhs, const Full3& f ) { return InfixOpWhatzit >(lhs,f); } template inline typename LEType,RHS> >::Type operator%( const InfixOpWhatzit& x, const RHS& rhs ) { return x.f[ x.lhs ][ rhs ]; } template inline typename LEType,Full2 > >::Type operator%( const InfixOpWhatzit& x, const Full2& rhs ) { return x.f[ x.lhs ][ rhs ]; } template inline typename LEType,Full3 > >::Type operator%( const InfixOpWhatzit& x, const Full3& rhs ) { return x.f[ x.lhs ][ rhs ]; } #endif ////////////////////////////////////////////////////////////////////// // operators ////////////////////////////////////////////////////////////////////// namespace impl { struct XMakePair { template struct Sig : public FunType > {}; template std::pair operator()( const A& a, const B& b ) const { return std::make_pair(a,b); } }; } typedef Full2 MakePair; FCPP_MAYBE_NAMESPACE_OPEN FCPP_MAYBE_EXTERN MakePair makePair; FCPP_MAYBE_NAMESPACE_CLOSE namespace impl { struct XMin { template struct Sig; template struct Sig : public FunType {}; template T operator()( const T& x, const T& y ) const { return std::less()( x, y ) ? x : y; } }; } typedef Full2 Min; FCPP_MAYBE_NAMESPACE_OPEN FCPP_MAYBE_EXTERN Min min; FCPP_MAYBE_NAMESPACE_CLOSE namespace impl { struct XMax { template struct Sig; template struct Sig : public FunType {}; template T operator()( const T& x, const T& y ) const { return std::less()( x, y ) ? y : x; } }; } typedef Full2 Max; FCPP_MAYBE_NAMESPACE_OPEN FCPP_MAYBE_EXTERN Max max; FCPP_MAYBE_NAMESPACE_CLOSE namespace impl { struct XPlus { template struct Sig; template struct Sig : public FunType {}; template T operator()( const T& x, const T& y ) const { return std::plus()( x, y ); } }; } typedef Full2 Plus; FCPP_MAYBE_NAMESPACE_OPEN FCPP_MAYBE_EXTERN Plus plus; FCPP_MAYBE_NAMESPACE_CLOSE namespace impl { struct XMinus { template struct Sig; template struct Sig : public FunType {}; template T operator()( const T& x, const T& y ) const { return std::minus()( x, y ); } }; } typedef Full2 Minus; FCPP_MAYBE_NAMESPACE_OPEN FCPP_MAYBE_EXTERN Minus minus; FCPP_MAYBE_NAMESPACE_CLOSE namespace impl { struct XMultiplies { template struct Sig; template struct Sig : public FunType {}; template T operator()( const T& x, const T& y ) const { return std::multiplies()( x, y ); } }; } typedef Full2 Multiplies; FCPP_MAYBE_NAMESPACE_OPEN FCPP_MAYBE_EXTERN Multiplies multiplies; FCPP_MAYBE_NAMESPACE_CLOSE namespace impl { struct XDivides { template struct Sig; template struct Sig : public FunType {}; template T operator()( const T& x, const T& y ) const { return std::divides()( x, y ); } }; } typedef Full2 Divides; FCPP_MAYBE_NAMESPACE_OPEN FCPP_MAYBE_EXTERN Divides divides; FCPP_MAYBE_NAMESPACE_CLOSE namespace impl { struct XModulus { template struct Sig; template struct Sig : public FunType {}; template T operator()( const T& x, const T& y ) const { return std::modulus()( x, y ); } }; } typedef Full2 Modulus; FCPP_MAYBE_NAMESPACE_OPEN FCPP_MAYBE_EXTERN Modulus modulus; FCPP_MAYBE_NAMESPACE_CLOSE namespace impl { struct XNegate { template struct Sig : public FunType {}; template T operator()( const T& x ) const { return std::negate()( x ); } }; } typedef Full1 Negate; FCPP_MAYBE_NAMESPACE_OPEN FCPP_MAYBE_EXTERN Negate negate; FCPP_MAYBE_NAMESPACE_CLOSE namespace impl { struct XEqual { template struct Sig; template struct Sig : public FunType {}; template bool operator()( const T&x, const T&y ) const { return std::equal_to()( x, y ); } }; } typedef Full2 Equal; FCPP_MAYBE_NAMESPACE_OPEN FCPP_MAYBE_EXTERN Equal equal; FCPP_MAYBE_NAMESPACE_CLOSE namespace impl { struct XNotEqual { template struct Sig; template struct Sig : public FunType {}; template bool operator()( const T&x, const T&y ) const { return std::not_equal_to()( x, y ); } }; } typedef Full2 NotEqual; FCPP_MAYBE_NAMESPACE_OPEN FCPP_MAYBE_EXTERN NotEqual notEqual; FCPP_MAYBE_NAMESPACE_CLOSE namespace impl { struct XGreater { template struct Sig; template struct Sig : public FunType {}; template bool operator()( const T&x, const T&y ) const { return std::greater()( x, y ); } }; } typedef Full2 Greater; FCPP_MAYBE_NAMESPACE_OPEN FCPP_MAYBE_EXTERN Greater greater; FCPP_MAYBE_NAMESPACE_CLOSE namespace impl { struct XLess { template struct Sig; template struct Sig : public FunType {}; template bool operator()( const T&x, const T&y ) const { return std::less()( x, y ); } }; } typedef Full2 Less; FCPP_MAYBE_NAMESPACE_OPEN FCPP_MAYBE_EXTERN Less less; FCPP_MAYBE_NAMESPACE_CLOSE namespace impl { struct XGreaterEqual { template struct Sig; template struct Sig : public FunType {}; template bool operator()( const T&x, const T&y ) const { return std::greater_equal()( x, y ); } }; } typedef Full2 GreaterEqual; FCPP_MAYBE_NAMESPACE_OPEN FCPP_MAYBE_EXTERN GreaterEqual greaterEqual; FCPP_MAYBE_NAMESPACE_CLOSE namespace impl { struct XLessEqual { template struct Sig; template struct Sig : public FunType {}; template bool operator()( const T&x, const T&y ) const { return std::less_equal()( x, y ); } }; } typedef Full2 LessEqual; FCPP_MAYBE_NAMESPACE_OPEN FCPP_MAYBE_EXTERN LessEqual lessEqual; FCPP_MAYBE_NAMESPACE_CLOSE namespace impl { struct XLogicalAnd { template struct Sig; template struct Sig : public FunType {}; template bool operator()( const T&x, const T&y ) const { return std::logical_and()( x, y ); } }; } typedef Full2 LogicalAnd; FCPP_MAYBE_NAMESPACE_OPEN FCPP_MAYBE_EXTERN LogicalAnd logicalAnd; FCPP_MAYBE_NAMESPACE_CLOSE namespace impl { struct XLogicalOr { template struct Sig; template struct Sig : public FunType {}; template bool operator()( const T&x, const T&y ) const { return std::logical_or()( x, y ); } }; } typedef Full2 LogicalOr; FCPP_MAYBE_NAMESPACE_OPEN FCPP_MAYBE_EXTERN LogicalOr logicalOr; FCPP_MAYBE_NAMESPACE_CLOSE namespace impl { struct XLogicalNot { template struct Sig : public FunType {}; template bool operator()( const T&x ) const { return std::logical_not()( x ); } }; } typedef Full1 LogicalNot; FCPP_MAYBE_NAMESPACE_OPEN FCPP_MAYBE_EXTERN LogicalNot logicalNot; FCPP_MAYBE_NAMESPACE_CLOSE namespace impl { struct XDereference { template struct Sig : public FunType::value_type> {}; template typename Sig::ResultType operator()( const T& p ) const { return *p; } }; } typedef Full1 Dereference; FCPP_MAYBE_NAMESPACE_OPEN FCPP_MAYBE_EXTERN Dereference dereference; FCPP_MAYBE_NAMESPACE_CLOSE namespace impl { struct XAddressOf { template struct Sig : public FunType {}; template const T* operator()( const T& x ) const { return &x; } }; } typedef Full1 AddressOf; FCPP_MAYBE_NAMESPACE_OPEN FCPP_MAYBE_EXTERN AddressOf addressOf; FCPP_MAYBE_NAMESPACE_CLOSE namespace impl { struct XDelete_ { template struct Sig : public FunType {}; template void operator()( T* p ) const { delete p; } }; } typedef Full1 Delete_; FCPP_MAYBE_NAMESPACE_OPEN FCPP_MAYBE_EXTERN Delete_ delete_; FCPP_MAYBE_NAMESPACE_CLOSE namespace impl { template struct XDynamicCast { template struct Sig : public FunType {}; template Dest operator()( const Src& s ) const { return dynamic_cast(s); } }; } template struct DynamicCast { typedef Full1 > Type; }; template Full1 > dynamicCast() { return makeFull1( impl::XDynamicCast() ); } // outStream is the << stream operator, but takes a stream* // e.g. &cout ^outStream^ x namespace impl { struct XOutStream { template struct Sig : public FunType {}; template StreamP operator()( StreamP s, const Data& x ) const { (*s) << x; return s; } }; } typedef Full2 OutStream; FCPP_MAYBE_NAMESPACE_OPEN FCPP_MAYBE_EXTERN OutStream outStream; FCPP_MAYBE_NAMESPACE_CLOSE // inStream is the >> stream operator, but takes stream* and data* // e.g. &cin ^inStream^ &x namespace impl { struct XInStream { template struct Sig : public FunType {}; template StreamP operator()( StreamP s, DataP x ) const { (*s) >> (*x); return s; } }; } typedef Full2 InStream; FCPP_MAYBE_NAMESPACE_OPEN FCPP_MAYBE_EXTERN InStream inStream; FCPP_MAYBE_NAMESPACE_CLOSE #ifndef FCPP_I_AM_GCC2 // makeManip(aStream)(aManip) returns the manipulator for that stream // (The C++ std stream manipulators have a crazy interface which // necessitates this ugliness.) // e.g. &cout ^outStream^ makeManip(cout)(endl) template struct ManipMaker { std::basic_ostream& (* operator()( std::basic_ostream& (*pfn)( std::basic_ostream&) ) const )( std::basic_ostream& ) { return pfn; } std::basic_ios& (* operator()( std::basic_ios& (*pfn)( std::basic_ios& ) ) const )( std::basic_ios& ) { return pfn; } std::ios_base& (* operator()( std::ios_base& (*pfn)( std::ios_base& ) ) const )( std::ios_base& ) { return pfn; } }; template ManipMaker makeManip( std::basic_ios& ) { return ManipMaker(); } #endif ////////////////////////////////////////////////////////////////////// // STL conversions ////////////////////////////////////////////////////////////////////// // Note that these are template functions, not functoids. I'm lazy. namespace impl { template class Xstl1 : public CFunType { Op f; public: Xstl1( const Op& o ) : f(o) {} typename Op::result_type operator()( const typename Op::argument_type& x ) const { return f(x); } }; } template Full1 > stl_to_fun1( const Op& o ) { return makeFull1( impl::Xstl1(o) ); } namespace impl { template class Xstl2 : public CFunType { Op f; public: Xstl2( const Op& o ) : f(o) {} typename Op::result_type operator()( const typename Op::first_argument_type& x, const typename Op::second_argument_type& y ) const { return f(x,y); } }; } template Full2 > stl_to_fun2( const Op& o ) { return makeFull2(impl::Xstl2(o)); } ////////////////////////////////////////////////////////////////////// // monomorphizing conversions ////////////////////////////////////////////////////////////////////// // Note that these are template functions, not functoids. I'm lazy. namespace impl { template class XMonomorphicWrapper3 : public CFunType { F f; public: XMonomorphicWrapper3( const F& g ) : f(g) {} Res operator()( const Arg1& x, const Arg2& y, const Arg3& z ) const { return f(x,y,z); } }; } template Full3 > monomorphize3( const F& f ) { return makeFull3(impl::XMonomorphicWrapper3( f )); } namespace impl { template class XMonomorphicWrapper2 : public CFunType { F f; public: XMonomorphicWrapper2( const F& g ) : f(g) {} Res operator()( const Arg1& x, const Arg2& y ) const { return f(x,y); } }; } template Full2 > monomorphize2( const F& f ) { return makeFull2(impl::XMonomorphicWrapper2( f )); } namespace impl { template class XMonomorphicWrapper1 : public CFunType { F f; public: XMonomorphicWrapper1( const F& g ) : f(g) {} Res operator()( const Arg1& x ) const { return f(x); } }; } template Full1 > monomorphize1( const F& f ) { return makeFull1( impl::XMonomorphicWrapper1( f ) ); } namespace impl { template class XMonomorphicWrapper0 : public CFunType { F f; public: XMonomorphicWrapper0( const F& g ) : f(g) {} Res operator()() const { return f(); } }; } template Full0 > monomorphize0( const F& f ) { return makeFull0( impl::XMonomorphicWrapper0( f ) ); } ////////////////////////////////////////////////////////////////////// // ptr_fun ////////////////////////////////////////////////////////////////////// // ptr_to_fun is now a functoid -- hurray! namespace impl { template class Xptr_to_nullary_function : public CFunType { Result (*ptr)(); public: explicit Xptr_to_nullary_function(Result (*x)()) : ptr(x) {} Result operator()() const { return ptr(); } }; template class Xptr_to_unary_function : public CFunType { Result (*ptr)(Arg); public: explicit Xptr_to_unary_function(Result (*x)(Arg)) : ptr(x) {} Result operator()(Arg x) const { return ptr(x); } }; template class Xptr_to_binary_function : public CFunType { Result (*ptr)(Arg1, Arg2); public: explicit Xptr_to_binary_function(Result (*x)(Arg1, Arg2)) : ptr(x) {} Result operator()(Arg1 x, Arg2 y) const { return ptr(x, y); } }; template class Xptr_to_ternary_function : public CFunType { Result (*ptr)(Arg1, Arg2, Arg3); public: explicit Xptr_to_ternary_function(Result (*x)(Arg1, Arg2, Arg3)) : ptr(x) {} Result operator()(Arg1 x, Arg2 y, Arg3 z) const { return ptr(x,y,z); } }; ////////////////////////////////////////////////////////////////////// // Turn member functions into normal functions which take a Receiver* // (or a smart pointer) as their first (extra) argument. Note that we // disallow reference parameters. ////////////////////////////////////////////////////////////////////// template class Xptr_to_mem_binary_function { Result (Arg1::*ptr)(Arg2,Arg3); public: explicit Xptr_to_mem_binary_function(Result (Arg1::*x)(Arg2,Arg3)) : ptr(x) {} template struct Sig : public FunType {}; template Result operator()(const P& x, const Arg2& y, const Arg3& z) const //{ return (x->*ptr)(y,z); } { return ((*x).*ptr)(y,z); } }; template class Xptr_to_const_mem_binary_function { Result (Arg1::*ptr)(Arg2,Arg3) const; public: explicit Xptr_to_const_mem_binary_function( Result (Arg1::*x)(Arg2,Arg3) const) : ptr(x) {} template struct Sig : public FunType {}; template Result operator()(const P& x, const Arg2& y, const Arg3& z) const //{ return (x->*ptr)(y,z); } { return ((*x).*ptr)(y,z); } }; template class Xptr_to_mem_unary_function { Result (Arg1::*ptr)(Arg2); public: explicit Xptr_to_mem_unary_function(Result (Arg1::*x)(Arg2)) : ptr(x) {} template struct Sig : public FunType {}; template Result operator()(const P& x, const Arg2& y) const //{ return (x->*ptr)(y); } { return ((*x).*ptr)(y); } }; template class Xptr_to_const_mem_unary_function { Result (Arg1::*ptr)(Arg2) const; public: explicit Xptr_to_const_mem_unary_function(Result (Arg1::*x)(Arg2) const) : ptr(x) {} template struct Sig : public FunType {}; template Result operator()(const P& x, const Arg2& y) const //{ return (x->*ptr)(y); } { return ((*x).*ptr)(y); } }; template class Xptr_to_mem_nullary_function { Result (Arg1::*ptr)(); public: explicit Xptr_to_mem_nullary_function(Result (Arg1::*x)()) : ptr(x) {} template struct Sig : public FunType {}; template //Result operator()(const P& x) const { return (x->*ptr)(); } Result operator()(const P& x) const { return ((*x).*ptr)(); } }; template class Xptr_to_const_mem_nullary_function { Result (Arg1::*ptr)() const; public: explicit Xptr_to_const_mem_nullary_function(Result (Arg1::*x)() const) : ptr(x) {} template struct Sig : public FunType {}; template //Result operator()(const P& x) const { return (x->*ptr)(); } Result operator()(const P& x) const { return ((*x).*ptr)(); } }; struct XPtrToFun { template struct Sig; // non-member functions template struct Sig< Result (*)() > : public FunType< Result (*)(), Full0 > > {}; template struct Sig< Result (*)(A1) > : public FunType< Result (*)(A1), Full1 > > {}; template struct Sig< Result (*)(A1,A2) > : public FunType< Result (*)(A1,A2), Full2 > > {}; template struct Sig< Result (*)(A1,A2,A3) > : public FunType< Result (*)(A1,A2,A3), Full3 > > {}; // member functions template struct Sig< Result (A1::*)(A2,A3) > : public FunType< Result (A1::*)(A2,A3), Full3 > > {}; template struct Sig< Result (A1::*)(A2,A3) const > : public FunType< Result (A1::*)(A2,A3) const, Full3 > > {}; template struct Sig< Result (A1::*)(A2) > : public FunType< Result (A1::*)(A2), Full2 > > {}; template struct Sig< Result (A1::*)(A2) const > : public FunType< Result (A1::*)(A2) const, Full2 > > {}; template struct Sig< Result (A1::*)() > : public FunType< Result (A1::*)(), Full1 > > {}; template struct Sig< Result (A1::*)() const > : public FunType< Result (A1::*)() const, Full1 > > {}; // non-member functions template inline Full0 > operator()(Result (*x)()) const { return makeFull0( Xptr_to_nullary_function(x) ); } template inline Full1 > operator()(Result (*x)(A)) const { return makeFull1( Xptr_to_unary_function(x) ); } template inline Full2 > operator()(Result (*x)(A1, A2)) const { return makeFull2( Xptr_to_binary_function(x) ); } template inline Full3 > operator()(Result (*x)(A1, A2, A3)) const { return makeFull3( Xptr_to_ternary_function(x) ); } // member functions template inline Full3 > operator()(Result (A1::*x)(A2,A3)) const { return makeFull3( Xptr_to_mem_binary_function(x) ); } template inline Full3 > operator()(Result (A1::*x)(A2,A3) const) const { return makeFull3( Xptr_to_const_mem_binary_function(x) ); } template inline Full2 > operator()(Result (A1::*x)(A2)) const { return makeFull2( Xptr_to_mem_unary_function(x) ); } template inline Full2 > operator()(Result (A1::*x)(A2) const) const { return makeFull2( Xptr_to_const_mem_unary_function(x) ); } template inline Full1 > operator()(Result (A1::*x)()) const { return makeFull1( Xptr_to_mem_nullary_function(x) ); } template inline Full1 > operator()(Result (A1::*x)() const) const { return makeFull1( Xptr_to_const_mem_nullary_function(x) ); } }; } // end namespace impl typedef Full1 PtrToFun; FCPP_MAYBE_NAMESPACE_OPEN FCPP_MAYBE_EXTERN PtrToFun ptr_to_fun; FCPP_MAYBE_NAMESPACE_CLOSE ////////////////////////////////////////////////////////////////////// // funify is an identity for FullNs, but calls ptr_to_fun otherwise ////////////////////////////////////////////////////////////////////// namespace impl { struct XFunify { template struct Sig : public FunType::ResultType> {}; template struct Sig< Full0 > : public FunType< Full0, Full0 > {}; template struct Sig< Full1 > : public FunType< Full1, Full1 > {}; template struct Sig< Full2 > : public FunType< Full2, Full2 > {}; template struct Sig< Full3 > : public FunType< Full3, Full3 > {}; template typename Sig

::ResultType operator()( const P& p ) const { return ptr_to_fun(p); } template typename Sig >::ResultType operator()( const Full0& f ) const { return f; } template typename Sig >::ResultType operator()( const Full1& f ) const { return f; } template typename Sig >::ResultType operator()( const Full2& f ) const { return f; } template typename Sig >::ResultType operator()( const Full3& f ) const { return f; } }; } typedef Full1 Funify; FCPP_MAYBE_NAMESPACE_OPEN FCPP_MAYBE_EXTERN Funify funify; FCPP_MAYBE_NAMESPACE_CLOSE ////////////////////////////////////////////////////////////////////// // Misc stuff ////////////////////////////////////////////////////////////////////// // FIX THIS: add dec? pre/post versions? namespace impl { struct XInc { template struct Sig : public FunType {}; template T operator()(const T& x) const { T y = x; return ++y; } }; } typedef Full1 Inc; FCPP_MAYBE_NAMESPACE_OPEN FCPP_MAYBE_EXTERN Inc inc; FCPP_MAYBE_NAMESPACE_CLOSE // These are obsolete; ignore(const_(true)) and ignore(const_(false)) // do the same thing. Hurray for combinators! namespace impl { struct XAlways1 { template struct Sig : public FunType {}; template bool operator()(const T&) const { return true; } }; } typedef Full1 Always1; FCPP_MAYBE_NAMESPACE_OPEN FCPP_MAYBE_EXTERN Always1 always1; FCPP_MAYBE_NAMESPACE_CLOSE namespace impl { struct XNever1 { template struct Sig : public FunType {}; template bool operator()(const T&) const { return false; } }; } typedef Full1 Never1; FCPP_MAYBE_NAMESPACE_OPEN FCPP_MAYBE_EXTERN Never1 never1; FCPP_MAYBE_NAMESPACE_CLOSE } // end namespace fcpp #endif