| //////////////////////////////////////////////////////////////////////////// |
| // 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 |