1 /*============================================================================= 2 Phoenix V1.2.1 3 Copyright (c) 2001-2002 Joel de Guzman 4 MT code Copyright (c) 2002-2003 Martin Wille 5 6 Distributed under the Boost Software License, Version 1.0. (See accompanying 7 file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) 8 ==============================================================================*/ 9 #ifndef BOOST_SPIRIT_CLASSIC_PHOENIX_CLOSURES_HPP 10 #define BOOST_SPIRIT_CLASSIC_PHOENIX_CLOSURES_HPP 11 12 /////////////////////////////////////////////////////////////////////////////// 13 #include <boost/spirit/home/classic/phoenix/actor.hpp> 14 #include <boost/assert.hpp> 15 16 #ifdef PHOENIX_THREADSAFE 17 #include <boost/thread/tss.hpp> 18 #include <boost/thread/once.hpp> 19 #endif 20 21 /////////////////////////////////////////////////////////////////////////////// 22 namespace phoenix { 23 24 #if BOOST_WORKAROUND(BOOST_MSVC, >= 1400) 25 #pragma warning(push) 26 #pragma warning(disable:4512) //assignment operator could not be generated 27 #endif 28 29 /////////////////////////////////////////////////////////////////////////////// 30 // 31 // Adaptable closures 32 // 33 // The framework will not be complete without some form of closures 34 // support. Closures encapsulate a stack frame where local 35 // variables are created upon entering a function and destructed 36 // upon exiting. Closures provide an environment for local 37 // variables to reside. Closures can hold heterogeneous types. 38 // 39 // Phoenix closures are true hardware stack based closures. At the 40 // very least, closures enable true reentrancy in lambda functions. 41 // A closure provides access to a function stack frame where local 42 // variables reside. Modeled after Pascal nested stack frames, 43 // closures can be nested just like nested functions where code in 44 // inner closures may access local variables from in-scope outer 45 // closures (accessing inner scopes from outer scopes is an error 46 // and will cause a run-time assertion failure). 47 // 48 // There are three (3) interacting classes: 49 // 50 // 1) closure: 51 // 52 // At the point of declaration, a closure does not yet create a 53 // stack frame nor instantiate any variables. A closure declaration 54 // declares the types and names[note] of the local variables. The 55 // closure class is meant to be subclassed. It is the 56 // responsibility of a closure subclass to supply the names for 57 // each of the local variable in the closure. Example: 58 // 59 // struct my_closure : closure<int, string, double> { 60 // 61 // member1 num; // names the 1st (int) local variable 62 // member2 message; // names the 2nd (string) local variable 63 // member3 real; // names the 3rd (double) local variable 64 // }; 65 // 66 // my_closure clos; 67 // 68 // Now that we have a closure 'clos', its local variables can be 69 // accessed lazily using the dot notation. Each qualified local 70 // variable can be used just like any primitive actor (see 71 // primitives.hpp). Examples: 72 // 73 // clos.num = 30 74 // clos.message = arg1 75 // clos.real = clos.num * 1e6 76 // 77 // The examples above are lazily evaluated. As usual, these 78 // expressions return composite actors that will be evaluated 79 // through a second function call invocation (see operators.hpp). 80 // Each of the members (clos.xxx) is an actor. As such, applying 81 // the operator() will reveal its identity: 82 // 83 // clos.num() // will return the current value of clos.num 84 // 85 // *** [note] Acknowledgement: Juan Carlos Arevalo-Baeza (JCAB) 86 // introduced and initilally implemented the closure member names 87 // that uses the dot notation. 88 // 89 // 2) closure_member 90 // 91 // The named local variables of closure 'clos' above are actually 92 // closure members. The closure_member class is an actor and 93 // conforms to its conceptual interface. member1..memberN are 94 // predefined typedefs that correspond to each of the listed types 95 // in the closure template parameters. 96 // 97 // 3) closure_frame 98 // 99 // When a closure member is finally evaluated, it should refer to 100 // an actual instance of the variable in the hardware stack. 101 // Without doing so, the process is not complete and the evaluated 102 // member will result to an assertion failure. Remember that the 103 // closure is just a declaration. The local variables that a 104 // closure refers to must still be instantiated. 105 // 106 // The closure_frame class does the actual instantiation of the 107 // local variables and links these variables with the closure and 108 // all its members. There can be multiple instances of 109 // closure_frames typically situated in the stack inside a 110 // function. Each closure_frame instance initiates a stack frame 111 // with a new set of closure local variables. Example: 112 // 113 // void foo() 114 // { 115 // closure_frame<my_closure> frame(clos); 116 // /* do something */ 117 // } 118 // 119 // where 'clos' is an instance of our closure 'my_closure' above. 120 // Take note that the usage above precludes locally declared 121 // classes. If my_closure is a locally declared type, we can still 122 // use its self_type as a parameter to closure_frame: 123 // 124 // closure_frame<my_closure::self_type> frame(clos); 125 // 126 // Upon instantiation, the closure_frame links the local variables 127 // to the closure. The previous link to another closure_frame 128 // instance created before is saved. Upon destruction, the 129 // closure_frame unlinks itself from the closure and relinks the 130 // preceding closure_frame prior to this instance. 131 // 132 // The local variables in the closure 'clos' above is default 133 // constructed in the stack inside function 'foo'. Once 'foo' is 134 // exited, all of these local variables are destructed. In some 135 // cases, default construction is not desirable and we need to 136 // initialize the local closure variables with some values. This 137 // can be done by passing in the initializers in a compatible 138 // tuple. A compatible tuple is one with the same number of 139 // elements as the destination and where each element from the 140 // destination can be constructed from each corresponding element 141 // in the source. Example: 142 // 143 // tuple<int, char const*, int> init(123, "Hello", 1000); 144 // closure_frame<my_closure> frame(clos, init); 145 // 146 // Here now, our closure_frame's variables are initialized with 147 // int: 123, char const*: "Hello" and int: 1000. 148 // 149 /////////////////////////////////////////////////////////////////////////////// 150 151 namespace impl 152 { 153 /////////////////////////////////////////////////////////////////////// 154 // closure_frame_holder is a simple class that encapsulates the 155 // storage for a frame pointer. It uses thread specific data in 156 // case when multithreading is enabled, an ordinary pointer otherwise 157 // 158 // it has get() and set() member functions. set() has to be used 159 // _after_ get(). get() contains intialisation code in the multi 160 // threading case 161 // 162 // closure_frame_holder is used by the closure<> class to store 163 // the pointer to the current frame. 164 // 165 #ifndef PHOENIX_THREADSAFE 166 template <typename FrameT> 167 struct closure_frame_holder 168 { 169 typedef FrameT frame_t; 170 typedef frame_t *frame_ptr; 171 closure_frame_holderphoenix::impl::closure_frame_holder172 closure_frame_holder() : frame(0) {} 173 getphoenix::impl::closure_frame_holder174 frame_ptr &get() { return frame; } setphoenix::impl::closure_frame_holder175 void set(frame_t *f) { frame = f; } 176 177 private: 178 frame_ptr frame; 179 180 // no copies, no assignments 181 closure_frame_holder(closure_frame_holder const &); 182 closure_frame_holder &operator=(closure_frame_holder const &); 183 }; 184 #else 185 template <typename FrameT> 186 struct closure_frame_holder 187 { 188 typedef FrameT frame_t; 189 typedef frame_t *frame_ptr; 190 191 closure_frame_holder() : tsp_frame() {} 192 193 frame_ptr &get() 194 { 195 if (!tsp_frame.get()) 196 tsp_frame.reset(new frame_ptr(0)); 197 return *tsp_frame; 198 } 199 void set(frame_ptr f) 200 { 201 *tsp_frame = f; 202 } 203 204 private: 205 boost::thread_specific_ptr<frame_ptr> tsp_frame; 206 207 // no copies, no assignments 208 closure_frame_holder(closure_frame_holder const &); 209 closure_frame_holder &operator=(closure_frame_holder const &); 210 }; 211 #endif 212 } // namespace phoenix::impl 213 214 /////////////////////////////////////////////////////////////////////////////// 215 // 216 // closure_frame class 217 // 218 /////////////////////////////////////////////////////////////////////////////// 219 template <typename ClosureT> 220 class closure_frame : public ClosureT::tuple_t { 221 222 public: 223 closure_frame(ClosureT const & clos)224 closure_frame(ClosureT const& clos) 225 : ClosureT::tuple_t(), save(clos.frame.get()), frame(clos.frame) 226 { clos.frame.set(this); } 227 228 template <typename TupleT> closure_frame(ClosureT const & clos,TupleT const & init)229 closure_frame(ClosureT const& clos, TupleT const& init) 230 : ClosureT::tuple_t(init), save(clos.frame.get()), frame(clos.frame) 231 { clos.frame.set(this); } 232 ~closure_frame()233 ~closure_frame() 234 { frame.set(save); } 235 236 private: 237 238 closure_frame(closure_frame const&); // no copy 239 closure_frame& operator=(closure_frame const&); // no assign 240 241 closure_frame* save; 242 impl::closure_frame_holder<closure_frame>& frame; 243 }; 244 245 /////////////////////////////////////////////////////////////////////////////// 246 // 247 // closure_member class 248 // 249 /////////////////////////////////////////////////////////////////////////////// 250 template <int N, typename ClosureT> 251 class closure_member { 252 253 public: 254 255 typedef typename ClosureT::tuple_t tuple_t; 256 closure_member()257 closure_member() 258 : frame(ClosureT::closure_frame_holder_ref()) {} 259 260 template <typename TupleT> 261 struct result { 262 263 typedef typename tuple_element< 264 N, typename ClosureT::tuple_t 265 >::rtype type; 266 }; 267 268 template <typename TupleT> 269 typename tuple_element<N, typename ClosureT::tuple_t>::rtype eval(TupleT const &) const270 eval(TupleT const& /*args*/) const 271 { 272 using namespace std; 273 BOOST_ASSERT(frame.get() != 0); 274 return (*frame.get())[tuple_index<N>()]; 275 } 276 277 private: 278 impl::closure_frame_holder<typename ClosureT::closure_frame_t> &frame; 279 }; 280 281 /////////////////////////////////////////////////////////////////////////////// 282 // 283 // closure class 284 // 285 /////////////////////////////////////////////////////////////////////////////// 286 template < 287 typename T0 = nil_t 288 , typename T1 = nil_t 289 , typename T2 = nil_t 290 291 #if PHOENIX_LIMIT > 3 292 , typename T3 = nil_t 293 , typename T4 = nil_t 294 , typename T5 = nil_t 295 296 #if PHOENIX_LIMIT > 6 297 , typename T6 = nil_t 298 , typename T7 = nil_t 299 , typename T8 = nil_t 300 301 #if PHOENIX_LIMIT > 9 302 , typename T9 = nil_t 303 , typename T10 = nil_t 304 , typename T11 = nil_t 305 306 #if PHOENIX_LIMIT > 12 307 , typename T12 = nil_t 308 , typename T13 = nil_t 309 , typename T14 = nil_t 310 311 #endif 312 #endif 313 #endif 314 #endif 315 > 316 class closure { 317 318 public: 319 320 typedef tuple< 321 T0, T1, T2 322 #if PHOENIX_LIMIT > 3 323 , T3, T4, T5 324 #if PHOENIX_LIMIT > 6 325 , T6, T7, T8 326 #if PHOENIX_LIMIT > 9 327 , T9, T10, T11 328 #if PHOENIX_LIMIT > 12 329 , T12, T13, T14 330 #endif 331 #endif 332 #endif 333 #endif 334 > tuple_t; 335 336 typedef closure< 337 T0, T1, T2 338 #if PHOENIX_LIMIT > 3 339 , T3, T4, T5 340 #if PHOENIX_LIMIT > 6 341 , T6, T7, T8 342 #if PHOENIX_LIMIT > 9 343 , T9, T10, T11 344 #if PHOENIX_LIMIT > 12 345 , T12, T13, T14 346 #endif 347 #endif 348 #endif 349 #endif 350 > self_t; 351 352 typedef closure_frame<self_t> closure_frame_t; 353 closure()354 closure() 355 : frame() { closure_frame_holder_ref(&frame); } 356 357 typedef actor<closure_member<0, self_t> > member1; 358 typedef actor<closure_member<1, self_t> > member2; 359 typedef actor<closure_member<2, self_t> > member3; 360 361 #if PHOENIX_LIMIT > 3 362 typedef actor<closure_member<3, self_t> > member4; 363 typedef actor<closure_member<4, self_t> > member5; 364 typedef actor<closure_member<5, self_t> > member6; 365 366 #if PHOENIX_LIMIT > 6 367 typedef actor<closure_member<6, self_t> > member7; 368 typedef actor<closure_member<7, self_t> > member8; 369 typedef actor<closure_member<8, self_t> > member9; 370 371 #if PHOENIX_LIMIT > 9 372 typedef actor<closure_member<9, self_t> > member10; 373 typedef actor<closure_member<10, self_t> > member11; 374 typedef actor<closure_member<11, self_t> > member12; 375 376 #if PHOENIX_LIMIT > 12 377 typedef actor<closure_member<12, self_t> > member13; 378 typedef actor<closure_member<13, self_t> > member14; 379 typedef actor<closure_member<14, self_t> > member15; 380 381 #endif 382 #endif 383 #endif 384 #endif 385 386 #if !defined(__MWERKS__) || (__MWERKS__ > 0x3002) 387 private: 388 #endif 389 390 closure(closure const&); // no copy 391 closure& operator=(closure const&); // no assign 392 393 #if !defined(__MWERKS__) || (__MWERKS__ > 0x3002) 394 template <int N, typename ClosureT> 395 friend class closure_member; 396 397 template <typename ClosureT> 398 friend class closure_frame; 399 #endif 400 401 typedef impl::closure_frame_holder<closure_frame_t> holder_t; 402 403 #ifdef PHOENIX_THREADSAFE 404 static boost::thread_specific_ptr<holder_t*> & tsp_frame_instance()405 tsp_frame_instance() 406 { 407 static boost::thread_specific_ptr<holder_t*> the_instance; 408 return the_instance; 409 } 410 411 static void tsp_frame_instance_init()412 tsp_frame_instance_init() 413 { 414 tsp_frame_instance(); 415 } 416 #endif 417 418 static holder_t & closure_frame_holder_ref(holder_t * holder_=0)419 closure_frame_holder_ref(holder_t* holder_ = 0) 420 { 421 #ifdef PHOENIX_THREADSAFE 422 #ifndef BOOST_THREAD_PROVIDES_ONCE_CXX11 423 static boost::once_flag been_here = BOOST_ONCE_INIT; 424 #else 425 static boost::once_flag been_here; 426 #endif 427 boost::call_once(been_here, tsp_frame_instance_init); 428 boost::thread_specific_ptr<holder_t*> &tsp_frame = tsp_frame_instance(); 429 if (!tsp_frame.get()) 430 tsp_frame.reset(new holder_t *(0)); 431 holder_t *& holder = *tsp_frame; 432 #else 433 static holder_t* holder = 0; 434 #endif 435 if (holder_ != 0) 436 holder = holder_; 437 return *holder; 438 } 439 440 mutable holder_t frame; 441 }; 442 443 #if BOOST_WORKAROUND(BOOST_MSVC, >= 1400) 444 #pragma warning(pop) 445 #endif 446 447 } 448 // namespace phoenix 449 450 #endif 451