Chris@16: /*============================================================================= Chris@16: Phoenix V1.2.1 Chris@16: Copyright (c) 2001-2002 Joel de Guzman Chris@16: MT code Copyright (c) 2002-2003 Martin Wille Chris@16: Chris@16: Distributed under the Boost Software License, Version 1.0. (See accompanying Chris@16: file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) Chris@16: ==============================================================================*/ Chris@16: #ifndef CLASSIC_PHOENIX_CLOSURES_HPP Chris@16: #define CLASSIC_PHOENIX_CLOSURES_HPP Chris@16: Chris@16: /////////////////////////////////////////////////////////////////////////////// Chris@16: #include Chris@16: #include Chris@16: Chris@16: #ifdef PHOENIX_THREADSAFE Chris@16: #include Chris@16: #include Chris@16: #endif Chris@16: Chris@16: /////////////////////////////////////////////////////////////////////////////// Chris@16: namespace phoenix { Chris@16: Chris@16: #if BOOST_WORKAROUND(BOOST_MSVC, >= 1400) Chris@16: #pragma warning(push) Chris@16: #pragma warning(disable:4512) //assignment operator could not be generated Chris@16: #endif Chris@16: Chris@16: /////////////////////////////////////////////////////////////////////////////// Chris@16: // Chris@16: // Adaptable closures Chris@16: // Chris@16: // The framework will not be complete without some form of closures Chris@16: // support. Closures encapsulate a stack frame where local Chris@16: // variables are created upon entering a function and destructed Chris@16: // upon exiting. Closures provide an environment for local Chris@16: // variables to reside. Closures can hold heterogeneous types. Chris@16: // Chris@16: // Phoenix closures are true hardware stack based closures. At the Chris@16: // very least, closures enable true reentrancy in lambda functions. Chris@16: // A closure provides access to a function stack frame where local Chris@16: // variables reside. Modeled after Pascal nested stack frames, Chris@16: // closures can be nested just like nested functions where code in Chris@16: // inner closures may access local variables from in-scope outer Chris@16: // closures (accessing inner scopes from outer scopes is an error Chris@16: // and will cause a run-time assertion failure). Chris@16: // Chris@16: // There are three (3) interacting classes: Chris@16: // Chris@16: // 1) closure: Chris@16: // Chris@16: // At the point of declaration, a closure does not yet create a Chris@16: // stack frame nor instantiate any variables. A closure declaration Chris@16: // declares the types and names[note] of the local variables. The Chris@16: // closure class is meant to be subclassed. It is the Chris@16: // responsibility of a closure subclass to supply the names for Chris@16: // each of the local variable in the closure. Example: Chris@16: // Chris@16: // struct my_closure : closure { Chris@16: // Chris@16: // member1 num; // names the 1st (int) local variable Chris@16: // member2 message; // names the 2nd (string) local variable Chris@16: // member3 real; // names the 3rd (double) local variable Chris@16: // }; Chris@16: // Chris@16: // my_closure clos; Chris@16: // Chris@16: // Now that we have a closure 'clos', its local variables can be Chris@16: // accessed lazily using the dot notation. Each qualified local Chris@16: // variable can be used just like any primitive actor (see Chris@16: // primitives.hpp). Examples: Chris@16: // Chris@16: // clos.num = 30 Chris@16: // clos.message = arg1 Chris@16: // clos.real = clos.num * 1e6 Chris@16: // Chris@16: // The examples above are lazily evaluated. As usual, these Chris@16: // expressions return composite actors that will be evaluated Chris@16: // through a second function call invocation (see operators.hpp). Chris@16: // Each of the members (clos.xxx) is an actor. As such, applying Chris@16: // the operator() will reveal its identity: Chris@16: // Chris@16: // clos.num() // will return the current value of clos.num Chris@16: // Chris@16: // *** [note] Acknowledgement: Juan Carlos Arevalo-Baeza (JCAB) Chris@16: // introduced and initilally implemented the closure member names Chris@16: // that uses the dot notation. Chris@16: // Chris@16: // 2) closure_member Chris@16: // Chris@16: // The named local variables of closure 'clos' above are actually Chris@16: // closure members. The closure_member class is an actor and Chris@16: // conforms to its conceptual interface. member1..memberN are Chris@16: // predefined typedefs that correspond to each of the listed types Chris@16: // in the closure template parameters. Chris@16: // Chris@16: // 3) closure_frame Chris@16: // Chris@16: // When a closure member is finally evaluated, it should refer to Chris@16: // an actual instance of the variable in the hardware stack. Chris@16: // Without doing so, the process is not complete and the evaluated Chris@16: // member will result to an assertion failure. Remember that the Chris@16: // closure is just a declaration. The local variables that a Chris@16: // closure refers to must still be instantiated. Chris@16: // Chris@16: // The closure_frame class does the actual instantiation of the Chris@16: // local variables and links these variables with the closure and Chris@16: // all its members. There can be multiple instances of Chris@16: // closure_frames typically situated in the stack inside a Chris@16: // function. Each closure_frame instance initiates a stack frame Chris@16: // with a new set of closure local variables. Example: Chris@16: // Chris@16: // void foo() Chris@16: // { Chris@16: // closure_frame frame(clos); Chris@16: // /* do something */ Chris@16: // } Chris@16: // Chris@16: // where 'clos' is an instance of our closure 'my_closure' above. Chris@16: // Take note that the usage above precludes locally declared Chris@16: // classes. If my_closure is a locally declared type, we can still Chris@16: // use its self_type as a paramater to closure_frame: Chris@16: // Chris@16: // closure_frame frame(clos); Chris@16: // Chris@16: // Upon instantiation, the closure_frame links the local variables Chris@16: // to the closure. The previous link to another closure_frame Chris@16: // instance created before is saved. Upon destruction, the Chris@16: // closure_frame unlinks itself from the closure and relinks the Chris@16: // preceding closure_frame prior to this instance. Chris@16: // Chris@16: // The local variables in the closure 'clos' above is default Chris@16: // constructed in the stack inside function 'foo'. Once 'foo' is Chris@16: // exited, all of these local variables are destructed. In some Chris@16: // cases, default construction is not desirable and we need to Chris@16: // initialize the local closure variables with some values. This Chris@16: // can be done by passing in the initializers in a compatible Chris@16: // tuple. A compatible tuple is one with the same number of Chris@16: // elements as the destination and where each element from the Chris@16: // destination can be constructed from each corresponding element Chris@16: // in the source. Example: Chris@16: // Chris@16: // tuple init(123, "Hello", 1000); Chris@16: // closure_frame frame(clos, init); Chris@16: // Chris@16: // Here now, our closure_frame's variables are initialized with Chris@16: // int: 123, char const*: "Hello" and int: 1000. Chris@16: // Chris@16: /////////////////////////////////////////////////////////////////////////////// Chris@16: Chris@16: namespace impl Chris@16: { Chris@16: /////////////////////////////////////////////////////////////////////// Chris@16: // closure_frame_holder is a simple class that encapsulates the Chris@16: // storage for a frame pointer. It uses thread specific data in Chris@16: // case when multithreading is enabled, an ordinary pointer otherwise Chris@16: // Chris@16: // it has get() and set() member functions. set() has to be used Chris@16: // _after_ get(). get() contains intialisation code in the multi Chris@16: // threading case Chris@16: // Chris@16: // closure_frame_holder is used by the closure<> class to store Chris@16: // the pointer to the current frame. Chris@16: // Chris@16: #ifndef PHOENIX_THREADSAFE Chris@16: template Chris@16: struct closure_frame_holder Chris@16: { Chris@16: typedef FrameT frame_t; Chris@16: typedef frame_t *frame_ptr; Chris@16: Chris@16: closure_frame_holder() : frame(0) {} Chris@16: Chris@16: frame_ptr &get() { return frame; } Chris@16: void set(frame_t *f) { frame = f; } Chris@16: Chris@16: private: Chris@16: frame_ptr frame; Chris@16: Chris@16: // no copies, no assignments Chris@16: closure_frame_holder(closure_frame_holder const &); Chris@16: closure_frame_holder &operator=(closure_frame_holder const &); Chris@16: }; Chris@16: #else Chris@16: template Chris@16: struct closure_frame_holder Chris@16: { Chris@16: typedef FrameT frame_t; Chris@16: typedef frame_t *frame_ptr; Chris@16: Chris@16: closure_frame_holder() : tsp_frame() {} Chris@16: Chris@16: frame_ptr &get() Chris@16: { Chris@16: if (!tsp_frame.get()) Chris@16: tsp_frame.reset(new frame_ptr(0)); Chris@16: return *tsp_frame; Chris@16: } Chris@16: void set(frame_ptr f) Chris@16: { Chris@16: *tsp_frame = f; Chris@16: } Chris@16: Chris@16: private: Chris@16: boost::thread_specific_ptr tsp_frame; Chris@16: Chris@16: // no copies, no assignments Chris@16: closure_frame_holder(closure_frame_holder const &); Chris@16: closure_frame_holder &operator=(closure_frame_holder const &); Chris@16: }; Chris@16: #endif Chris@16: } // namespace phoenix::impl Chris@16: Chris@16: /////////////////////////////////////////////////////////////////////////////// Chris@16: // Chris@16: // closure_frame class Chris@16: // Chris@16: /////////////////////////////////////////////////////////////////////////////// Chris@16: template Chris@16: class closure_frame : public ClosureT::tuple_t { Chris@16: Chris@16: public: Chris@16: Chris@16: closure_frame(ClosureT const& clos) Chris@16: : ClosureT::tuple_t(), save(clos.frame.get()), frame(clos.frame) Chris@16: { clos.frame.set(this); } Chris@16: Chris@16: template Chris@16: closure_frame(ClosureT const& clos, TupleT const& init) Chris@16: : ClosureT::tuple_t(init), save(clos.frame.get()), frame(clos.frame) Chris@16: { clos.frame.set(this); } Chris@16: Chris@16: ~closure_frame() Chris@16: { frame.set(save); } Chris@16: Chris@16: private: Chris@16: Chris@16: closure_frame(closure_frame const&); // no copy Chris@16: closure_frame& operator=(closure_frame const&); // no assign Chris@16: Chris@16: closure_frame* save; Chris@16: impl::closure_frame_holder& frame; Chris@16: }; Chris@16: Chris@16: /////////////////////////////////////////////////////////////////////////////// Chris@16: // Chris@16: // closure_member class Chris@16: // Chris@16: /////////////////////////////////////////////////////////////////////////////// Chris@16: template Chris@16: class closure_member { Chris@16: Chris@16: public: Chris@16: Chris@16: typedef typename ClosureT::tuple_t tuple_t; Chris@16: Chris@16: closure_member() Chris@16: : frame(ClosureT::closure_frame_holder_ref()) {} Chris@16: Chris@16: template Chris@16: struct result { Chris@16: Chris@16: typedef typename tuple_element< Chris@16: N, typename ClosureT::tuple_t Chris@16: >::rtype type; Chris@16: }; Chris@16: Chris@16: template Chris@16: typename tuple_element::rtype Chris@16: eval(TupleT const& /*args*/) const Chris@16: { Chris@16: using namespace std; Chris@16: BOOST_ASSERT(frame.get() != 0); Chris@16: return (*frame.get())[tuple_index()]; Chris@16: } Chris@16: Chris@16: private: Chris@16: impl::closure_frame_holder &frame; Chris@16: }; Chris@16: Chris@16: /////////////////////////////////////////////////////////////////////////////// Chris@16: // Chris@16: // closure class Chris@16: // Chris@16: /////////////////////////////////////////////////////////////////////////////// Chris@16: template < Chris@16: typename T0 = nil_t Chris@16: , typename T1 = nil_t Chris@16: , typename T2 = nil_t Chris@16: Chris@16: #if PHOENIX_LIMIT > 3 Chris@16: , typename T3 = nil_t Chris@16: , typename T4 = nil_t Chris@16: , typename T5 = nil_t Chris@16: Chris@16: #if PHOENIX_LIMIT > 6 Chris@16: , typename T6 = nil_t Chris@16: , typename T7 = nil_t Chris@16: , typename T8 = nil_t Chris@16: Chris@16: #if PHOENIX_LIMIT > 9 Chris@16: , typename T9 = nil_t Chris@16: , typename T10 = nil_t Chris@16: , typename T11 = nil_t Chris@16: Chris@16: #if PHOENIX_LIMIT > 12 Chris@16: , typename T12 = nil_t Chris@16: , typename T13 = nil_t Chris@16: , typename T14 = nil_t Chris@16: Chris@16: #endif Chris@16: #endif Chris@16: #endif Chris@16: #endif Chris@16: > Chris@16: class closure { Chris@16: Chris@16: public: Chris@16: Chris@16: typedef tuple< Chris@16: T0, T1, T2 Chris@16: #if PHOENIX_LIMIT > 3 Chris@16: , T3, T4, T5 Chris@16: #if PHOENIX_LIMIT > 6 Chris@16: , T6, T7, T8 Chris@16: #if PHOENIX_LIMIT > 9 Chris@16: , T9, T10, T11 Chris@16: #if PHOENIX_LIMIT > 12 Chris@16: , T12, T13, T14 Chris@16: #endif Chris@16: #endif Chris@16: #endif Chris@16: #endif Chris@16: > tuple_t; Chris@16: Chris@16: typedef closure< Chris@16: T0, T1, T2 Chris@16: #if PHOENIX_LIMIT > 3 Chris@16: , T3, T4, T5 Chris@16: #if PHOENIX_LIMIT > 6 Chris@16: , T6, T7, T8 Chris@16: #if PHOENIX_LIMIT > 9 Chris@16: , T9, T10, T11 Chris@16: #if PHOENIX_LIMIT > 12 Chris@16: , T12, T13, T14 Chris@16: #endif Chris@16: #endif Chris@16: #endif Chris@16: #endif Chris@16: > self_t; Chris@16: Chris@16: typedef closure_frame closure_frame_t; Chris@16: Chris@16: closure() Chris@16: : frame() { closure_frame_holder_ref(&frame); } Chris@16: Chris@16: typedef actor > member1; Chris@16: typedef actor > member2; Chris@16: typedef actor > member3; Chris@16: Chris@16: #if PHOENIX_LIMIT > 3 Chris@16: typedef actor > member4; Chris@16: typedef actor > member5; Chris@16: typedef actor > member6; Chris@16: Chris@16: #if PHOENIX_LIMIT > 6 Chris@16: typedef actor > member7; Chris@16: typedef actor > member8; Chris@16: typedef actor > member9; Chris@16: Chris@16: #if PHOENIX_LIMIT > 9 Chris@16: typedef actor > member10; Chris@16: typedef actor > member11; Chris@16: typedef actor > member12; Chris@16: Chris@16: #if PHOENIX_LIMIT > 12 Chris@16: typedef actor > member13; Chris@16: typedef actor > member14; Chris@16: typedef actor > member15; Chris@16: Chris@16: #endif Chris@16: #endif Chris@16: #endif Chris@16: #endif Chris@16: Chris@16: #if !defined(__MWERKS__) || (__MWERKS__ > 0x3002) Chris@16: private: Chris@16: #endif Chris@16: Chris@16: closure(closure const&); // no copy Chris@16: closure& operator=(closure const&); // no assign Chris@16: Chris@16: #if !defined(__MWERKS__) || (__MWERKS__ > 0x3002) Chris@16: template Chris@16: friend class closure_member; Chris@16: Chris@16: template Chris@16: friend class closure_frame; Chris@16: #endif Chris@16: Chris@16: typedef impl::closure_frame_holder holder_t; Chris@16: Chris@16: #ifdef PHOENIX_THREADSAFE Chris@16: static boost::thread_specific_ptr & Chris@16: tsp_frame_instance() Chris@16: { Chris@16: static boost::thread_specific_ptr the_instance; Chris@16: return the_instance; Chris@16: } Chris@16: Chris@16: static void Chris@16: tsp_frame_instance_init() Chris@16: { Chris@16: tsp_frame_instance(); Chris@16: } Chris@16: #endif Chris@16: Chris@16: static holder_t & Chris@16: closure_frame_holder_ref(holder_t* holder_ = 0) Chris@16: { Chris@16: #ifdef PHOENIX_THREADSAFE Chris@16: static boost::once_flag been_here = BOOST_ONCE_INIT; Chris@16: boost::call_once(been_here, tsp_frame_instance_init); Chris@16: boost::thread_specific_ptr &tsp_frame = tsp_frame_instance(); Chris@16: if (!tsp_frame.get()) Chris@16: tsp_frame.reset(new holder_t *(0)); Chris@16: holder_t *& holder = *tsp_frame; Chris@16: #else Chris@16: static holder_t* holder = 0; Chris@16: #endif Chris@16: if (holder_ != 0) Chris@16: holder = holder_; Chris@16: return *holder; Chris@16: } Chris@16: Chris@16: mutable holder_t frame; Chris@16: }; Chris@16: Chris@16: #if BOOST_WORKAROUND(BOOST_MSVC, >= 1400) Chris@16: #pragma warning(pop) Chris@16: #endif Chris@16: Chris@16: } Chris@16: // namespace phoenix Chris@16: Chris@16: #endif