1 ////////////////////////////////////////////////////////////////////////////
4 // Build lazy operations for Phoenix equivalents for FC++
6 // These are equivalents of the Boost FC++ functoids in reuse.hpp
13 // reuser4 (not yet tested)
15 // NOTE: It has been possible to simplify the operation of this code.
16 // It now makes no use of boost::function or old FC++ code.
18 // The functor type F must be an operator defined with
19 // boost::phoenix::function.
20 // See the example Apply in lazy_prelude.hpp
22 ////////////////////////////////////////////////////////////////////////////
23 /*=============================================================================
24 Copyright (c) 2000-2003 Brian McNamara and Yannis Smaragdakis
25 Copyright (c) 2001-2007 Joel de Guzman
26 Copyright (c) 2015 John Fletcher
28 Distributed under the Boost Software License, Version 1.0. (See accompanying
29 file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
30 ==============================================================================*/
32 #ifndef BOOST_PHOENIX_FUNCTION_LAZY_REUSE
33 #define BOOST_PHOENIX_FUNCTION_LAZY_REUSE
35 #include <boost/phoenix/core.hpp>
36 #include <boost/phoenix/function.hpp>
37 #include <boost/intrusive_ptr.hpp>
46 //////////////////////////////////////////////////////////////////////
47 // Original FC++ comment:
48 // "Reuser"s are effectively special-purpose versions of curry() that
49 // enable recursive list functoids to reuse the thunk of the curried
50 // recursive call. See
51 // http://www.cc.gatech.edu/~yannis/fc++/New/reusers.html
52 // for a more detailed description.
53 //////////////////////////////////////////////////////////////////////
55 // For efficiency, we mark parameters as either "VAR"iant or "INV"ariant.
59 template <class V, class X> struct Maybe_Var_Inv;
61 struct Maybe_Var_Inv<VAR,X> {
62 static void remake( X& x, const X& val ) {
66 static X clone( const X& x ) { return X(x); }
69 struct Maybe_Var_Inv<INV,X> {
70 static void remake( X&, const X& ) {}
71 static const X& clone( const X& x ) { return x; }
74 /////////////////////////////////////////////////////////////////////
75 // ThunkImpl is an implementation of Fun0Impl for this use.
76 /////////////////////////////////////////////////////////////////////
78 template <class Result>
81 mutable RefCountType refC;
83 ThunkImpl() : refC(0) {}
84 virtual Result operator()() const =0;
85 virtual ~ThunkImpl() {}
87 friend void intrusive_ptr_add_ref( const ThunkImpl<X>* p );
89 friend void intrusive_ptr_release( const ThunkImpl<X>* p );
93 void intrusive_ptr_add_ref( const ThunkImpl<T>* p ) {
97 void intrusive_ptr_release( const ThunkImpl<T>* p ) {
98 if( !--(p->refC) ) delete p;
101 //////////////////////////////////////////////////////////////////////
102 // reuser1 is needed in list<T> operations
103 //////////////////////////////////////////////////////////////////////
105 template <class V1, class V2, class F, class X>
108 template <class V1, class V2, class F, class X, class R>
109 struct Thunk1 : public ThunkImpl<R> {
112 Thunk1( const F& ff, const X& xx ) : f(ff), x(xx) {}
113 void init( const F& ff, const X& xx ) const {
114 Maybe_Var_Inv<V1,F>::remake( f, ff );
115 Maybe_Var_Inv<V2,X>::remake( x, xx );
117 R operator()() const {
118 return Maybe_Var_Inv<V1,F>::clone(f)(
119 Maybe_Var_Inv<V2,X>::clone(x),
120 reuser1<V1,V2,F,X>(this) );
124 template <class V1, class V2, class F, class X>
126 typedef typename F::template result<F(X)>::type R;
127 typedef typename boost::phoenix::function<R> fun0_type;
128 typedef Thunk1<V1,V2,F,X,R> M;
129 typedef M result_type;
130 boost::intrusive_ptr<const M> ref;
131 reuser1(a_unique_type_for_nil) {}
132 reuser1(const M* m) : ref(m) {}
133 M operator()( const F& f, const X& x ) {
134 if( !ref ) ref = boost::intrusive_ptr<const M>( new M(f,x) );
138 void iter( const F& f, const X& x ) {
139 if( ref ) ref->init(f,x);
143 //////////////////////////////////////////////////////////////////////
144 // reuser2 is needed in list<T>
145 //////////////////////////////////////////////////////////////////////
147 template <class V1, class V2, class V3, class F, class X, class Y>
150 template <class V1, class V2, class V3, class F, class X, class Y, class R>
151 struct Thunk2 : public ThunkImpl<R> {
155 Thunk2( const F& ff, const X& xx, const Y& yy ) : f(ff), x(xx), y(yy) {}
156 void init( const F& ff, const X& xx, const Y& yy ) const {
157 Maybe_Var_Inv<V1,F>::remake( f, ff );
158 Maybe_Var_Inv<V2,X>::remake( x, xx );
159 Maybe_Var_Inv<V3,Y>::remake( y, yy );
161 R operator()() const {
162 return Maybe_Var_Inv<V1,F>::clone(f)(
163 Maybe_Var_Inv<V2,X>::clone(x),
164 Maybe_Var_Inv<V3,Y>::clone(y),
165 reuser2<V1,V2,V3,F,X,Y>(this) );
169 template <class V1, class V2, class V3, class F, class X, class Y>
171 typedef typename F::template result<F(X,Y)>::type R;
172 typedef Thunk2<V1,V2,V3,F,X,Y,R> M;
173 typedef M result_type;
174 boost::intrusive_ptr<const M> ref;
175 reuser2(a_unique_type_for_nil) {}
176 reuser2(const M* m) : ref(m) {}
177 M operator()( const F& f, const X& x, const Y& y ) {
178 if( !ref ) ref = boost::intrusive_ptr<const M>( new M(f,x,y) );
179 else ref->init(f,x,y);
182 void iter( const F& f, const X& x, const Y& y ) {
183 if( ref ) ref->init(f,x,y);
187 //////////////////////////////////////////////////////////////////////
189 //////////////////////////////////////////////////////////////////////
191 template <class V1, class V2, class V3, class V4,
192 class F, class X, class Y, class Z>
195 template <class V1, class V2, class V3, class V4,
196 class F, class X, class Y, class Z, class R>
197 struct Thunk3 : public ThunkImpl<R> {
202 Thunk3( const F& ff, const X& xx, const Y& yy, const Z& zz )
203 : f(ff), x(xx), y(yy), z(zz) {}
204 void init( const F& ff, const X& xx, const Y& yy, const Z& zz ) const {
205 Maybe_Var_Inv<V1,F>::remake( f, ff );
206 Maybe_Var_Inv<V2,X>::remake( x, xx );
207 Maybe_Var_Inv<V3,Y>::remake( y, yy );
208 Maybe_Var_Inv<V4,Z>::remake( z, zz );
210 R operator()() const {
211 return Maybe_Var_Inv<V1,F>::clone(f)(
212 Maybe_Var_Inv<V2,X>::clone(x),
213 Maybe_Var_Inv<V3,Y>::clone(y),
214 Maybe_Var_Inv<V4,Z>::clone(z),
215 reuser3<V1,V2,V3,V4,F,X,Y,Z>(this) );
219 template <class V1, class V2, class V3, class V4,
220 class F, class X, class Y, class Z>
222 typedef typename F::template result<F(X,Y,Z)>::type R;
223 typedef Thunk3<V1,V2,V3,V4,F,X,Y,Z,R> M;
224 typedef M result_type;
225 boost::intrusive_ptr<const M> ref;
226 reuser3(a_unique_type_for_nil) {}
227 reuser3(const M* m) : ref(m) {}
228 M operator()( const F& f, const X& x, const Y& y, const Z& z ) {
229 if( !ref ) ref = boost::intrusive_ptr<const M>( new M(f,x,y,z) );
230 else ref->init(f,x,y,z);
233 void iter( const F& f, const X& x, const Y& y, const Z& z ) {
234 if( ref ) ref->init(f,x,y,z);
237 //////////////////////////////////////////////////////////////////////
239 //////////////////////////////////////////////////////////////////////
241 template <class V1, class V2, class V3, class V4, class V5,
242 class F, class W, class X, class Y, class Z>
245 template <class V1, class V2, class V3, class V4, class V5,
246 class F, class W, class X, class Y, class Z, class R>
247 struct Thunk4 : public ThunkImpl<R> {
253 Thunk4( const F& ff, const W& ww, const X& xx, const Y& yy, const Z& zz )
254 : f(ff), w(ww), x(xx), y(yy), z(zz) {}
255 void init( const F& ff, const W& ww, const X& xx, const Y& yy, const Z& zz ) const {
256 Maybe_Var_Inv<V1,F>::remake( f, ff );
257 Maybe_Var_Inv<V2,W>::remake( w, ww );
258 Maybe_Var_Inv<V3,X>::remake( x, xx );
259 Maybe_Var_Inv<V4,Y>::remake( y, yy );
260 Maybe_Var_Inv<V5,Z>::remake( z, zz );
262 R operator()() const {
263 return Maybe_Var_Inv<V1,F>::clone(f)(
264 Maybe_Var_Inv<V2,W>::clone(w),
265 Maybe_Var_Inv<V3,X>::clone(x),
266 Maybe_Var_Inv<V4,Y>::clone(y),
267 Maybe_Var_Inv<V5,Z>::clone(z),
268 reuser4<V1,V2,V3,V4,V5,F,W,X,Y,Z>(this) );
272 template <class V1, class V2, class V3, class V4, class V5,
273 class F, class W, class X, class Y, class Z>
275 typedef typename F::template result<F(W,X,Y,Z)>::type R;
276 typedef Thunk4<V1,V2,V3,V4,V5,F,W,X,Y,Z,R> M;
277 typedef M result_type;
278 boost::intrusive_ptr<const M> ref;
279 reuser4(a_unique_type_for_nil) {}
280 reuser4(const M* m) : ref(m) {}
281 M operator()( const F& f, const W& w, const X& x, const Y& y, const Z& z ) {
282 if( !ref ) ref = boost::intrusive_ptr<const M>( new M(f,w,x,y,z) );
283 else ref->init(f,w,x,y,z);
286 void iter( const F& f, const W& w, const X& x, const Y& y, const Z& z ) {
287 if( ref ) ref->init(f,w,x,y,z);