Chris@102
|
1 ////////////////////////////////////////////////////////////////////////////
|
Chris@102
|
2 // lazy_reuse.hpp
|
Chris@102
|
3 //
|
Chris@102
|
4 // Build lazy operations for Phoenix equivalents for FC++
|
Chris@102
|
5 //
|
Chris@102
|
6 // These are equivalents of the Boost FC++ functoids in reuse.hpp
|
Chris@102
|
7 //
|
Chris@102
|
8 // Implemented so far:
|
Chris@102
|
9 //
|
Chris@102
|
10 // reuser1 (not yet tested)
|
Chris@102
|
11 // reuser2 (not yet tested)
|
Chris@102
|
12 // reuser3
|
Chris@102
|
13 //
|
Chris@102
|
14 // NOTE: It has been possible to simplify the operation of this code.
|
Chris@102
|
15 // It now makes no use of boost::function or old FC++ code.
|
Chris@102
|
16 //
|
Chris@102
|
17 // The functor type F must be an operator defined with
|
Chris@102
|
18 // boost::phoenix::function.
|
Chris@102
|
19 // See the example Apply in lazy_prelude.hpp
|
Chris@102
|
20 //
|
Chris@102
|
21 ////////////////////////////////////////////////////////////////////////////
|
Chris@102
|
22 /*=============================================================================
|
Chris@102
|
23 Copyright (c) 2000-2003 Brian McNamara and Yannis Smaragdakis
|
Chris@102
|
24 Copyright (c) 2001-2007 Joel de Guzman
|
Chris@102
|
25 Copyright (c) 2015 John Fletcher
|
Chris@102
|
26
|
Chris@102
|
27 Distributed under the Boost Software License, Version 1.0. (See accompanying
|
Chris@102
|
28 file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
Chris@102
|
29 ==============================================================================*/
|
Chris@102
|
30
|
Chris@102
|
31 #ifndef BOOST_PHOENIX_FUNCTION_LAZY_REUSE
|
Chris@102
|
32 #define BOOST_PHOENIX_FUNCTION_LAZY_REUSE
|
Chris@102
|
33
|
Chris@102
|
34 #include <boost/phoenix/core.hpp>
|
Chris@102
|
35 #include <boost/phoenix/function.hpp>
|
Chris@102
|
36 #include <boost/intrusive_ptr.hpp>
|
Chris@102
|
37
|
Chris@102
|
38
|
Chris@102
|
39 namespace boost {
|
Chris@102
|
40
|
Chris@102
|
41 namespace phoenix {
|
Chris@102
|
42
|
Chris@102
|
43 namespace fcpp {
|
Chris@102
|
44
|
Chris@102
|
45 //////////////////////////////////////////////////////////////////////
|
Chris@102
|
46 // Original FC++ comment:
|
Chris@102
|
47 // "Reuser"s are effectively special-purpose versions of curry() that
|
Chris@102
|
48 // enable recursive list functoids to reuse the thunk of the curried
|
Chris@102
|
49 // recursive call. See
|
Chris@102
|
50 // http://www.cc.gatech.edu/~yannis/fc++/New/reusers.html
|
Chris@102
|
51 // for a more detailed description.
|
Chris@102
|
52 //////////////////////////////////////////////////////////////////////
|
Chris@102
|
53
|
Chris@102
|
54 // For efficiency, we mark parameters as either "VAR"iant or "INV"ariant.
|
Chris@102
|
55 struct INV {};
|
Chris@102
|
56 struct VAR {};
|
Chris@102
|
57
|
Chris@102
|
58 template <class V, class X> struct Maybe_Var_Inv;
|
Chris@102
|
59 template <class X>
|
Chris@102
|
60 struct Maybe_Var_Inv<VAR,X> {
|
Chris@102
|
61 static void remake( X& x, const X& val ) {
|
Chris@102
|
62 x.~X();
|
Chris@102
|
63 new (&x) X(val);
|
Chris@102
|
64 }
|
Chris@102
|
65 static X clone( const X& x ) { return X(x); }
|
Chris@102
|
66 };
|
Chris@102
|
67 template <class X>
|
Chris@102
|
68 struct Maybe_Var_Inv<INV,X> {
|
Chris@102
|
69 static void remake( X&, const X& ) {}
|
Chris@102
|
70 static const X& clone( const X& x ) { return x; }
|
Chris@102
|
71 };
|
Chris@102
|
72
|
Chris@102
|
73 /////////////////////////////////////////////////////////////////////
|
Chris@102
|
74 // ThunkImpl is an implementation of Fun0Impl for this use.
|
Chris@102
|
75 /////////////////////////////////////////////////////////////////////
|
Chris@102
|
76
|
Chris@102
|
77 template <class Result>
|
Chris@102
|
78 class ThunkImpl
|
Chris@102
|
79 {
|
Chris@102
|
80 mutable RefCountType refC;
|
Chris@102
|
81 public:
|
Chris@102
|
82 ThunkImpl() : refC(0) {}
|
Chris@102
|
83 virtual Result operator()() const =0;
|
Chris@102
|
84 virtual ~ThunkImpl() {}
|
Chris@102
|
85 template <class X>
|
Chris@102
|
86 friend void intrusive_ptr_add_ref( const ThunkImpl<X>* p );
|
Chris@102
|
87 template <class X>
|
Chris@102
|
88 friend void intrusive_ptr_release( const ThunkImpl<X>* p );
|
Chris@102
|
89 };
|
Chris@102
|
90
|
Chris@102
|
91 template <class T>
|
Chris@102
|
92 void intrusive_ptr_add_ref( const ThunkImpl<T>* p ) {
|
Chris@102
|
93 ++ (p->refC);
|
Chris@102
|
94 }
|
Chris@102
|
95 template <class T>
|
Chris@102
|
96 void intrusive_ptr_release( const ThunkImpl<T>* p ) {
|
Chris@102
|
97 if( !--(p->refC) ) delete p;
|
Chris@102
|
98 }
|
Chris@102
|
99
|
Chris@102
|
100 //////////////////////////////////////////////////////////////////////
|
Chris@102
|
101 // reuser1 is needed in list<T> operations
|
Chris@102
|
102 //////////////////////////////////////////////////////////////////////
|
Chris@102
|
103
|
Chris@102
|
104 template <class V1, class V2, class F, class X>
|
Chris@102
|
105 struct reuser1;
|
Chris@102
|
106
|
Chris@102
|
107 template <class V1, class V2, class F, class X, class R>
|
Chris@102
|
108 struct Thunk1 : public ThunkImpl<R> {
|
Chris@102
|
109 mutable F f;
|
Chris@102
|
110 mutable X x;
|
Chris@102
|
111 Thunk1( const F& ff, const X& xx ) : f(ff), x(xx) {}
|
Chris@102
|
112 void init( const F& ff, const X& xx ) const {
|
Chris@102
|
113 Maybe_Var_Inv<V1,F>::remake( f, ff );
|
Chris@102
|
114 Maybe_Var_Inv<V2,X>::remake( x, xx );
|
Chris@102
|
115 }
|
Chris@102
|
116 R operator()() const {
|
Chris@102
|
117 return Maybe_Var_Inv<V1,F>::clone(f)(
|
Chris@102
|
118 Maybe_Var_Inv<V2,X>::clone(x),
|
Chris@102
|
119 reuser1<V1,V2,F,X>(this) );
|
Chris@102
|
120 }
|
Chris@102
|
121 };
|
Chris@102
|
122
|
Chris@102
|
123 template <class V1, class V2, class F, class X>
|
Chris@102
|
124 struct reuser1 {
|
Chris@102
|
125 typedef typename F::template result<F(X)>::type R;
|
Chris@102
|
126 typedef typename boost::phoenix::function<R> fun0_type;
|
Chris@102
|
127 typedef Thunk1<V1,V2,F,X,R> M;
|
Chris@102
|
128 typedef M result_type;
|
Chris@102
|
129 boost::intrusive_ptr<const M> ref;
|
Chris@102
|
130 reuser1(a_unique_type_for_nil) {}
|
Chris@102
|
131 reuser1(const M* m) : ref(m) {}
|
Chris@102
|
132 M operator()( const F& f, const X& x ) {
|
Chris@102
|
133 if( !ref ) ref = boost::intrusive_ptr<const M>( new M(f,x) );
|
Chris@102
|
134 else ref->init(f,x);
|
Chris@102
|
135 return *ref;
|
Chris@102
|
136 }
|
Chris@102
|
137 void iter( const F& f, const X& x ) {
|
Chris@102
|
138 if( ref ) ref->init(f,x);
|
Chris@102
|
139 }
|
Chris@102
|
140 };
|
Chris@102
|
141
|
Chris@102
|
142 //////////////////////////////////////////////////////////////////////
|
Chris@102
|
143 // reuser2 is needed in list<T>
|
Chris@102
|
144 //////////////////////////////////////////////////////////////////////
|
Chris@102
|
145
|
Chris@102
|
146 template <class V1, class V2, class V3, class F, class X, class Y>
|
Chris@102
|
147 struct reuser2;
|
Chris@102
|
148
|
Chris@102
|
149 template <class V1, class V2, class V3, class F, class X, class Y, class R>
|
Chris@102
|
150 struct Thunk2 : public ThunkImpl<R> {
|
Chris@102
|
151 mutable F f;
|
Chris@102
|
152 mutable X x;
|
Chris@102
|
153 mutable Y y;
|
Chris@102
|
154 Thunk2( const F& ff, const X& xx, const Y& yy ) : f(ff), x(xx), y(yy) {}
|
Chris@102
|
155 void init( const F& ff, const X& xx, const Y& yy ) const {
|
Chris@102
|
156 Maybe_Var_Inv<V1,F>::remake( f, ff );
|
Chris@102
|
157 Maybe_Var_Inv<V2,X>::remake( x, xx );
|
Chris@102
|
158 Maybe_Var_Inv<V3,Y>::remake( y, yy );
|
Chris@102
|
159 }
|
Chris@102
|
160 R operator()() const {
|
Chris@102
|
161 return Maybe_Var_Inv<V1,F>::clone(f)(
|
Chris@102
|
162 Maybe_Var_Inv<V2,X>::clone(x),
|
Chris@102
|
163 Maybe_Var_Inv<V3,Y>::clone(y),
|
Chris@102
|
164 reuser2<V1,V2,V3,F,X,Y>(this) );
|
Chris@102
|
165 }
|
Chris@102
|
166 };
|
Chris@102
|
167
|
Chris@102
|
168 template <class V1, class V2, class V3, class F, class X, class Y>
|
Chris@102
|
169 struct reuser2 {
|
Chris@102
|
170 typedef typename F::template result<F(X,Y)>::type R;
|
Chris@102
|
171 typedef Thunk2<V1,V2,V3,F,X,Y,R> M;
|
Chris@102
|
172 typedef M result_type;
|
Chris@102
|
173 boost::intrusive_ptr<const M> ref;
|
Chris@102
|
174 reuser2(a_unique_type_for_nil) {}
|
Chris@102
|
175 reuser2(const M* m) : ref(m) {}
|
Chris@102
|
176 M operator()( const F& f, const X& x, const Y& y ) {
|
Chris@102
|
177 if( !ref ) ref = boost::intrusive_ptr<const M>( new M(f,x,y) );
|
Chris@102
|
178 else ref->init(f,x,y);
|
Chris@102
|
179 return *ref;
|
Chris@102
|
180 }
|
Chris@102
|
181 void iter( const F& f, const X& x, const Y& y ) {
|
Chris@102
|
182 if( ref ) ref->init(f,x,y);
|
Chris@102
|
183 }
|
Chris@102
|
184 };
|
Chris@102
|
185
|
Chris@102
|
186 //////////////////////////////////////////////////////////////////////
|
Chris@102
|
187 // reuser3
|
Chris@102
|
188 //////////////////////////////////////////////////////////////////////
|
Chris@102
|
189
|
Chris@102
|
190 template <class V1, class V2, class V3, class V4,
|
Chris@102
|
191 class F, class X, class Y, class Z>
|
Chris@102
|
192 struct reuser3;
|
Chris@102
|
193
|
Chris@102
|
194 template <class V1, class V2, class V3, class V4,
|
Chris@102
|
195 class F, class X, class Y, class Z, class R>
|
Chris@102
|
196 struct Thunk3 : public ThunkImpl<R> {
|
Chris@102
|
197 mutable F f;
|
Chris@102
|
198 mutable X x;
|
Chris@102
|
199 mutable Y y;
|
Chris@102
|
200 mutable Z z;
|
Chris@102
|
201 Thunk3( const F& ff, const X& xx, const Y& yy, const Z& zz )
|
Chris@102
|
202 : f(ff), x(xx), y(yy), z(zz) {}
|
Chris@102
|
203 void init( const F& ff, const X& xx, const Y& yy, const Z& zz ) const {
|
Chris@102
|
204 Maybe_Var_Inv<V1,F>::remake( f, ff );
|
Chris@102
|
205 Maybe_Var_Inv<V2,X>::remake( x, xx );
|
Chris@102
|
206 Maybe_Var_Inv<V3,Y>::remake( y, yy );
|
Chris@102
|
207 Maybe_Var_Inv<V4,Z>::remake( z, zz );
|
Chris@102
|
208 }
|
Chris@102
|
209 R operator()() const {
|
Chris@102
|
210 return Maybe_Var_Inv<V1,F>::clone(f)(
|
Chris@102
|
211 Maybe_Var_Inv<V2,X>::clone(x),
|
Chris@102
|
212 Maybe_Var_Inv<V3,Y>::clone(y),
|
Chris@102
|
213 Maybe_Var_Inv<V4,Z>::clone(z),
|
Chris@102
|
214 reuser3<V1,V2,V3,V4,F,X,Y,Z>(this) );
|
Chris@102
|
215 }
|
Chris@102
|
216 };
|
Chris@102
|
217
|
Chris@102
|
218 template <class V1, class V2, class V3, class V4,
|
Chris@102
|
219 class F, class X, class Y, class Z>
|
Chris@102
|
220 struct reuser3 {
|
Chris@102
|
221 typedef typename F::template result<F(X,Y,Z)>::type R;
|
Chris@102
|
222 typedef Thunk3<V1,V2,V3,V4,F,X,Y,Z,R> M;
|
Chris@102
|
223 typedef M result_type;
|
Chris@102
|
224 boost::intrusive_ptr<const M> ref;
|
Chris@102
|
225 reuser3(a_unique_type_for_nil) {}
|
Chris@102
|
226 reuser3(const M* m) : ref(m) {}
|
Chris@102
|
227 M operator()( const F& f, const X& x, const Y& y, const Z& z ) {
|
Chris@102
|
228 if( !ref ) ref = boost::intrusive_ptr<const M>( new M(f,x,y,z) );
|
Chris@102
|
229 else ref->init(f,x,y,z);
|
Chris@102
|
230 return *ref;
|
Chris@102
|
231 }
|
Chris@102
|
232 void iter( const F& f, const X& x, const Y& y, const Z& z ) {
|
Chris@102
|
233 if( ref ) ref->init(f,x,y,z);
|
Chris@102
|
234 }
|
Chris@102
|
235 };
|
Chris@102
|
236
|
Chris@102
|
237 }
|
Chris@102
|
238
|
Chris@102
|
239 }
|
Chris@102
|
240 }
|
Chris@102
|
241
|
Chris@102
|
242 #endif
|