]>
Commit | Line | Data |
---|---|---|
7c673cae FG |
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> { | |
62 | static void remake( X& x, const X& val ) { | |
63 | x.~X(); | |
64 | new (&x) X(val); | |
65 | } | |
66 | static X clone( const X& x ) { return X(x); } | |
67 | }; | |
68 | template <class 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; } | |
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: | |
83 | ThunkImpl() : refC(0) {} | |
84 | virtual Result operator()() const =0; | |
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> | |
93 | void intrusive_ptr_add_ref( const ThunkImpl<T>* p ) { | |
94 | ++ (p->refC); | |
95 | } | |
96 | template <class T> | |
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; | |
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 ); | |
116 | } | |
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) ); | |
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; | |
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) ); | |
135 | else ref->init(f,x); | |
136 | return *ref; | |
137 | } | |
138 | 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; | |
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 ); | |
160 | } | |
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) ); | |
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; | |
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); | |
180 | return *ref; | |
181 | } | |
182 | 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; | |
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 ); | |
209 | } | |
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) ); | |
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; | |
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); | |
231 | return *ref; | |
232 | } | |
233 | 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; | |
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 ); | |
261 | } | |
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) ); | |
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; | |
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); | |
284 | return *ref; | |
285 | } | |
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); | |
288 | } | |
289 | }; | |
290 | ||
291 | } | |
292 | ||
293 | } | |
294 | } | |
295 | ||
296 | #endif |