blob: c88b768e3dab6bd9b6c25c491a132b705c847aad [file] [log] [blame]
////////////////////////////////////////////////////////////////////////////
// lazy operator.hpp
//
// Build lazy operations for Phoenix equivalents for FC++
//
// These are equivalents of the Boost FC++ functoids in operator.hpp
//
// Implemented so far:
//
// make_pair
// plus minus multiplies divides modulus
// negate equal not_equal greater less
// greater_equal less_equal logical_and logical_or
// logical_not min max inc dec
//
// These are not from the FC++ operator.hpp but were made for testing purposes.
//
// identity (renamed id)
// sin
//
// These are now being modified to use boost::phoenix::function
// so that they are available for use as arguments.
// Types are being defined in capitals e.g. Id id;
////////////////////////////////////////////////////////////////////////////
/*=============================================================================
Copyright (c) 2000-2003 Brian McNamara and Yannis Smaragdakis
Copyright (c) 2001-2007 Joel de Guzman
Copyright (c) 2015 John Fletcher
Distributed under the Boost Software License, Version 1.0. (See accompanying
file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
==============================================================================*/
#ifndef BOOST_PHOENIX_FUNCTION_LAZY_OPERATOR
#define BOOST_PHOENIX_FUNCTION_LAZY_OPERATOR
#include <cmath>
#include <cstdlib>
#include <boost/phoenix/core.hpp>
#include <boost/phoenix/function.hpp>
#include <boost/function.hpp>
namespace boost {
namespace phoenix {
//////////////////////////////////////////////////////////////////////
// a_unique_type_for_nil
//////////////////////////////////////////////////////////////////////
// This may need to be moved elsewhere to define reuser.
struct a_unique_type_for_nil {
bool operator==( a_unique_type_for_nil ) const { return true; }
bool operator< ( a_unique_type_for_nil ) const { return false; }
typedef a_unique_type_for_nil value_type;
};
// This maybe put into a namespace.
a_unique_type_for_nil NIL;
//////////////////////////////////////////////////////////////////////
// lazy_exception - renamed from fcpp_exception.
//////////////////////////////////////////////////////////////////////
#ifndef BOOST_PHOENIX_NO_LAZY_EXCEPTIONS
struct lazy_exception : public std::exception {
const char* s;
lazy_exception( const char* ss ) : s(ss) {}
const char* what() const throw() { return s; }
};
#endif
//////////////////////////////////////////////////////////////////////
// in ref_count.hpp in BoostFC++
typedef unsigned int RefCountType;
namespace impl {
struct Id
{
template <typename Sig>
struct result;
template <typename This, typename A0>
struct result<This(A0)>
: boost::remove_reference<A0>
{};
template <typename A0>
A0 operator()(A0 const & a0) const
{
return a0;
}
};
}
//BOOST_PHOENIX_ADAPT_CALLABLE(id, impl::id, 1)
typedef boost::phoenix::function<impl::Id> Id;
Id id;
#ifdef BOOST_RESULT_OF_USE_TR1
// Experiment following examples in
// phoenix/stl/container/container.hpp
namespace result_of {
template <
typename Arg1
, typename Arg2
>
class make_pair
{
public:
typedef typename boost::remove_reference<Arg1>::type Arg1Type;
typedef typename boost::remove_reference<Arg2>::type Arg2Type;
typedef std::pair<Arg1Type,Arg2Type> type;
typedef std::pair<Arg1Type,Arg2Type> result_type;
};
}
#endif
namespace impl
{
struct make_pair {
#ifdef BOOST_RESULT_OF_USE_TR1
template <typename Sig>
struct result;
// This fails with -O2 unless refs are removed from A1 and A2.
template <typename This, typename A0, typename A1>
struct result<This(A0, A1)>
{
typedef typename result_of::make_pair<A0,A1>::type type;
};
#else
template <typename Sig>
struct result;
template <typename This, typename A0, typename A1>
struct result<This(A0, A1)>
: boost::remove_reference<std::pair<A0, A1> >
{};
#endif
template <typename A0, typename A1>
#ifdef BOOST_RESULT_OF_USE_TR1
typename result<make_pair(A0,A1)>::type
#else
std::pair<A0, A1>
#endif
operator()(A0 const & a0, A1 const & a1) const
{
return std::make_pair(a0,a1);
}
};
}
BOOST_PHOENIX_ADAPT_CALLABLE(make_pair, impl::make_pair, 2)
namespace impl
{
// For now I will leave the return type deduction as it is.
// I want to look at bringing in the sort of type deduction for
// mixed types which I have in FC++.
// Also I could look at the case where one of the arguments is
// another functor or a Phoenix placeholder.
struct Plus
{
template <typename Sig>
struct result;
template <typename This, typename A0, typename A1>
struct result<This(A0, A1)>
: boost::remove_reference<A0>
{};
template <typename This, typename A0, typename A1, typename A2>
struct result<This(A0, A1, A2)>
: boost::remove_reference<A0>
{};
template <typename A0, typename A1>
A0 operator()(A0 const & a0, A1 const & a1) const
{
//A0 res = a0 + a1;
//return res;
return a0 + a1;
}
template <typename A0, typename A1, typename A2>
A0 operator()(A0 const & a0, A1 const & a1, A2 const & a2) const
{
return a0 + a1 + a2;
}
};
struct Minus
{
template <typename Sig>
struct result;
template <typename This, typename A0, typename A1>
struct result<This(A0, A1)>
: boost::remove_reference<A0>
{};
template <typename A0, typename A1>
A0 operator()(A0 const & a0, A1 const & a1) const
{
return a0 - a1;
}
};
struct multiplies
{
template <typename Sig>
struct result;
template <typename This, typename A0, typename A1>
struct result<This(A0, A1)>
: boost::remove_reference<A0>
{};
template <typename A0, typename A1>
A0 operator()(A0 const & a0, A1 const & a1) const
{
return a0 * a1;
}
};
struct divides
{
template <typename Sig>
struct result;
template <typename This, typename A0, typename A1>
struct result<This(A0, A1)>
: boost::remove_reference<A0>
{};
template <typename A0, typename A1>
A0 operator()(A0 const & a0, A1 const & a1) const
{
return a0 / a1;
}
};
struct modulus
{
template <typename Sig>
struct result;
template <typename This, typename A0, typename A1>
struct result<This(A0, A1)>
: boost::remove_reference<A0>
{};
template <typename A0, typename A1>
A0 operator()(A0 const & a0, A1 const & a1) const
{
return a0 % a1;
}
};
struct negate
{
template <typename Sig>
struct result;
template <typename This, typename A0>
struct result<This(A0)>
: boost::remove_reference<A0>
{};
template <typename A0>
A0 operator()(A0 const & a0) const
{
return -a0;
}
};
struct equal
{
template <typename Sig>
struct result;
template <typename This, typename A0, typename A1>
struct result<This(A0,A1)>
{
typedef bool type;
};
template <typename A0, typename A1>
bool operator()(A0 const & a0, A1 const & a1) const
{
return a0 == a1;
}
};
struct not_equal
{
template <typename Sig>
struct result;
template <typename This, typename A0, typename A1>
struct result<This(A0,A1)>
{
typedef bool type;
};
template <typename A0, typename A1>
bool operator()(A0 const & a0, A1 const & a1) const
{
return a0 != a1;
}
};
struct greater
{
template <typename Sig>
struct result;
template <typename This, typename A0, typename A1>
struct result<This(A0,A1)>
{
typedef bool type;
};
template <typename A0, typename A1>
bool operator()(A0 const & a0, A1 const & a1) const
{
return a0 > a1;
}
};
struct less
{
template <typename Sig>
struct result;
template <typename This, typename A0, typename A1>
struct result<This(A0,A1)>
{
typedef bool type;
};
template <typename A0, typename A1>
bool operator()(A0 const & a0, A1 const & a1) const
{
return a0 < a1;
}
};
struct greater_equal
{
template <typename Sig>
struct result;
template <typename This, typename A0, typename A1>
struct result<This(A0,A1)>
{
typedef bool type;
};
template <typename A0, typename A1>
bool operator()(A0 const & a0, A1 const & a1) const
{
return a0 >= a1;
}
};
struct less_equal
{
template <typename Sig>
struct result;
template <typename This, typename A0, typename A1>
struct result<This(A0,A1)>
{
typedef bool type;
};
template <typename A0, typename A1>
bool operator()(A0 const & a0, A1 const & a1) const
{
return a0 <= a1;
}
};
struct logical_and
{
template <typename Sig>
struct result;
template <typename This, typename A0, typename A1>
struct result<This(A0,A1)>
{
typedef bool type;
};
template <typename A0, typename A1>
bool operator()(A0 const & a0, A1 const & a1) const
{
return a0 && a1;
}
};
struct logical_or
{
template <typename Sig>
struct result;
template <typename This, typename A0, typename A1>
struct result<This(A0,A1)>
{
typedef bool type;
};
template <typename A0, typename A1>
bool operator()(A0 const & a0, A1 const & a1) const
{
return a0 || a1;
}
};
struct logical_not
{
template <typename Sig>
struct result;
template <typename This, typename A0>
struct result<This(A0)>
{
typedef bool type;
};
template <typename A0>
bool operator()(A0 const & a0) const
{
return !a0;
}
};
struct min
{
template <typename Sig>
struct result;
template <typename This, typename A0, typename A1>
struct result<This(A0, A1)>
: boost::remove_reference<A0>
{};
template <typename A0, typename A1>
A0 operator()(A0 const & a0, A1 const & a1) const
{
if ( a0 < a1 ) return a0; else return a1;
}
};
struct max
{
template <typename Sig>
struct result;
template <typename This, typename A0, typename A1>
struct result<This(A0, A1)>
: boost::remove_reference<A0>
{};
template <typename A0, typename A1>
A0 operator()(A0 const & a0, A1 const & a1) const
{
if ( a0 < a1 ) return a1; else return a0;
}
};
struct Inc
{
template <typename Sig>
struct result;
template <typename This, typename A0>
struct result<This(A0)>
: boost::remove_reference<A0>
{};
template <typename A0>
A0 operator()(A0 const & a0) const
{
return a0 + 1;
}
};
struct Dec
{
template <typename Sig>
struct result;
template <typename This, typename A0>
struct result<This(A0)>
: boost::remove_reference<A0>
{};
template <typename A0>
A0 operator()(A0 const & a0) const
{
return a0 - 1;
}
};
struct Sin
{
template <typename Sig>
struct result;
template <typename This, typename A0>
struct result<This(A0)>
: boost::remove_reference<A0>
{};
template <typename A0>
A0 operator()(A0 const & a0) const
{
return std::sin(a0);
}
};
// Example of templated struct.
// How do I make it callable?
template <typename Result>
struct what {
typedef Result result_type;
Result operator()(Result const & r) const
{
return r;
}
// what is not complete - error.
//static boost::function1<Result,Result> res = what<Result>();
};
template <typename Result>
struct what0 {
typedef Result result_type;
Result operator()() const
{
return Result(100);
}
};
template <class Result, class F>
class MonomorphicWrapper0 /* : public c_fun_type<Res> */
{
F f;
public:
typedef Result result_type;
MonomorphicWrapper0( const F& g ) : f(g) {}
Result operator()() const {
return f();
}
};
/* I need the equivalent of this
template <class Res, class F>
full0<impl::XMonomorphicWrapper0<Res,F> > monomorphize0( const F& f )
{
return make_full0( impl::XMonomorphicWrapper0<Res,F>( f ) );
}*/
// boost::function0<int> res = MonomorphicWrapper0<int,F>(f);
template <class Res, class F>
boost::function<Res()> monomorphize0( const F& f )
{
boost::function0<Res> ff = MonomorphicWrapper0<Res,F>( f );
//BOOST_PHOENIX_ADAPT_FUNCTION_NULLARY(Res,fres,ff)
return ff;
}
// This is C++1y
//template <typename Result>
//static boost::function1<Result,Result> res = what<Result>();
}
/////////////////////////////////////////////////////////
// Look at this. How to use Phoenix with a templated
// struct. First adapt with boost::function and then
// convert that to Phoenix!!
// I have not found out how to do it directly.
/////////////////////////////////////////////////////////
boost::function1<int, int > what_int = impl::what<int>();
typedef boost::function1<int,int> fun1_int_int;
typedef boost::function0<int> fun0_int;
boost::function0<int> what0_int = impl::what0<int>();
BOOST_PHOENIX_ADAPT_FUNCTION(int,what,what_int,1)
BOOST_PHOENIX_ADAPT_FUNCTION_NULLARY(int,what0,what0_int)
// And this shows how to make them into argument callable functions.
typedef boost::phoenix::function<fun1_int_int> What_arg;
typedef boost::phoenix::function<fun0_int> What0_arg;
What_arg what_arg(what_int);
What0_arg what0_arg(what0_int);
//BOOST_PHOENIX_ADAPT_CALLABLE(plus, impl::plus, 2)
//BOOST_PHOENIX_ADAPT_CALLABLE(plus, impl::plus, 3)
//BOOST_PHOENIX_ADAPT_CALLABLE(minus, impl::minus, 2)
BOOST_PHOENIX_ADAPT_CALLABLE(multiplies, impl::multiplies, 2)
BOOST_PHOENIX_ADAPT_CALLABLE(divides, impl::divides, 2)
BOOST_PHOENIX_ADAPT_CALLABLE(modulus, impl::modulus, 2)
BOOST_PHOENIX_ADAPT_CALLABLE(negate, impl::negate, 1)
BOOST_PHOENIX_ADAPT_CALLABLE(equal, impl::equal, 2)
BOOST_PHOENIX_ADAPT_CALLABLE(not_equal, impl::not_equal, 2)
BOOST_PHOENIX_ADAPT_CALLABLE(greater, impl::greater, 2)
BOOST_PHOENIX_ADAPT_CALLABLE(less, impl::less, 2)
BOOST_PHOENIX_ADAPT_CALLABLE(greater_equal, impl::greater_equal, 2)
BOOST_PHOENIX_ADAPT_CALLABLE(less_equal, impl::less_equal, 2)
BOOST_PHOENIX_ADAPT_CALLABLE(logical_and, impl::logical_and, 2)
BOOST_PHOENIX_ADAPT_CALLABLE(logical_or, impl::logical_or, 2)
BOOST_PHOENIX_ADAPT_CALLABLE(logical_not, impl::logical_not, 1)
BOOST_PHOENIX_ADAPT_CALLABLE(min, impl::min, 2)
BOOST_PHOENIX_ADAPT_CALLABLE(max, impl::max, 2)
//BOOST_PHOENIX_ADAPT_CALLABLE(inc, impl::inc, 1)
//BOOST_PHOENIX_ADAPT_CALLABLE(dec, impl::dec, 1)
//BOOST_PHOENIX_ADAPT_CALLABLE(sin, impl::sin, 1)
// To use these as arguments they have to be defined like this.
typedef boost::phoenix::function<impl::Plus> Plus;
typedef boost::phoenix::function<impl::Minus> Minus;
typedef boost::phoenix::function<impl::Inc> Inc;
typedef boost::phoenix::function<impl::Dec> Dec;
typedef boost::phoenix::function<impl::Sin> Sin;
Plus plus;
Minus minus;
Inc inc;
Dec dec;
Sin sin;
}
}
#endif