//////////////////////////////////////////////////////////////////////////// // 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 // reuser2 // reuser3 // reuser4 (not yet tested) // // 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 #include #include 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 struct Maybe_Var_Inv; template struct Maybe_Var_Inv { static void remake( X& x, const X& val ) { x.~X(); new (&x) X(val); } static X clone( const X& x ) { return X(x); } }; template struct Maybe_Var_Inv { 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 ThunkImpl { mutable RefCountType refC; public: ThunkImpl() : refC(0) {} virtual Result operator()() const =0; virtual ~ThunkImpl() {} template friend void intrusive_ptr_add_ref( const ThunkImpl* p ); template friend void intrusive_ptr_release( const ThunkImpl* p ); }; template void intrusive_ptr_add_ref( const ThunkImpl* p ) { ++ (p->refC); } template void intrusive_ptr_release( const ThunkImpl* p ) { if( !--(p->refC) ) delete p; } ////////////////////////////////////////////////////////////////////// // reuser1 is needed in list operations ////////////////////////////////////////////////////////////////////// template struct reuser1; template struct Thunk1 : public ThunkImpl { 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::remake( f, ff ); Maybe_Var_Inv::remake( x, xx ); } R operator()() const { return Maybe_Var_Inv::clone(f)( Maybe_Var_Inv::clone(x), reuser1(this) ); } }; template struct reuser1 { typedef typename F::template result::type R; typedef typename boost::phoenix::function fun0_type; typedef Thunk1 M; typedef M result_type; boost::intrusive_ptr 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( 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 ////////////////////////////////////////////////////////////////////// template struct reuser2; template struct Thunk2 : public ThunkImpl { 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::remake( f, ff ); Maybe_Var_Inv::remake( x, xx ); Maybe_Var_Inv::remake( y, yy ); } R operator()() const { return Maybe_Var_Inv::clone(f)( Maybe_Var_Inv::clone(x), Maybe_Var_Inv::clone(y), reuser2(this) ); } }; template struct reuser2 { typedef typename F::template result::type R; typedef Thunk2 M; typedef M result_type; boost::intrusive_ptr 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( 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 struct reuser3; template struct Thunk3 : public ThunkImpl { 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::remake( f, ff ); Maybe_Var_Inv::remake( x, xx ); Maybe_Var_Inv::remake( y, yy ); Maybe_Var_Inv::remake( z, zz ); } R operator()() const { return Maybe_Var_Inv::clone(f)( Maybe_Var_Inv::clone(x), Maybe_Var_Inv::clone(y), Maybe_Var_Inv::clone(z), reuser3(this) ); } }; template struct reuser3 { typedef typename F::template result::type R; typedef Thunk3 M; typedef M result_type; boost::intrusive_ptr 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( 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); } }; ////////////////////////////////////////////////////////////////////// // reuser4 ////////////////////////////////////////////////////////////////////// template struct reuser4; template struct Thunk4 : public ThunkImpl { mutable F f; mutable W w; mutable X x; mutable Y y; mutable Z z; Thunk4( const F& ff, const W& ww, const X& xx, const Y& yy, const Z& zz ) : f(ff), w(ww), x(xx), y(yy), z(zz) {} void init( const F& ff, const W& ww, const X& xx, const Y& yy, const Z& zz ) const { Maybe_Var_Inv::remake( f, ff ); Maybe_Var_Inv::remake( w, ww ); Maybe_Var_Inv::remake( x, xx ); Maybe_Var_Inv::remake( y, yy ); Maybe_Var_Inv::remake( z, zz ); } R operator()() const { return Maybe_Var_Inv::clone(f)( Maybe_Var_Inv::clone(w), Maybe_Var_Inv::clone(x), Maybe_Var_Inv::clone(y), Maybe_Var_Inv::clone(z), reuser4(this) ); } }; template struct reuser4 { typedef typename F::template result::type R; typedef Thunk4 M; typedef M result_type; boost::intrusive_ptr ref; reuser4(a_unique_type_for_nil) {} reuser4(const M* m) : ref(m) {} M operator()( const F& f, const W& w, const X& x, const Y& y, const Z& z ) { if( !ref ) ref = boost::intrusive_ptr( new M(f,w,x,y,z) ); else ref->init(f,w,x,y,z); return *ref; } void iter( const F& f, const W& w, const X& x, const Y& y, const Z& z ) { if( ref ) ref->init(f,w,x,y,z); } }; } } } #endif