blob: cef2ded820036fcb6a7e866c4f27167e26ee3ce7 [file] [log] [blame]
////////////////////////////////////////////////////////////////////////////
// lazy_reuse.hpp
//
// Build lazy operations for Phoenix equivalents for FC++
//
// These are equivalents of the Boost FC++ functoids in reuse.hpp
//
// Implemented so far:
//
// reuser1 (not yet tested)
// reuser2 (not yet tested)
// reuser3
//
// NOTE: It has been possible to simplify the operation of this code.
// It now makes no use of boost::function or old FC++ code.
//
// The functor type F must be an operator defined with
// boost::phoenix::function.
// See the example Apply in lazy_prelude.hpp
//
////////////////////////////////////////////////////////////////////////////
/*=============================================================================
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_REUSE
#define BOOST_PHOENIX_FUNCTION_LAZY_REUSE
#include <boost/phoenix/core.hpp>
#include <boost/phoenix/function.hpp>
#include <boost/intrusive_ptr.hpp>
namespace boost {
namespace phoenix {
namespace fcpp {
//////////////////////////////////////////////////////////////////////
// Original FC++ comment:
// "Reuser"s are effectively special-purpose versions of curry() that
// enable recursive list functoids to reuse the thunk of the curried
// recursive call. See
// http://www.cc.gatech.edu/~yannis/fc++/New/reusers.html
// for a more detailed description.
//////////////////////////////////////////////////////////////////////
// For efficiency, we mark parameters as either "VAR"iant or "INV"ariant.
struct INV {};
struct VAR {};
template <class V, class X> struct Maybe_Var_Inv;
template <class X>
struct Maybe_Var_Inv<VAR,X> {
static void remake( X& x, const X& val ) {
x.~X();
new (&x) X(val);
}
static X clone( const X& x ) { return X(x); }
};
template <class X>
struct Maybe_Var_Inv<INV,X> {
static void remake( X&, const X& ) {}
static const X& clone( const X& x ) { return x; }
};
/////////////////////////////////////////////////////////////////////
// ThunkImpl is an implementation of Fun0Impl for this use.
/////////////////////////////////////////////////////////////////////
template <class Result>
class ThunkImpl
{
mutable RefCountType refC;
public:
ThunkImpl() : refC(0) {}
virtual Result operator()() const =0;
virtual ~ThunkImpl() {}
template <class X>
friend void intrusive_ptr_add_ref( const ThunkImpl<X>* p );
template <class X>
friend void intrusive_ptr_release( const ThunkImpl<X>* p );
};
template <class T>
void intrusive_ptr_add_ref( const ThunkImpl<T>* p ) {
++ (p->refC);
}
template <class T>
void intrusive_ptr_release( const ThunkImpl<T>* p ) {
if( !--(p->refC) ) delete p;
}
//////////////////////////////////////////////////////////////////////
// reuser1 is needed in list<T> operations
//////////////////////////////////////////////////////////////////////
template <class V1, class V2, class F, class X>
struct reuser1;
template <class V1, class V2, class F, class X, class R>
struct Thunk1 : public ThunkImpl<R> {
mutable F f;
mutable X x;
Thunk1( const F& ff, const X& xx ) : f(ff), x(xx) {}
void init( const F& ff, const X& xx ) const {
Maybe_Var_Inv<V1,F>::remake( f, ff );
Maybe_Var_Inv<V2,X>::remake( x, xx );
}
R operator()() const {
return Maybe_Var_Inv<V1,F>::clone(f)(
Maybe_Var_Inv<V2,X>::clone(x),
reuser1<V1,V2,F,X>(this) );
}
};
template <class V1, class V2, class F, class X>
struct reuser1 {
typedef typename F::template result<F(X)>::type R;
typedef typename boost::phoenix::function<R> fun0_type;
typedef Thunk1<V1,V2,F,X,R> M;
typedef M result_type;
boost::intrusive_ptr<const M> ref;
reuser1(a_unique_type_for_nil) {}
reuser1(const M* m) : ref(m) {}
M operator()( const F& f, const X& x ) {
if( !ref ) ref = boost::intrusive_ptr<const M>( new M(f,x) );
else ref->init(f,x);
return *ref;
}
void iter( const F& f, const X& x ) {
if( ref ) ref->init(f,x);
}
};
//////////////////////////////////////////////////////////////////////
// reuser2 is needed in list<T>
//////////////////////////////////////////////////////////////////////
template <class V1, class V2, class V3, class F, class X, class Y>
struct reuser2;
template <class V1, class V2, class V3, class F, class X, class Y, class R>
struct Thunk2 : public ThunkImpl<R> {
mutable F f;
mutable X x;
mutable Y y;
Thunk2( const F& ff, const X& xx, const Y& yy ) : f(ff), x(xx), y(yy) {}
void init( const F& ff, const X& xx, const Y& yy ) const {
Maybe_Var_Inv<V1,F>::remake( f, ff );
Maybe_Var_Inv<V2,X>::remake( x, xx );
Maybe_Var_Inv<V3,Y>::remake( y, yy );
}
R operator()() const {
return Maybe_Var_Inv<V1,F>::clone(f)(
Maybe_Var_Inv<V2,X>::clone(x),
Maybe_Var_Inv<V3,Y>::clone(y),
reuser2<V1,V2,V3,F,X,Y>(this) );
}
};
template <class V1, class V2, class V3, class F, class X, class Y>
struct reuser2 {
typedef typename F::template result<F(X,Y)>::type R;
typedef Thunk2<V1,V2,V3,F,X,Y,R> M;
typedef M result_type;
boost::intrusive_ptr<const M> ref;
reuser2(a_unique_type_for_nil) {}
reuser2(const M* m) : ref(m) {}
M operator()( const F& f, const X& x, const Y& y ) {
if( !ref ) ref = boost::intrusive_ptr<const M>( new M(f,x,y) );
else ref->init(f,x,y);
return *ref;
}
void iter( const F& f, const X& x, const Y& y ) {
if( ref ) ref->init(f,x,y);
}
};
//////////////////////////////////////////////////////////////////////
// reuser3
//////////////////////////////////////////////////////////////////////
template <class V1, class V2, class V3, class V4,
class F, class X, class Y, class Z>
struct reuser3;
template <class V1, class V2, class V3, class V4,
class F, class X, class Y, class Z, class R>
struct Thunk3 : public ThunkImpl<R> {
mutable F f;
mutable X x;
mutable Y y;
mutable Z z;
Thunk3( const F& ff, const X& xx, const Y& yy, const Z& zz )
: f(ff), x(xx), y(yy), z(zz) {}
void init( const F& ff, const X& xx, const Y& yy, const Z& zz ) const {
Maybe_Var_Inv<V1,F>::remake( f, ff );
Maybe_Var_Inv<V2,X>::remake( x, xx );
Maybe_Var_Inv<V3,Y>::remake( y, yy );
Maybe_Var_Inv<V4,Z>::remake( z, zz );
}
R operator()() const {
return Maybe_Var_Inv<V1,F>::clone(f)(
Maybe_Var_Inv<V2,X>::clone(x),
Maybe_Var_Inv<V3,Y>::clone(y),
Maybe_Var_Inv<V4,Z>::clone(z),
reuser3<V1,V2,V3,V4,F,X,Y,Z>(this) );
}
};
template <class V1, class V2, class V3, class V4,
class F, class X, class Y, class Z>
struct reuser3 {
typedef typename F::template result<F(X,Y,Z)>::type R;
typedef Thunk3<V1,V2,V3,V4,F,X,Y,Z,R> M;
typedef M result_type;
boost::intrusive_ptr<const M> ref;
reuser3(a_unique_type_for_nil) {}
reuser3(const M* m) : ref(m) {}
M operator()( const F& f, const X& x, const Y& y, const Z& z ) {
if( !ref ) ref = boost::intrusive_ptr<const M>( new M(f,x,y,z) );
else ref->init(f,x,y,z);
return *ref;
}
void iter( const F& f, const X& x, const Y& y, const Z& z ) {
if( ref ) ref->init(f,x,y,z);
}
};
}
}
}
#endif