source: NonGTP/Boost/boost/spirit/phoenix/closures.hpp @ 857

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