annotate DEPENDENCIES/generic/include/boost/spirit/home/classic/phoenix/closures.hpp @ 133:4acb5d8d80b6 tip

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