1 ////////////////////////////////////////////////////////////////////////////
2 // lazy_reuse.hpp
3 //
4 // Build lazy operations for Phoenix equivalents for FC++
5 //
6 // These are equivalents of the Boost FC++ functoids in reuse.hpp
7 //
8 // Implemented so far:
9 //
10 // reuser1
11 // reuser2
12 // reuser3
13 // reuser4 (not yet tested)
14 //
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.
17 //
18 //       The functor type F must be an operator defined with
19 //       boost::phoenix::function.
20 //       See the example Apply in lazy_prelude.hpp
21 //
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
27 
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 ==============================================================================*/
31 
32 #ifndef BOOST_PHOENIX_FUNCTION_LAZY_REUSE
33 #define BOOST_PHOENIX_FUNCTION_LAZY_REUSE
34 
35 #include <boost/phoenix/core.hpp>
36 #include <boost/phoenix/function.hpp>
37 #include <boost/intrusive_ptr.hpp>
38 
39 
40 namespace boost {
41 
42   namespace phoenix {
43 
44     namespace fcpp {
45 
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 //////////////////////////////////////////////////////////////////////
54 
55 // For efficiency, we mark parameters as either "VAR"iant or "INV"ariant.
56 struct INV {};
57 struct VAR {};
58 
59 template <class V, class X> struct Maybe_Var_Inv;
60 template <class X>
61 struct Maybe_Var_Inv<VAR,X> {
remakeboost::phoenix::fcpp::Maybe_Var_Inv62    static void remake( X& x, const X& val ) {
63       x.~X();
64       new (&x) X(val);
65    }
cloneboost::phoenix::fcpp::Maybe_Var_Inv66    static X clone( const X& x ) { return X(x); }
67 };
68 template <class X>
69 struct Maybe_Var_Inv<INV,X> {
remakeboost::phoenix::fcpp::Maybe_Var_Inv70    static void remake( X&, const X& ) {}
cloneboost::phoenix::fcpp::Maybe_Var_Inv71    static const X& clone( const X& x ) { return x; }
72 };
73 
74 /////////////////////////////////////////////////////////////////////
75 // ThunkImpl is an implementation of Fun0Impl for this use.
76 /////////////////////////////////////////////////////////////////////
77 
78 template <class Result>
79 class ThunkImpl
80 {
81    mutable RefCountType refC;
82 public:
ThunkImpl()83    ThunkImpl() : refC(0) {}
84    virtual Result operator()() const =0;
~ThunkImpl()85    virtual ~ThunkImpl() {}
86    template <class X>
87    friend void intrusive_ptr_add_ref( const ThunkImpl<X>* p );
88    template <class X>
89    friend void intrusive_ptr_release( const ThunkImpl<X>* p );
90 };
91 
92 template <class T>
intrusive_ptr_add_ref(const ThunkImpl<T> * p)93 void intrusive_ptr_add_ref( const ThunkImpl<T>* p ) {
94    ++ (p->refC);
95 }
96 template <class T>
intrusive_ptr_release(const ThunkImpl<T> * p)97 void intrusive_ptr_release( const ThunkImpl<T>* p ) {
98    if( !--(p->refC) ) delete p;
99 }
100 
101 //////////////////////////////////////////////////////////////////////
102 // reuser1 is needed in list<T> operations
103 //////////////////////////////////////////////////////////////////////
104 
105 template <class V1, class V2, class F, class X>
106 struct reuser1;
107 
108 template <class V1, class V2, class F, class X, class R>
109 struct Thunk1 : public ThunkImpl<R> {
110    mutable F f;
111    mutable X x;
Thunk1boost::phoenix::fcpp::Thunk1112    Thunk1( const F& ff, const X& xx ) : f(ff), x(xx) {}
initboost::phoenix::fcpp::Thunk1113    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 );
116    }
operator ()boost::phoenix::fcpp::Thunk1117    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) );
121    }
122 };
123 
124 template <class V1, class V2, class F, class X>
125 struct reuser1 {
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;
reuser1boost::phoenix::fcpp::reuser1131    reuser1(a_unique_type_for_nil) {}
reuser1boost::phoenix::fcpp::reuser1132    reuser1(const M* m) : ref(m) {}
operator ()boost::phoenix::fcpp::reuser1133    M operator()( const F& f, const X& x ) {
134       if( !ref )   ref = boost::intrusive_ptr<const M>( new M(f,x) );
135       else         ref->init(f,x);
136       return *ref;
137    }
iterboost::phoenix::fcpp::reuser1138    void iter( const F& f, const X& x ) {
139       if( ref )    ref->init(f,x);
140    }
141 };
142 
143 //////////////////////////////////////////////////////////////////////
144 // reuser2 is needed in list<T>
145 //////////////////////////////////////////////////////////////////////
146 
147 template <class V1, class V2, class V3, class F, class X, class Y>
148 struct reuser2;
149 
150 template <class V1, class V2, class V3, class F, class X, class Y, class R>
151 struct Thunk2 : public ThunkImpl<R> {
152    mutable F f;
153    mutable X x;
154    mutable Y y;
Thunk2boost::phoenix::fcpp::Thunk2155    Thunk2( const F& ff, const X& xx, const Y& yy ) : f(ff), x(xx), y(yy) {}
initboost::phoenix::fcpp::Thunk2156    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 );
160    }
operator ()boost::phoenix::fcpp::Thunk2161    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) );
166    }
167 };
168 
169 template <class V1, class V2, class V3, class F, class X, class Y>
170 struct reuser2 {
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;
reuser2boost::phoenix::fcpp::reuser2175    reuser2(a_unique_type_for_nil) {}
reuser2boost::phoenix::fcpp::reuser2176    reuser2(const M* m) : ref(m) {}
operator ()boost::phoenix::fcpp::reuser2177    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);
180       return *ref;
181    }
iterboost::phoenix::fcpp::reuser2182    void iter( const F& f, const X& x, const Y& y ) {
183       if( ref )    ref->init(f,x,y);
184    }
185 };
186 
187 //////////////////////////////////////////////////////////////////////
188 // reuser3
189 //////////////////////////////////////////////////////////////////////
190 
191 template <class V1, class V2, class V3, class V4,
192           class F, class X, class Y, class Z>
193 struct reuser3;
194 
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> {
198    mutable F f;
199    mutable X x;
200    mutable Y y;
201    mutable Z z;
Thunk3boost::phoenix::fcpp::Thunk3202    Thunk3( const F& ff, const X& xx, const Y& yy, const Z& zz )
203       : f(ff), x(xx), y(yy), z(zz) {}
initboost::phoenix::fcpp::Thunk3204    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 );
209    }
operator ()boost::phoenix::fcpp::Thunk3210    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) );
216    }
217 };
218 
219 template <class V1, class V2, class V3, class V4,
220           class F, class X, class Y, class Z>
221 struct reuser3 {
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;
reuser3boost::phoenix::fcpp::reuser3226    reuser3(a_unique_type_for_nil) {}
reuser3boost::phoenix::fcpp::reuser3227    reuser3(const M* m) : ref(m) {}
operator ()boost::phoenix::fcpp::reuser3228    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);
231       return *ref;
232    }
iterboost::phoenix::fcpp::reuser3233    void iter( const F& f, const X& x, const Y& y, const Z& z ) {
234       if( ref )    ref->init(f,x,y,z);
235    }
236 };
237 //////////////////////////////////////////////////////////////////////
238 // reuser4
239 //////////////////////////////////////////////////////////////////////
240 
241       template <class V1, class V2, class V3, class V4, class V5,
242                 class F, class W, class X, class Y, class Z>
243 struct reuser4;
244 
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> {
248       mutable F f;
249       mutable W w;
250       mutable X x;
251       mutable Y y;
252       mutable Z z;
Thunk4boost::phoenix::fcpp::Thunk4253       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) {}
initboost::phoenix::fcpp::Thunk4255    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 );
261    }
operator ()boost::phoenix::fcpp::Thunk4262    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) );
269    }
270 };
271 
272       template <class V1, class V2, class V3, class V4, class V5,
273                 class F, class W, class X, class Y, class Z>
274       struct reuser4 {
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;
reuser4boost::phoenix::fcpp::reuser4279         reuser4(a_unique_type_for_nil) {}
reuser4boost::phoenix::fcpp::reuser4280         reuser4(const M* m) : ref(m) {}
operator ()boost::phoenix::fcpp::reuser4281    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);
284       return *ref;
285    }
iterboost::phoenix::fcpp::reuser4286    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);
288    }
289       };
290 
291     }
292 
293   }
294 }
295 
296 #endif
297