1 /*============================================================================= 2 Adaptable closures 3 4 Phoenix V0.9 5 Copyright (c) 2001-2002 Joel de Guzman 6 7 Distributed under the Boost Software License, Version 1.0. (See 8 accompanying file LICENSE_1_0.txt or copy at 9 http://www.boost.org/LICENSE_1_0.txt) 10 11 URL: http://spirit.sourceforge.net/ 12 13 ==============================================================================*/ 14 #ifndef PHOENIX_CLOSURES_HPP 15 #define PHOENIX_CLOSURES_HPP 16 17 /////////////////////////////////////////////////////////////////////////////// 18 #include "boost/lambda/core.hpp" 19 /////////////////////////////////////////////////////////////////////////////// 20 namespace boost { 21 namespace lambda { 22 23 /////////////////////////////////////////////////////////////////////////////// 24 // 25 // Adaptable closures 26 // 27 // The framework will not be complete without some form of closures 28 // support. Closures encapsulate a stack frame where local 29 // variables are created upon entering a function and destructed 30 // upon exiting. Closures provide an environment for local 31 // variables to reside. Closures can hold heterogeneous types. 32 // 33 // Phoenix closures are true hardware stack based closures. At the 34 // very least, closures enable true reentrancy in lambda functions. 35 // A closure provides access to a function stack frame where local 36 // variables reside. Modeled after Pascal nested stack frames, 37 // closures can be nested just like nested functions where code in 38 // inner closures may access local variables from in-scope outer 39 // closures (accessing inner scopes from outer scopes is an error 40 // and will cause a run-time assertion failure). 41 // 42 // There are three (3) interacting classes: 43 // 44 // 1) closure: 45 // 46 // At the point of declaration, a closure does not yet create a 47 // stack frame nor instantiate any variables. A closure declaration 48 // declares the types and names[note] of the local variables. The 49 // closure class is meant to be subclassed. It is the 50 // responsibility of a closure subclass to supply the names for 51 // each of the local variable in the closure. Example: 52 // 53 // struct my_closure : closure<int, string, double> { 54 // 55 // member1 num; // names the 1st (int) local variable 56 // member2 message; // names the 2nd (string) local variable 57 // member3 real; // names the 3rd (double) local variable 58 // }; 59 // 60 // my_closure clos; 61 // 62 // Now that we have a closure 'clos', its local variables can be 63 // accessed lazily using the dot notation. Each qualified local 64 // variable can be used just like any primitive actor (see 65 // primitives.hpp). Examples: 66 // 67 // clos.num = 30 68 // clos.message = arg1 69 // clos.real = clos.num * 1e6 70 // 71 // The examples above are lazily evaluated. As usual, these 72 // expressions return composite actors that will be evaluated 73 // through a second function call invocation (see operators.hpp). 74 // Each of the members (clos.xxx) is an actor. As such, applying 75 // the operator() will reveal its identity: 76 // 77 // clos.num() // will return the current value of clos.num 78 // 79 // *** [note] Acknowledgement: Juan Carlos Arevalo-Baeza (JCAB) 80 // introduced and initilally implemented the closure member names 81 // that uses the dot notation. 82 // 83 // 2) closure_member 84 // 85 // The named local variables of closure 'clos' above are actually 86 // closure members. The closure_member class is an actor and 87 // conforms to its conceptual interface. member1..memberN are 88 // predefined typedefs that correspond to each of the listed types 89 // in the closure template parameters. 90 // 91 // 3) closure_frame 92 // 93 // When a closure member is finally evaluated, it should refer to 94 // an actual instance of the variable in the hardware stack. 95 // Without doing so, the process is not complete and the evaluated 96 // member will result to an assertion failure. Remember that the 97 // closure is just a declaration. The local variables that a 98 // closure refers to must still be instantiated. 99 // 100 // The closure_frame class does the actual instantiation of the 101 // local variables and links these variables with the closure and 102 // all its members. There can be multiple instances of 103 // closure_frames typically situated in the stack inside a 104 // function. Each closure_frame instance initiates a stack frame 105 // with a new set of closure local variables. Example: 106 // 107 // void foo() 108 // { 109 // closure_frame<my_closure> frame(clos); 110 // /* do something */ 111 // } 112 // 113 // where 'clos' is an instance of our closure 'my_closure' above. 114 // Take note that the usage above precludes locally declared 115 // classes. If my_closure is a locally declared type, we can still 116 // use its self_type as a paramater to closure_frame: 117 // 118 // closure_frame<my_closure::self_type> frame(clos); 119 // 120 // Upon instantiation, the closure_frame links the local variables 121 // to the closure. The previous link to another closure_frame 122 // instance created before is saved. Upon destruction, the 123 // closure_frame unlinks itself from the closure and relinks the 124 // preceding closure_frame prior to this instance. 125 // 126 // The local variables in the closure 'clos' above is default 127 // constructed in the stack inside function 'foo'. Once 'foo' is 128 // exited, all of these local variables are destructed. In some 129 // cases, default construction is not desirable and we need to 130 // initialize the local closure variables with some values. This 131 // can be done by passing in the initializers in a compatible 132 // tuple. A compatible tuple is one with the same number of 133 // elements as the destination and where each element from the 134 // destination can be constructed from each corresponding element 135 // in the source. Example: 136 // 137 // tuple<int, char const*, int> init(123, "Hello", 1000); 138 // closure_frame<my_closure> frame(clos, init); 139 // 140 // Here now, our closure_frame's variables are initialized with 141 // int: 123, char const*: "Hello" and int: 1000. 142 // 143 /////////////////////////////////////////////////////////////////////////////// 144 145 146 147 /////////////////////////////////////////////////////////////////////////////// 148 // 149 // closure_frame class 150 // 151 /////////////////////////////////////////////////////////////////////////////// 152 template <typename ClosureT> 153 class closure_frame : public ClosureT::tuple_t { 154 155 public: 156 closure_frame(ClosureT & clos)157 closure_frame(ClosureT& clos) 158 : ClosureT::tuple_t(), save(clos.frame), frame(clos.frame) 159 { clos.frame = this; } 160 161 template <typename TupleT> closure_frame(ClosureT & clos,TupleT const & init)162 closure_frame(ClosureT& clos, TupleT const& init) 163 : ClosureT::tuple_t(init), save(clos.frame), frame(clos.frame) 164 { clos.frame = this; } 165 ~closure_frame()166 ~closure_frame() 167 { frame = save; } 168 169 private: 170 171 closure_frame(closure_frame const&); // no copy 172 closure_frame& operator=(closure_frame const&); // no assign 173 174 closure_frame* save; 175 closure_frame*& frame; 176 }; 177 178 /////////////////////////////////////////////////////////////////////////////// 179 // 180 // closure_member class 181 // 182 /////////////////////////////////////////////////////////////////////////////// 183 template <int N, typename ClosureT> 184 class closure_member { 185 186 public: 187 188 typedef typename ClosureT::tuple_t tuple_t; 189 closure_member()190 closure_member() 191 : frame(ClosureT::closure_frame_ref()) {} 192 193 template <typename TupleT> 194 struct sig { 195 196 typedef typename detail::tuple_element_as_reference< 197 N, typename ClosureT::tuple_t 198 >::type type; 199 }; 200 201 template <class Ret, class A, class B, class C> 202 // typename detail::tuple_element_as_reference 203 // <N, typename ClosureT::tuple_t>::type 204 Ret 205 call(A&, B&, C&) const 206 { 207 assert(frame); 208 return boost::tuples::get<N>(*frame); 209 } 210 211 212 private: 213 214 typename ClosureT::closure_frame_t*& frame; 215 }; 216 217 /////////////////////////////////////////////////////////////////////////////// 218 // 219 // closure class 220 // 221 /////////////////////////////////////////////////////////////////////////////// 222 template < 223 typename T0 = null_type, 224 typename T1 = null_type, 225 typename T2 = null_type, 226 typename T3 = null_type, 227 typename T4 = null_type 228 > 229 class closure { 230 231 public: 232 233 typedef tuple<T0, T1, T2, T3, T4> tuple_t; 234 typedef closure<T0, T1, T2, T3, T4> self_t; 235 typedef closure_frame<self_t> closure_frame_t; 236 closure()237 closure() 238 : frame(0) { closure_frame_ref(&frame); } context()239 closure_frame_t& context() { assert(frame); return frame; } context() const240 closure_frame_t const& context() const { assert(frame); return frame; } 241 242 typedef lambda_functor<closure_member<0, self_t> > member1; 243 typedef lambda_functor<closure_member<1, self_t> > member2; 244 typedef lambda_functor<closure_member<2, self_t> > member3; 245 typedef lambda_functor<closure_member<3, self_t> > member4; 246 typedef lambda_functor<closure_member<4, self_t> > member5; 247 248 private: 249 250 closure(closure const&); // no copy 251 closure& operator=(closure const&); // no assign 252 253 template <int N, typename ClosureT> 254 friend class closure_member; 255 256 template <typename ClosureT> 257 friend class closure_frame; 258 259 static closure_frame_t*& closure_frame_ref(closure_frame_t ** frame_=0)260 closure_frame_ref(closure_frame_t** frame_ = 0) 261 { 262 static closure_frame_t** frame = 0; 263 if (frame_ != 0) 264 frame = frame_; 265 return *frame; 266 } 267 268 closure_frame_t* frame; 269 }; 270 271 }} 272 // namespace 273 274 #endif 275