stlab.adobe.com Adobe Systems Incorporated
arg_stream.hpp
Go to the documentation of this file.
1 /*************************************************************************
2 *
3 * ADOBE CONFIDENTIAL
4 * ___________________
5 *
6 * Copyright 2008 Adobe Systems Incorporated
7 * All Rights Reserved.
8 *
9 * NOTICE: All information contained herein is, and remains
10 * the property of Adobe Systems Incorporated and its suppliers,
11 * if any. The intellectual and technical concepts contained
12 * herein are proprietary to Adobe Systems Incorporated and its
13 * suppliers and may be covered by U.S. and Foreign Patents,
14 * patents in process, and are protected by trade secret or copyright law.
15 * Dissemination of this information or reproduction of this material
16 * is strictly forbidden unless prior written permission is obtained
17 * from Adobe Systems Incorporated.
18 **************************************************************************/
19 
20 #ifndef ADOBE_ARG_STREAM_H
21 #define ADOBE_ARG_STREAM_H
22 
23 #include <boost/function_types/result_type.hpp>
24 #include <boost/function_types/function_type.hpp>
25 #include <boost/function_types/function_arity.hpp>
26 
27 #include <boost/mpl/begin.hpp>
28 #include <boost/mpl/end.hpp>
29 #include <boost/mpl/next.hpp>
30 #include <boost/mpl/deref.hpp>
31 
32 // Apple sucks
33 #ifdef nil
34 #undef nil
35 #endif
36 
37 #include <boost/fusion/include/push_back.hpp>
38 #include <boost/fusion/include/cons.hpp>
39 #include <boost/fusion/include/invoke.hpp>
40 
41 #include <boost/type_traits/remove_cv.hpp>
42 #include <boost/type_traits/remove_reference.hpp>
43 #include <boost/type_traits/add_pointer.hpp>
44 
45 #include <boost/utility/enable_if.hpp>
46 
47 #include <adobe/type_inspection.hpp> // ADOBE_HAS_TYPE/ADOBE_HAS_MEMBER
48 
49 
50 // forward declare boost::function so we can specialize against it
51 namespace boost
52 {
53  template <typename F> class function;
54 }
55 
56 
57 namespace adobe
58 {
59 
96 namespace arg_stream
97 {
98 
99 
104 struct no_more_args : std::exception
105 {
106 };
107 
108 
109 namespace detail
110 {
112 
113  template <typename T>
115  {
116  static const bool value = ADOBE_HAS_TYPE(T, eof);
117  };
118 }
119 
128 template <typename T>
129 struct traits
130 {
131  static const bool has_eof_member = detail::has_eof_member<T>::value;
132 };
133 
134 
135 namespace detail
136 {
137  template <class ArgStream>
138  static bool eof_check(ArgStream & as, typename boost::enable_if_c<traits<ArgStream>::has_eof_memberfunction>::type * dummy = 0)
139  {
140  return as.eof();
141  }
142 
143  template <class ArgStream>
144  static bool eof_check(ArgStream & as, typename boost::disable_if_c<traits<ArgStream>::has_eof_memberfunction>::type * dummy = 0)
145  {
146  return false;
147  }
148 
149  template <class ArgStream>
150  static bool eof_check(ArgStream *as)
151  {
152  return as ? eof_check(*as) : true;
153  }
154 }
155 
167 template <typename ArgStream>
168 bool eof(ArgStream const & as)
169 {
170  return detail::eof_check(as);
171 }
172 
185 template <typename R, typename ArgStream>
186 R get_next_arg(ArgStream const & as)
187 {
188  return as.get_next_arg<R>();
189 }
190 // specialize these or let them fallback to the above specialization
191 template <typename R, typename ArgStream>
192 R get_next_arg(ArgStream & as)
193 {
194  return as.get_next_arg<R>();
195 }
196 template <typename R, typename ArgStream>
197 R get_next_arg(ArgStream * as)
198 {
199  return get_next_arg<R>(*as);
200 }
201 template <typename R, typename ArgStream>
202 R get_next_arg(ArgStream const * as)
203 {
204  return get_next_arg<R>(*as);
205 }
206 
207 
216 // for some reason boost::function_types does not handle boost::functions,
217 // nor does boost::function have a function::signature typedef,
218 // so in order to support boost, we use this signature<F>::type mechanism:
219 template <typename F>
220 struct signature
221 {
222  typedef F type;
223 };
224 // specialize for boost::function
225 template <typename F>
227 {
228  typedef F type;
229 };
230 
239 template <typename F>
241 {
242  typedef typename boost::function_types::result_type<typename signature<F>::type>::type type;
243 };
244 
245 namespace detail
246 {
247  // how it all works...
248 
249 
250  template<typename T>
252  : boost::remove_cv< typename boost::remove_reference<T>::type >
253  { };
254 
255 
256  // see also boost::function_types 'interpreter' example
257  // we convert the function signature into a mpl sequence (it *is* an mpl sequence, since it implements mpl::begin/end/etc)
258  // we recursively push the args onto a fusion sequence, calling get_next_arg as we go.
259  // the recursion ends when we get to the end of the mpl-sequence-function-sigature
260  // (see the specialized case where From == To)
261  // and then luckily fusion has a magic invoke function we can use
262  template< typename F,
263  class From = typename boost::mpl::begin< boost::function_types::parameter_types<typename signature<F>::type> >::type,
264  class To = typename boost::mpl::end< boost::function_types::parameter_types<typename signature<F>::type> >::type>
265  struct invoker
266  {
267  // add an argument to a Fusion cons-list for each parameter type
268  template<typename Args, typename ArgStream>
269  static inline
270  typename result_type<F>::type
271  apply(F func, ArgStream & astream, Args const & args)
272  {
273  typedef typename remove_cv_ref<typename boost::mpl::deref<From>::type>::type arg_type;
274  typedef typename boost::mpl::next<From>::type next_iter_type;
275 
277  func, astream, boost::fusion::push_back(args, get_next_arg<arg_type>(astream)) );
278  }
279  };
280 
281  // specialize final case
282  template<typename F, class To>
283  struct invoker<F,To,To>
284  {
285  template<typename Args, typename ArgStream>
286  static inline
287  typename result_type<F>::type
288  apply(F func, ArgStream &, Args const & args)
289  {
290  return boost::fusion::invoke(func, args);
291  }
292  };
293 
294 } // detail
295 
296 
304 template <typename F, typename ArgStream>
305 typename result_type<F>::type
306  call(F f, ArgStream & astream)
307 {
308  return detail::invoker<F>::template apply(f, astream, boost::fusion::nil());
309 }
310 
316 template <class T, typename F, typename ArgStream>
317 typename result_type<F>::type
318  call(T * that, F f, ArgStream & astream)
319 {
320  // object gets pushed on as first arg of fusion list,
321  // and remove first arg from signature (the object that the member function belongs to) using mpl::next
322  boost::fusion::nil args;
323  return detail::invoker<F,
324  typename boost::mpl::next< typename boost::mpl::begin< boost::function_types::parameter_types<typename signature<F>::type, boost::add_pointer<boost::mpl::placeholders::_> > >::type>::type,
325  typename boost::mpl::end< boost::function_types::parameter_types<typename signature<F>::type, boost::add_pointer<boost::mpl::placeholders::_> > >::type>
326  ::template apply(f, astream, boost::fusion::push_back(args, that));
327 }
328 
329 
338 template <typename ArgStreamFirst, typename ArgStreamSecond>
339 struct chain
340 {
341  template <class ArgStream>
342  bool eof(ArgStream * as)
343  {
344  return detail::eof_check(as);
345  }
346 
347  typedef ArgStreamFirst first_type;
348  typedef ArgStreamSecond second_type;
349  ArgStreamFirst * first;
350  ArgStreamSecond * second;
351 
352  chain(ArgStreamFirst & first_stream, ArgStreamSecond & second_stream)
353  :
354  first(&first_stream),
355  second(&second_stream)
356  {
357  }
358 
359  template <typename T>
361  {
362  if (!eof(first))
363  {
364  try
365  {
366  return first->get_next_arg<T>();
367  }
368  catch(arg_stream::no_more_args &)
369  {
370  first = 0;
371  }
372  }
373 
374  return second->get_next_arg<T>();
375  }
376 
377  bool eof() const
378  {
379  return eof(first) && eof(second);
380  }
381 };
382 
383 template <typename S1, typename S2>
384 struct traits<chain<S1, S2> >
385 {
386  static const bool has_eof_memberfunction = true;
387 };
388 
392 template <typename ArgStreamFirst, typename ArgStreamSecond>
393 chain<ArgStreamFirst, ArgStreamSecond> make_chain(ArgStreamFirst & first_stream, ArgStreamSecond & second_stream)
394 {
395  return chain<ArgStreamFirst, ArgStreamSecond>(first_stream, second_stream);
396 }
397 
401 struct nonarg
402 {
403  bool eof()
404  {
405  return true;
406  }
407 
408  template <typename R>
410  {
411  throw arg_stream::no_more_args();
412 
413  return *(R*)32; // some compilers need a return; here's a bad one (but that doesn't require default construction)
414  }
415 };
416 
417 template<>
418 struct traits<nonarg>
419 {
420  static const bool has_eof_memberfunction = true;
421 };
422 
427 template <typename T>
428 struct single
429 {
430  typedef T value_type;
431 
432  T value;
433  unsigned int repeat; // yep, unsigned.
434 
435  single(typename boost::add_reference<T const>::type t, unsigned int count = 1) : value(t), repeat(count)
436  {
437  }
438 
439  bool eof()
440  {
441  return repeat == 0;
442  }
443 
444  template <typename R>
445  R convert_or_throw(value_type & value, typename boost::enable_if<boost::is_convertible<value_type, R> >::type * dummy = 0)
446  {
447  return R(value);
448  }
449  template <typename R>
450  R convert_or_throw(value_type & value, typename boost::disable_if<boost::is_convertible<value_type, R> >::type * dummy = 0)
451  {
452  throw adobe::bad_cast();
453  return *(R*)value;
454  }
455 
456  template <typename R>
458  {
459  if (repeat)
460  {
461  repeat--;
462  }
463  else
464  {
465  throw arg_stream::no_more_args();
466  }
467 
468  return convert_or_throw<R>(value);
469  }
470 };
471 
472 template<typename T>
473 struct traits<single<T> >
474 {
475  static const bool has_eof_memberfunction = true;
476 };
477 
478 template <typename ArgStream, typename Transformer>
480 {
481  ADOBE_HAS_TEMPLATE1_IMPL(arg_stream_inverse_lookup);
482 
483  template <typename Class>
485  {
486  static const bool value = ADOBE_HAS_TEMPLATE1(Class, arg_stream_inverse_lookup);
487  };
488 
489  template <typename Class, typename R, bool>
491  {
492  static const bool value = false;
493  };
494  template <typename Class, typename R>
495  struct has_entry_if_has_inverse_lookup<Class, R, true>
496  {
498  };
499 
500  template <typename Class, typename R>
502  {
504  };
505 
506  typedef ArgStream value_type;
507  typedef ArgStream arg_stream_type;
508  typedef Transformer transformer_type;
509 
510  ArgStream & argstream;
511  Transformer & transformer;
512 
513  with_transform(ArgStream & as, Transformer & trans) : argstream(as), transformer(trans)
514  {
515  }
516 
517  bool eof()
518  {
519  return detail::eof_check(argstream);
520  }
521 
522  template <typename R>
523  R transforming_get(typename boost::enable_if<has_transform<Transformer, R> >::type * dummy = 0)
524  {
525  typedef typename Transformer::template arg_stream_inverse_lookup<R>::type Rfrom;
526  return transformer.template arg_stream_transform<R>(arg_stream::get_next_arg<Rfrom>(argstream));
527  }
528  template <typename R>
529  R transforming_get(typename boost::disable_if<has_transform<Transformer, R> >::type * dummy = 0)
530  {
531  return arg_stream::get_next_arg<R>(argstream);
532  }
533 
534  template <typename R>
536  {
537  return transforming_get<R>();
538  }
539 };
540 
541 template <typename ArgStream, typename Transformer>
542 with_transform<ArgStream, Transformer> make_transforming(ArgStream & as, Transformer & transformer)
543 {
544  return with_transform<ArgStream, Transformer>(as, transformer);
545 }
546 
547 } // namespace arg_stream
548 } // namespace adobe
549 
550 
551 #endif // include_guard
#define ADOBE_HAS_TYPE_IMPL(TypeInQuestion)
Implementation part of ADOBE_HAS_TYPE macro. Required before using ADOBE_HAS_TYPE.
is T::type a valid type (or a compile error?)
Definition: arg_stream.hpp:490
static bool eof_check(ArgStream *as)
Definition: arg_stream.hpp:150
ArgStreamSecond * second
Definition: arg_stream.hpp:350
#define ADOBE_HAS_TEMPLATE1(C, TemplateInQuestion)
returns true iff C has an internal template named &#39;TemplateInQuestion&#39; with 1 (nondefault) template p...
holds a single value, and returns it as an arg n (default 1) times
Definition: arg_stream.hpp:428
R get_next_arg(ArgStream const *as)
Definition: arg_stream.hpp:202
static result_type< F >::type apply(F func, ArgStream &astream, Args const &args)
Definition: arg_stream.hpp:271
bool eof(ArgStream *as)
Definition: arg_stream.hpp:342
bool eof(ArgStream const &as)
arg_stream::eof(argstream) returns true if there are no more args available.
Definition: arg_stream.hpp:168
ArgStreamFirst * first
Definition: arg_stream.hpp:349
An exception class thrown during ASL failures to cast.
Definition: typeinfo.hpp:379
static result_type< F >::type apply(F func, ArgStream &, Args const &args)
Definition: arg_stream.hpp:288
boost::function_types::result_type< typename signature< F >::type >::type type
Definition: arg_stream.hpp:242
R convert_or_throw(value_type &value, typename boost::enable_if< boost::is_convertible< value_type, R > >::type *dummy=0)
Definition: arg_stream.hpp:445
with_transform(ArgStream &as, Transformer &trans)
Definition: arg_stream.hpp:513
boost::range_difference< InputRange >::type count(InputRange &range, T &value)
count implementation
Definition: count.hpp:41
chain< ArgStreamFirst, ArgStreamSecond > make_chain(ArgStreamFirst &first_stream, ArgStreamSecond &second_stream)
given 2 arg_streams, returns an arg_stream of the 2 streams chained together
Definition: arg_stream.hpp:393
chain 2 arg_streams together by calling the first stream until depleted, then calling the second...
Definition: arg_stream.hpp:339
ArgStreamSecond second_type
Definition: arg_stream.hpp:348
with_transform< ArgStream, Transformer > make_transforming(ArgStream &as, Transformer &transformer)
Definition: arg_stream.hpp:542
void push_back(array_t &v, T x)
Definition: array.hpp:28
R convert_or_throw(value_type &value, typename boost::disable_if< boost::is_convertible< value_type, R > >::type *dummy=0)
Definition: arg_stream.hpp:450
R transforming_get(typename boost::enable_if< has_transform< Transformer, R > >::type *dummy=0)
Definition: arg_stream.hpp:523
single(typename boost::add_reference< T const >::type t, unsigned int count=1)
Definition: arg_stream.hpp:435
defines any traits that help with the implementation of arg_stream::call() and/or helper objects like...
Definition: arg_stream.hpp:129
chain(ArgStreamFirst &first_stream, ArgStreamSecond &second_stream)
Definition: arg_stream.hpp:352
the empty-set arg stream has no arguments. Not sure what this might be useful for.
Definition: arg_stream.hpp:401
ArgStreamFirst first_type
Definition: arg_stream.hpp:347
result_type<F>::type is the return type of the function f.
Definition: arg_stream.hpp:240
result_type< F >::type call(T *that, F f, ArgStream &astream)
specialization of arg_stream::call for handling member function calls.
Definition: arg_stream.hpp:318
R transforming_get(typename boost::disable_if< has_transform< Transformer, R > >::type *dummy=0)
Definition: arg_stream.hpp:529
#define ADOBE_HAS_TYPE(C, TypeInQuestion)
returns true iff C has an internal type named &#39;TypeInQuestion&#39;. ie returns true iff C::TypeInQuestion...
#define ADOBE_HAS_TEMPLATE1_IMPL(TemplateInQuestion)
Implementation part of ADOBE_HAS_TEMPLATE1 macro. Required before using ADOBE_HAS_TEMPLATE1.
returns the function signature of the callable object type F
Definition: arg_stream.hpp:220

Copyright © 2006-2007 Adobe Systems Incorporated.

Use of this website signifies your agreement to the Terms of Use and Online Privacy Policy.

Search powered by Google