Chris@16: /*============================================================================= Chris@16: Adaptable closures Chris@16: Chris@16: Phoenix V0.9 Chris@16: Copyright (c) 2001-2002 Joel de Guzman Chris@16: Chris@16: Distributed under the Boost Software License, Version 1.0. (See Chris@16: accompanying file LICENSE_1_0.txt or copy at Chris@16: http://www.boost.org/LICENSE_1_0.txt) Chris@16: Chris@16: URL: http://spirit.sourceforge.net/ Chris@16: Chris@16: ==============================================================================*/ Chris@16: #ifndef PHOENIX_CLOSURES_HPP Chris@16: #define PHOENIX_CLOSURES_HPP Chris@16: Chris@16: /////////////////////////////////////////////////////////////////////////////// Chris@16: #include "boost/lambda/core.hpp" Chris@16: /////////////////////////////////////////////////////////////////////////////// Chris@16: namespace boost { Chris@16: namespace lambda { 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: 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& clos) Chris@16: : ClosureT::tuple_t(), save(clos.frame), frame(clos.frame) Chris@16: { clos.frame = this; } Chris@16: Chris@16: template Chris@16: closure_frame(ClosureT& clos, TupleT const& init) Chris@16: : ClosureT::tuple_t(init), save(clos.frame), frame(clos.frame) Chris@16: { clos.frame = this; } Chris@16: Chris@16: ~closure_frame() Chris@16: { frame = 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: closure_frame*& 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_ref()) {} Chris@16: Chris@16: template Chris@16: struct sig { Chris@16: Chris@16: typedef typename detail::tuple_element_as_reference< Chris@16: N, typename ClosureT::tuple_t Chris@16: >::type type; Chris@16: }; Chris@16: Chris@16: template Chris@16: // typename detail::tuple_element_as_reference Chris@16: // ::type Chris@16: Ret Chris@16: call(A&, B&, C&) const Chris@16: { Chris@16: assert(frame); Chris@16: return boost::tuples::get(*frame); Chris@16: } Chris@16: Chris@16: Chris@16: private: Chris@16: Chris@16: typename ClosureT::closure_frame_t*& frame; Chris@16: }; Chris@16: Chris@16: /////////////////////////////////////////////////////////////////////////////// Chris@16: // Chris@16: // closure class Chris@16: // Chris@16: /////////////////////////////////////////////////////////////////////////////// Chris@16: template < Chris@16: typename T0 = null_type, Chris@16: typename T1 = null_type, Chris@16: typename T2 = null_type, Chris@16: typename T3 = null_type, Chris@16: typename T4 = null_type Chris@16: > Chris@16: class closure { Chris@16: Chris@16: public: Chris@16: Chris@16: typedef tuple tuple_t; Chris@16: typedef closure self_t; Chris@16: typedef closure_frame closure_frame_t; Chris@16: Chris@16: closure() Chris@16: : frame(0) { closure_frame_ref(&frame); } Chris@16: closure_frame_t& context() { assert(frame); return frame; } Chris@16: closure_frame_t const& context() const { assert(frame); return frame; } Chris@16: Chris@16: typedef lambda_functor > member1; Chris@16: typedef lambda_functor > member2; Chris@16: typedef lambda_functor > member3; Chris@16: typedef lambda_functor > member4; Chris@16: typedef lambda_functor > member5; Chris@16: Chris@16: private: Chris@16: Chris@16: closure(closure const&); // no copy Chris@16: closure& operator=(closure const&); // no assign Chris@16: Chris@16: template Chris@16: friend class closure_member; Chris@16: Chris@16: template Chris@16: friend class closure_frame; Chris@16: Chris@16: static closure_frame_t*& Chris@16: closure_frame_ref(closure_frame_t** frame_ = 0) Chris@16: { Chris@16: static closure_frame_t** frame = 0; Chris@16: if (frame_ != 0) Chris@16: frame = frame_; Chris@16: return *frame; Chris@16: } Chris@16: Chris@16: closure_frame_t* frame; Chris@16: }; Chris@16: Chris@16: }} Chris@16: // namespace Chris@16: Chris@16: #endif