Chris@102: //////////////////////////////////////////////////////////////////////////// Chris@102: // lazy_reuse.hpp Chris@102: // Chris@102: // Build lazy operations for Phoenix equivalents for FC++ Chris@102: // Chris@102: // These are equivalents of the Boost FC++ functoids in reuse.hpp Chris@102: // Chris@102: // Implemented so far: Chris@102: // Chris@102: // reuser1 (not yet tested) Chris@102: // reuser2 (not yet tested) Chris@102: // reuser3 Chris@102: // Chris@102: // NOTE: It has been possible to simplify the operation of this code. Chris@102: // It now makes no use of boost::function or old FC++ code. Chris@102: // Chris@102: // The functor type F must be an operator defined with Chris@102: // boost::phoenix::function. Chris@102: // See the example Apply in lazy_prelude.hpp Chris@102: // Chris@102: //////////////////////////////////////////////////////////////////////////// Chris@102: /*============================================================================= Chris@102: Copyright (c) 2000-2003 Brian McNamara and Yannis Smaragdakis Chris@102: Copyright (c) 2001-2007 Joel de Guzman Chris@102: Copyright (c) 2015 John Fletcher Chris@102: Chris@102: Distributed under the Boost Software License, Version 1.0. (See accompanying Chris@102: file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) Chris@102: ==============================================================================*/ Chris@102: Chris@102: #ifndef BOOST_PHOENIX_FUNCTION_LAZY_REUSE Chris@102: #define BOOST_PHOENIX_FUNCTION_LAZY_REUSE Chris@102: Chris@102: #include Chris@102: #include Chris@102: #include Chris@102: Chris@102: Chris@102: namespace boost { Chris@102: Chris@102: namespace phoenix { Chris@102: Chris@102: namespace fcpp { Chris@102: Chris@102: ////////////////////////////////////////////////////////////////////// Chris@102: // Original FC++ comment: Chris@102: // "Reuser"s are effectively special-purpose versions of curry() that Chris@102: // enable recursive list functoids to reuse the thunk of the curried Chris@102: // recursive call. See Chris@102: // http://www.cc.gatech.edu/~yannis/fc++/New/reusers.html Chris@102: // for a more detailed description. Chris@102: ////////////////////////////////////////////////////////////////////// Chris@102: Chris@102: // For efficiency, we mark parameters as either "VAR"iant or "INV"ariant. Chris@102: struct INV {}; Chris@102: struct VAR {}; Chris@102: Chris@102: template struct Maybe_Var_Inv; Chris@102: template Chris@102: struct Maybe_Var_Inv { Chris@102: static void remake( X& x, const X& val ) { Chris@102: x.~X(); Chris@102: new (&x) X(val); Chris@102: } Chris@102: static X clone( const X& x ) { return X(x); } Chris@102: }; Chris@102: template Chris@102: struct Maybe_Var_Inv { Chris@102: static void remake( X&, const X& ) {} Chris@102: static const X& clone( const X& x ) { return x; } Chris@102: }; Chris@102: Chris@102: ///////////////////////////////////////////////////////////////////// Chris@102: // ThunkImpl is an implementation of Fun0Impl for this use. Chris@102: ///////////////////////////////////////////////////////////////////// Chris@102: Chris@102: template Chris@102: class ThunkImpl Chris@102: { Chris@102: mutable RefCountType refC; Chris@102: public: Chris@102: ThunkImpl() : refC(0) {} Chris@102: virtual Result operator()() const =0; Chris@102: virtual ~ThunkImpl() {} Chris@102: template Chris@102: friend void intrusive_ptr_add_ref( const ThunkImpl* p ); Chris@102: template Chris@102: friend void intrusive_ptr_release( const ThunkImpl* p ); Chris@102: }; Chris@102: Chris@102: template Chris@102: void intrusive_ptr_add_ref( const ThunkImpl* p ) { Chris@102: ++ (p->refC); Chris@102: } Chris@102: template Chris@102: void intrusive_ptr_release( const ThunkImpl* p ) { Chris@102: if( !--(p->refC) ) delete p; Chris@102: } Chris@102: Chris@102: ////////////////////////////////////////////////////////////////////// Chris@102: // reuser1 is needed in list operations Chris@102: ////////////////////////////////////////////////////////////////////// Chris@102: Chris@102: template Chris@102: struct reuser1; Chris@102: Chris@102: template Chris@102: struct Thunk1 : public ThunkImpl { Chris@102: mutable F f; Chris@102: mutable X x; Chris@102: Thunk1( const F& ff, const X& xx ) : f(ff), x(xx) {} Chris@102: void init( const F& ff, const X& xx ) const { Chris@102: Maybe_Var_Inv::remake( f, ff ); Chris@102: Maybe_Var_Inv::remake( x, xx ); Chris@102: } Chris@102: R operator()() const { Chris@102: return Maybe_Var_Inv::clone(f)( Chris@102: Maybe_Var_Inv::clone(x), Chris@102: reuser1(this) ); Chris@102: } Chris@102: }; Chris@102: Chris@102: template Chris@102: struct reuser1 { Chris@102: typedef typename F::template result::type R; Chris@102: typedef typename boost::phoenix::function fun0_type; Chris@102: typedef Thunk1 M; Chris@102: typedef M result_type; Chris@102: boost::intrusive_ptr ref; Chris@102: reuser1(a_unique_type_for_nil) {} Chris@102: reuser1(const M* m) : ref(m) {} Chris@102: M operator()( const F& f, const X& x ) { Chris@102: if( !ref ) ref = boost::intrusive_ptr( new M(f,x) ); Chris@102: else ref->init(f,x); Chris@102: return *ref; Chris@102: } Chris@102: void iter( const F& f, const X& x ) { Chris@102: if( ref ) ref->init(f,x); Chris@102: } Chris@102: }; Chris@102: Chris@102: ////////////////////////////////////////////////////////////////////// Chris@102: // reuser2 is needed in list Chris@102: ////////////////////////////////////////////////////////////////////// Chris@102: Chris@102: template Chris@102: struct reuser2; Chris@102: Chris@102: template Chris@102: struct Thunk2 : public ThunkImpl { Chris@102: mutable F f; Chris@102: mutable X x; Chris@102: mutable Y y; Chris@102: Thunk2( const F& ff, const X& xx, const Y& yy ) : f(ff), x(xx), y(yy) {} Chris@102: void init( const F& ff, const X& xx, const Y& yy ) const { Chris@102: Maybe_Var_Inv::remake( f, ff ); Chris@102: Maybe_Var_Inv::remake( x, xx ); Chris@102: Maybe_Var_Inv::remake( y, yy ); Chris@102: } Chris@102: R operator()() const { Chris@102: return Maybe_Var_Inv::clone(f)( Chris@102: Maybe_Var_Inv::clone(x), Chris@102: Maybe_Var_Inv::clone(y), Chris@102: reuser2(this) ); Chris@102: } Chris@102: }; Chris@102: Chris@102: template Chris@102: struct reuser2 { Chris@102: typedef typename F::template result::type R; Chris@102: typedef Thunk2 M; Chris@102: typedef M result_type; Chris@102: boost::intrusive_ptr ref; Chris@102: reuser2(a_unique_type_for_nil) {} Chris@102: reuser2(const M* m) : ref(m) {} Chris@102: M operator()( const F& f, const X& x, const Y& y ) { Chris@102: if( !ref ) ref = boost::intrusive_ptr( new M(f,x,y) ); Chris@102: else ref->init(f,x,y); Chris@102: return *ref; Chris@102: } Chris@102: void iter( const F& f, const X& x, const Y& y ) { Chris@102: if( ref ) ref->init(f,x,y); Chris@102: } Chris@102: }; Chris@102: Chris@102: ////////////////////////////////////////////////////////////////////// Chris@102: // reuser3 Chris@102: ////////////////////////////////////////////////////////////////////// Chris@102: Chris@102: template Chris@102: struct reuser3; Chris@102: Chris@102: template Chris@102: struct Thunk3 : public ThunkImpl { Chris@102: mutable F f; Chris@102: mutable X x; Chris@102: mutable Y y; Chris@102: mutable Z z; Chris@102: Thunk3( const F& ff, const X& xx, const Y& yy, const Z& zz ) Chris@102: : f(ff), x(xx), y(yy), z(zz) {} Chris@102: void init( const F& ff, const X& xx, const Y& yy, const Z& zz ) const { Chris@102: Maybe_Var_Inv::remake( f, ff ); Chris@102: Maybe_Var_Inv::remake( x, xx ); Chris@102: Maybe_Var_Inv::remake( y, yy ); Chris@102: Maybe_Var_Inv::remake( z, zz ); Chris@102: } Chris@102: R operator()() const { Chris@102: return Maybe_Var_Inv::clone(f)( Chris@102: Maybe_Var_Inv::clone(x), Chris@102: Maybe_Var_Inv::clone(y), Chris@102: Maybe_Var_Inv::clone(z), Chris@102: reuser3(this) ); Chris@102: } Chris@102: }; Chris@102: Chris@102: template Chris@102: struct reuser3 { Chris@102: typedef typename F::template result::type R; Chris@102: typedef Thunk3 M; Chris@102: typedef M result_type; Chris@102: boost::intrusive_ptr ref; Chris@102: reuser3(a_unique_type_for_nil) {} Chris@102: reuser3(const M* m) : ref(m) {} Chris@102: M operator()( const F& f, const X& x, const Y& y, const Z& z ) { Chris@102: if( !ref ) ref = boost::intrusive_ptr( new M(f,x,y,z) ); Chris@102: else ref->init(f,x,y,z); Chris@102: return *ref; Chris@102: } Chris@102: void iter( const F& f, const X& x, const Y& y, const Z& z ) { Chris@102: if( ref ) ref->init(f,x,y,z); Chris@102: } Chris@102: }; Chris@102: Chris@102: } Chris@102: Chris@102: } Chris@102: } Chris@102: Chris@102: #endif