os/ossrv/ossrv_pub/boost_apis/boost/spirit/phoenix/closures.hpp
author sl@SLION-WIN7.fritz.box
Fri, 15 Jun 2012 03:10:57 +0200
changeset 0 bde4ae8d615e
permissions -rw-r--r--
First public contribution.
     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 ///////////////////////////////////////////////////////////////////////////////
    23 namespace 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 
   147 namespace 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 ///////////////////////////////////////////////////////////////////////////////
   215 template <typename ClosureT>
   216 class closure_frame : public ClosureT::tuple_t {
   217 
   218 public:
   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 
   232 private:
   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 ///////////////////////////////////////////////////////////////////////////////
   246 template <int N, typename ClosureT>
   247 class closure_member {
   248 
   249 public:
   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 
   273 private:
   274     impl::closure_frame_holder<typename ClosureT::closure_frame_t> &frame;
   275 };
   276 
   277 ///////////////////////////////////////////////////////////////////////////////
   278 //
   279 //  closure class
   280 //
   281 ///////////////////////////////////////////////////////////////////////////////
   282 template <
   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 >
   312 class closure {
   313 
   314 public:
   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)
   385 private:
   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