lazy_reuse.hpp 9.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296
  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. Distributed under the Boost Software License, Version 1.0. (See accompanying
  28. file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
  29. ==============================================================================*/
  30. #ifndef BOOST_PHOENIX_FUNCTION_LAZY_REUSE
  31. #define BOOST_PHOENIX_FUNCTION_LAZY_REUSE
  32. #include <boost/phoenix/core.hpp>
  33. #include <boost/phoenix/function.hpp>
  34. #include <boost/intrusive_ptr.hpp>
  35. namespace boost {
  36. namespace phoenix {
  37. namespace fcpp {
  38. //////////////////////////////////////////////////////////////////////
  39. // Original FC++ comment:
  40. // "Reuser"s are effectively special-purpose versions of curry() that
  41. // enable recursive list functoids to reuse the thunk of the curried
  42. // recursive call. See
  43. // http://www.cc.gatech.edu/~yannis/fc++/New/reusers.html
  44. // for a more detailed description.
  45. //////////////////////////////////////////////////////////////////////
  46. // For efficiency, we mark parameters as either "VAR"iant or "INV"ariant.
  47. struct INV {};
  48. struct VAR {};
  49. template <class V, class X> struct Maybe_Var_Inv;
  50. template <class X>
  51. struct Maybe_Var_Inv<VAR,X> {
  52. static void remake( X& x, const X& val ) {
  53. x.~X();
  54. new (&x) X(val);
  55. }
  56. static X clone( const X& x ) { return X(x); }
  57. };
  58. template <class X>
  59. struct Maybe_Var_Inv<INV,X> {
  60. static void remake( X&, const X& ) {}
  61. static const X& clone( const X& x ) { return x; }
  62. };
  63. /////////////////////////////////////////////////////////////////////
  64. // ThunkImpl is an implementation of Fun0Impl for this use.
  65. /////////////////////////////////////////////////////////////////////
  66. template <class Result>
  67. class ThunkImpl
  68. {
  69. mutable RefCountType refC;
  70. public:
  71. ThunkImpl() : refC(0) {}
  72. virtual Result operator()() const =0;
  73. virtual ~ThunkImpl() {}
  74. template <class X>
  75. friend void intrusive_ptr_add_ref( const ThunkImpl<X>* p );
  76. template <class X>
  77. friend void intrusive_ptr_release( const ThunkImpl<X>* p );
  78. };
  79. template <class T>
  80. void intrusive_ptr_add_ref( const ThunkImpl<T>* p ) {
  81. ++ (p->refC);
  82. }
  83. template <class T>
  84. void intrusive_ptr_release( const ThunkImpl<T>* p ) {
  85. if( !--(p->refC) ) delete p;
  86. }
  87. //////////////////////////////////////////////////////////////////////
  88. // reuser1 is needed in list<T> operations
  89. //////////////////////////////////////////////////////////////////////
  90. template <class V1, class V2, class F, class X>
  91. struct reuser1;
  92. template <class V1, class V2, class F, class X, class R>
  93. struct Thunk1 : public ThunkImpl<R> {
  94. mutable F f;
  95. mutable X x;
  96. Thunk1( const F& ff, const X& xx ) : f(ff), x(xx) {}
  97. void init( const F& ff, const X& xx ) const {
  98. Maybe_Var_Inv<V1,F>::remake( f, ff );
  99. Maybe_Var_Inv<V2,X>::remake( x, xx );
  100. }
  101. R operator()() const {
  102. return Maybe_Var_Inv<V1,F>::clone(f)(
  103. Maybe_Var_Inv<V2,X>::clone(x),
  104. reuser1<V1,V2,F,X>(this) );
  105. }
  106. };
  107. template <class V1, class V2, class F, class X>
  108. struct reuser1 {
  109. typedef typename F::template result<F(X)>::type R;
  110. typedef typename boost::phoenix::function<R> fun0_type;
  111. typedef Thunk1<V1,V2,F,X,R> M;
  112. typedef M result_type;
  113. boost::intrusive_ptr<const M> ref;
  114. reuser1(a_unique_type_for_nil) {}
  115. reuser1(const M* m) : ref(m) {}
  116. M operator()( const F& f, const X& x ) {
  117. if( !ref ) ref = boost::intrusive_ptr<const M>( new M(f,x) );
  118. else ref->init(f,x);
  119. return *ref;
  120. }
  121. void iter( const F& f, const X& x ) {
  122. if( ref ) ref->init(f,x);
  123. }
  124. };
  125. //////////////////////////////////////////////////////////////////////
  126. // reuser2 is needed in list<T>
  127. //////////////////////////////////////////////////////////////////////
  128. template <class V1, class V2, class V3, class F, class X, class Y>
  129. struct reuser2;
  130. template <class V1, class V2, class V3, class F, class X, class Y, class R>
  131. struct Thunk2 : public ThunkImpl<R> {
  132. mutable F f;
  133. mutable X x;
  134. mutable Y y;
  135. Thunk2( const F& ff, const X& xx, const Y& yy ) : f(ff), x(xx), y(yy) {}
  136. void init( const F& ff, const X& xx, const Y& yy ) const {
  137. Maybe_Var_Inv<V1,F>::remake( f, ff );
  138. Maybe_Var_Inv<V2,X>::remake( x, xx );
  139. Maybe_Var_Inv<V3,Y>::remake( y, yy );
  140. }
  141. R operator()() const {
  142. return Maybe_Var_Inv<V1,F>::clone(f)(
  143. Maybe_Var_Inv<V2,X>::clone(x),
  144. Maybe_Var_Inv<V3,Y>::clone(y),
  145. reuser2<V1,V2,V3,F,X,Y>(this) );
  146. }
  147. };
  148. template <class V1, class V2, class V3, class F, class X, class Y>
  149. struct reuser2 {
  150. typedef typename F::template result<F(X,Y)>::type R;
  151. typedef Thunk2<V1,V2,V3,F,X,Y,R> M;
  152. typedef M result_type;
  153. boost::intrusive_ptr<const M> ref;
  154. reuser2(a_unique_type_for_nil) {}
  155. reuser2(const M* m) : ref(m) {}
  156. M operator()( const F& f, const X& x, const Y& y ) {
  157. if( !ref ) ref = boost::intrusive_ptr<const M>( new M(f,x,y) );
  158. else ref->init(f,x,y);
  159. return *ref;
  160. }
  161. void iter( const F& f, const X& x, const Y& y ) {
  162. if( ref ) ref->init(f,x,y);
  163. }
  164. };
  165. //////////////////////////////////////////////////////////////////////
  166. // reuser3
  167. //////////////////////////////////////////////////////////////////////
  168. template <class V1, class V2, class V3, class V4,
  169. class F, class X, class Y, class Z>
  170. struct reuser3;
  171. template <class V1, class V2, class V3, class V4,
  172. class F, class X, class Y, class Z, class R>
  173. struct Thunk3 : public ThunkImpl<R> {
  174. mutable F f;
  175. mutable X x;
  176. mutable Y y;
  177. mutable Z z;
  178. Thunk3( const F& ff, const X& xx, const Y& yy, const Z& zz )
  179. : f(ff), x(xx), y(yy), z(zz) {}
  180. void init( const F& ff, const X& xx, const Y& yy, const Z& zz ) const {
  181. Maybe_Var_Inv<V1,F>::remake( f, ff );
  182. Maybe_Var_Inv<V2,X>::remake( x, xx );
  183. Maybe_Var_Inv<V3,Y>::remake( y, yy );
  184. Maybe_Var_Inv<V4,Z>::remake( z, zz );
  185. }
  186. R operator()() const {
  187. return Maybe_Var_Inv<V1,F>::clone(f)(
  188. Maybe_Var_Inv<V2,X>::clone(x),
  189. Maybe_Var_Inv<V3,Y>::clone(y),
  190. Maybe_Var_Inv<V4,Z>::clone(z),
  191. reuser3<V1,V2,V3,V4,F,X,Y,Z>(this) );
  192. }
  193. };
  194. template <class V1, class V2, class V3, class V4,
  195. class F, class X, class Y, class Z>
  196. struct reuser3 {
  197. typedef typename F::template result<F(X,Y,Z)>::type R;
  198. typedef Thunk3<V1,V2,V3,V4,F,X,Y,Z,R> M;
  199. typedef M result_type;
  200. boost::intrusive_ptr<const M> ref;
  201. reuser3(a_unique_type_for_nil) {}
  202. reuser3(const M* m) : ref(m) {}
  203. M operator()( const F& f, const X& x, const Y& y, const Z& z ) {
  204. if( !ref ) ref = boost::intrusive_ptr<const M>( new M(f,x,y,z) );
  205. else ref->init(f,x,y,z);
  206. return *ref;
  207. }
  208. void iter( const F& f, const X& x, const Y& y, const Z& z ) {
  209. if( ref ) ref->init(f,x,y,z);
  210. }
  211. };
  212. //////////////////////////////////////////////////////////////////////
  213. // reuser4
  214. //////////////////////////////////////////////////////////////////////
  215. template <class V1, class V2, class V3, class V4, class V5,
  216. class F, class W, class X, class Y, class Z>
  217. struct reuser4;
  218. template <class V1, class V2, class V3, class V4, class V5,
  219. class F, class W, class X, class Y, class Z, class R>
  220. struct Thunk4 : public ThunkImpl<R> {
  221. mutable F f;
  222. mutable W w;
  223. mutable X x;
  224. mutable Y y;
  225. mutable Z z;
  226. Thunk4( const F& ff, const W& ww, const X& xx, const Y& yy, const Z& zz )
  227. : f(ff), w(ww), x(xx), y(yy), z(zz) {}
  228. void init( const F& ff, const W& ww, const X& xx, const Y& yy, const Z& zz ) const {
  229. Maybe_Var_Inv<V1,F>::remake( f, ff );
  230. Maybe_Var_Inv<V2,W>::remake( w, ww );
  231. Maybe_Var_Inv<V3,X>::remake( x, xx );
  232. Maybe_Var_Inv<V4,Y>::remake( y, yy );
  233. Maybe_Var_Inv<V5,Z>::remake( z, zz );
  234. }
  235. R operator()() const {
  236. return Maybe_Var_Inv<V1,F>::clone(f)(
  237. Maybe_Var_Inv<V2,W>::clone(w),
  238. Maybe_Var_Inv<V3,X>::clone(x),
  239. Maybe_Var_Inv<V4,Y>::clone(y),
  240. Maybe_Var_Inv<V5,Z>::clone(z),
  241. reuser4<V1,V2,V3,V4,V5,F,W,X,Y,Z>(this) );
  242. }
  243. };
  244. template <class V1, class V2, class V3, class V4, class V5,
  245. class F, class W, class X, class Y, class Z>
  246. struct reuser4 {
  247. typedef typename F::template result<F(W,X,Y,Z)>::type R;
  248. typedef Thunk4<V1,V2,V3,V4,V5,F,W,X,Y,Z,R> M;
  249. typedef M result_type;
  250. boost::intrusive_ptr<const M> ref;
  251. reuser4(a_unique_type_for_nil) {}
  252. reuser4(const M* m) : ref(m) {}
  253. M operator()( const F& f, const W& w, const X& x, const Y& y, const Z& z ) {
  254. if( !ref ) ref = boost::intrusive_ptr<const M>( new M(f,w,x,y,z) );
  255. else ref->init(f,w,x,y,z);
  256. return *ref;
  257. }
  258. void iter( const F& f, const W& w, const X& x, const Y& y, const Z& z ) {
  259. if( ref ) ref->init(f,w,x,y,z);
  260. }
  261. };
  262. }
  263. }
  264. }
  265. #endif