stlab.adobe.com Adobe Systems Incorporated

arg_stream.hpp

Go to the documentation of this file.
00001 /*************************************************************************
00002 *
00003 * ADOBE CONFIDENTIAL
00004 * ___________________
00005 *
00006 *  Copyright 2008 Adobe Systems Incorporated
00007 *  All Rights Reserved.
00008 *
00009 * NOTICE:  All information contained herein is, and remains
00010 * the property of Adobe Systems Incorporated and its suppliers,
00011 * if any.  The intellectual and technical concepts contained
00012 * herein are proprietary to Adobe Systems Incorporated and its
00013 * suppliers and may be covered by U.S. and Foreign Patents,
00014 * patents in process, and are protected by trade secret or copyright law.
00015 * Dissemination of this information or reproduction of this material
00016 * is strictly forbidden unless prior written permission is obtained
00017 * from Adobe Systems Incorporated.
00018 **************************************************************************/
00019 
00020 #ifndef ADOBE_ARG_STREAM_H
00021 #define ADOBE_ARG_STREAM_H
00022 
00023 #include <boost/function_types/result_type.hpp>
00024 #include <boost/function_types/function_type.hpp>
00025 #include <boost/function_types/function_arity.hpp>
00026 
00027 #include <boost/mpl/begin.hpp>
00028 #include <boost/mpl/end.hpp>
00029 #include <boost/mpl/next.hpp>
00030 #include <boost/mpl/deref.hpp>
00031 
00032 // Apple sucks
00033 #ifdef nil
00034 #undef nil
00035 #endif
00036 
00037 #include <boost/fusion/include/push_back.hpp>
00038 #include <boost/fusion/include/cons.hpp>
00039 #include <boost/fusion/include/invoke.hpp>
00040 
00041 #include <boost/type_traits/remove_cv.hpp>
00042 #include <boost/type_traits/remove_reference.hpp>
00043 #include <boost/type_traits/add_pointer.hpp>
00044 
00045 #include <boost/utility/enable_if.hpp>
00046 
00047 #include <adobe/type_inspection.hpp> // ADOBE_HAS_TYPE/ADOBE_HAS_MEMBER
00048 
00049 
00050 // forward declare boost::function so we can specialize against it
00051 namespace boost
00052 {
00053     template <typename F> class function;
00054 }
00055 
00056 
00057 namespace adobe
00058 {
00059 
00096 namespace arg_stream
00097 {
00098 
00099 
00104 struct no_more_args : std::exception
00105 {
00106 };
00107 
00108 
00109 namespace detail
00110 {
00111     ADOBE_HAS_TYPE_IMPL(eof);
00112 
00113     template <typename T>
00114     struct has_eof_member
00115     {
00116         static const bool value = ADOBE_HAS_TYPE(T, eof);
00117     };
00118 }
00119 
00128 template <typename T>
00129 struct traits
00130 {
00131     static const bool has_eof_member = detail::has_eof_member<T>::value;
00132 };
00133 
00134 
00135 namespace detail
00136 {
00137     template <class ArgStream>
00138     static bool eof_check(ArgStream & as, typename boost::enable_if_c<traits<ArgStream>::has_eof_memberfunction>::type * dummy = 0)
00139     {
00140         return as.eof();
00141     }
00142 
00143     template <class ArgStream>
00144     static bool eof_check(ArgStream & as, typename boost::disable_if_c<traits<ArgStream>::has_eof_memberfunction>::type * dummy = 0)
00145     {
00146         return false;
00147     }
00148 
00149     template <class ArgStream>
00150     static bool eof_check(ArgStream *as)
00151     {
00152         return as ? eof_check(*as) : true;
00153     }
00154 }
00155 
00167 template <typename ArgStream>
00168 bool eof(ArgStream const & as)
00169 {
00170     return detail::eof_check(as);
00171 }
00172 
00185 template <typename R, typename ArgStream>
00186 R get_next_arg(ArgStream const & as)
00187 {
00188     return as.get_next_arg<R>();
00189 }
00190 // specialize these or let them fallback to the above specialization
00191 template <typename R, typename ArgStream>
00192 R get_next_arg(ArgStream & as)
00193 {
00194     return as.get_next_arg<R>();
00195 }
00196 template <typename R, typename ArgStream>
00197 R get_next_arg(ArgStream * as)
00198 {
00199     return get_next_arg<R>(*as);
00200 }
00201 template <typename R, typename ArgStream>
00202 R get_next_arg(ArgStream const * as)
00203 {
00204     return get_next_arg<R>(*as);
00205 }
00206 
00207 
00216 // for some reason boost::function_types does not handle boost::functions,
00217 // nor does boost::function have a function::signature typedef,
00218 // so in order to support boost, we use this signature<F>::type mechanism:
00219 template <typename F>
00220 struct signature
00221 {
00222     typedef F type;
00223 };
00224 // specialize for boost::function
00225 template <typename F>
00226 struct signature<boost::function<F> >
00227 {
00228     typedef F type;
00229 };
00230 
00239 template <typename F>
00240 struct result_type
00241 {
00242     typedef typename boost::function_types::result_type<typename signature<F>::type>::type type;
00243 };
00244 
00245 namespace detail
00246 {
00247     // how it all works...
00248 
00249 
00250     template<typename T>
00251     struct remove_cv_ref
00252       : boost::remove_cv< typename boost::remove_reference<T>::type >
00253     { };
00254 
00255 
00256     // see also boost::function_types 'interpreter' example
00257     // we convert the function signature into a mpl sequence (it *is* an mpl sequence, since it implements mpl::begin/end/etc)
00258     // we recursively push the args onto a fusion sequence, calling get_next_arg as we go.
00259     // the recursion ends when we get to the end of the mpl-sequence-function-sigature
00260     // (see the specialized case where From == To)
00261     // and then luckily fusion has a magic invoke function we can use
00262     template< typename F,
00263             class From = typename boost::mpl::begin< boost::function_types::parameter_types<typename signature<F>::type> >::type,
00264             class To   = typename boost::mpl::end< boost::function_types::parameter_types<typename signature<F>::type> >::type>
00265     struct invoker
00266     {
00267         // add an argument to a Fusion cons-list for each parameter type
00268         template<typename Args, typename ArgStream>
00269         static inline
00270             typename result_type<F>::type
00271             apply(F func, ArgStream & astream, Args const & args)
00272         {
00273             typedef typename remove_cv_ref<typename boost::mpl::deref<From>::type>::type arg_type;
00274             typedef typename boost::mpl::next<From>::type next_iter_type;
00275 
00276             return invoker<F, next_iter_type, To>::apply(
00277                     func, astream, boost::fusion::push_back(args, get_next_arg<arg_type>(astream)) );
00278         }
00279     };
00280 
00281     // specialize final case
00282     template<typename F, class To>
00283     struct invoker<F,To,To>
00284     {
00285         template<typename Args, typename ArgStream>
00286         static inline
00287         typename result_type<F>::type
00288         apply(F func, ArgStream &, Args const & args)
00289         {
00290             return boost::fusion::invoke(func, args);
00291         }
00292     };
00293 
00294 } // detail
00295 
00296 
00304 template <typename F, typename ArgStream>
00305 typename result_type<F>::type
00306     call(F f, ArgStream & astream)
00307 {
00308     return detail::invoker<F>::template apply(f, astream, boost::fusion::nil());
00309 }
00310 
00316 template <class T, typename F, typename ArgStream>
00317 typename result_type<F>::type
00318     call(T * that, F f, ArgStream & astream)
00319 {
00320     // object gets pushed on as first arg of fusion list,
00321     // and remove first arg from signature (the object that the member function belongs to) using mpl::next
00322     boost::fusion::nil  args;
00323     return detail::invoker<F,
00324         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,
00325         typename boost::mpl::end< boost::function_types::parameter_types<typename signature<F>::type, boost::add_pointer<boost::mpl::placeholders::_> > >::type>
00326             ::template apply(f, astream, boost::fusion::push_back(args, that));
00327 }
00328 
00329 
00338 template <typename ArgStreamFirst, typename ArgStreamSecond>
00339 struct chain
00340 {
00341     template <class ArgStream>
00342     bool eof(ArgStream * as)
00343     {
00344         return detail::eof_check(as);
00345     }
00346 
00347     typedef ArgStreamFirst first_type;
00348     typedef ArgStreamSecond second_type;
00349     ArgStreamFirst * first;
00350     ArgStreamSecond * second;
00351 
00352     chain(ArgStreamFirst & first_stream, ArgStreamSecond & second_stream)
00353         :
00354         first(&first_stream),
00355         second(&second_stream)
00356     {
00357     }
00358 
00359     template <typename T>
00360     T get_next_arg()
00361     {
00362         if (!eof(first))
00363         {
00364             try
00365             {
00366                 return first->get_next_arg<T>();
00367             }
00368             catch(arg_stream::no_more_args &)
00369             {
00370                 first = 0;
00371             }
00372         }
00373 
00374         return second->get_next_arg<T>();
00375     }
00376 
00377     bool eof() const
00378     {
00379         return eof(first) && eof(second);
00380     }
00381 };
00382 
00383 template <typename S1, typename S2>
00384 struct traits<chain<S1, S2> >
00385 {
00386     static const bool has_eof_memberfunction = true;
00387 };
00388 
00392 template <typename ArgStreamFirst, typename ArgStreamSecond>
00393 chain<ArgStreamFirst, ArgStreamSecond> make_chain(ArgStreamFirst & first_stream, ArgStreamSecond & second_stream)
00394 {
00395     return chain<ArgStreamFirst, ArgStreamSecond>(first_stream, second_stream);
00396 }
00397 
00401 struct nonarg
00402 {
00403     bool eof()
00404     {
00405         return true;
00406     }
00407 
00408     template <typename R>
00409     R get_next_arg()
00410     {
00411         throw arg_stream::no_more_args();
00412 
00413         return *(R*)32;  // some compilers need a return; here's a bad one (but that doesn't require default construction)
00414     }
00415 };
00416 
00417 template<>
00418 struct traits<nonarg>
00419 {
00420     static const bool has_eof_memberfunction = true;
00421 };
00422 
00427 template <typename T>
00428 struct single
00429 {
00430     typedef T value_type;
00431 
00432     T value;
00433     unsigned int repeat;  // yep, unsigned.
00434 
00435     single(typename boost::add_reference<T const>::type t, unsigned int count = 1) : value(t), repeat(count)
00436     {
00437     }
00438 
00439     bool eof()
00440     {
00441         return repeat == 0;
00442     }
00443 
00444     template <typename R>
00445     R convert_or_throw(value_type & value, typename boost::enable_if<boost::is_convertible<value_type, R> >::type * dummy = 0)
00446     {
00447         return R(value);
00448     }
00449     template <typename R>
00450     R convert_or_throw(value_type & value, typename boost::disable_if<boost::is_convertible<value_type, R> >::type * dummy = 0)
00451     {
00452         throw adobe::bad_cast();
00453         return *(R*)value;
00454     }
00455 
00456     template <typename R>
00457     R get_next_arg()
00458     {
00459         if (repeat)
00460         {
00461             repeat--;
00462         }
00463         else
00464         {
00465             throw arg_stream::no_more_args();
00466         }
00467 
00468         return convert_or_throw<R>(value);
00469     }
00470 };
00471 
00472 template<typename T>
00473 struct traits<single<T> >
00474 {
00475     static const bool has_eof_memberfunction = true;
00476 };
00477 
00478 template <typename ArgStream, typename Transformer>
00479 struct with_transform
00480 {
00481     ADOBE_HAS_TEMPLATE1_IMPL(arg_stream_inverse_lookup);
00482 
00483     template <typename Class>
00484     struct has_inverse_lookup
00485     {
00486         static const bool value = ADOBE_HAS_TEMPLATE1(Class, arg_stream_inverse_lookup);
00487     };
00488 
00489     template <typename Class, typename R, bool>
00490     struct has_entry_if_has_inverse_lookup
00491     {
00492         static const bool value = false;
00493     };
00494     template <typename Class, typename R>
00495     struct has_entry_if_has_inverse_lookup<Class, R, true>
00496     {
00497         static const bool value = has_type_type<typename Class::template arg_stream_inverse_lookup<R> >::value;
00498     };
00499 
00500     template <typename Class, typename R>
00501     struct has_transform
00502     {
00503         static const bool value = has_entry_if_has_inverse_lookup<Class, R, has_inverse_lookup<Class>::value>::value;
00504     };
00505 
00506     typedef ArgStream value_type;
00507     typedef ArgStream arg_stream_type;
00508     typedef Transformer transformer_type;
00509 
00510     ArgStream & argstream;
00511     Transformer & transformer;
00512 
00513     with_transform(ArgStream & as, Transformer & trans) : argstream(as), transformer(trans)
00514     {
00515     }
00516 
00517     bool eof()
00518     {
00519         return detail::eof_check(argstream);
00520     }
00521 
00522     template <typename R>
00523     R transforming_get(typename boost::enable_if<has_transform<Transformer, R> >::type * dummy = 0)
00524     {
00525         typedef typename Transformer::template arg_stream_inverse_lookup<R>::type Rfrom;
00526         return transformer.template arg_stream_transform<R>(arg_stream::get_next_arg<Rfrom>(argstream));
00527     }
00528     template <typename R>
00529     R transforming_get(typename boost::disable_if<has_transform<Transformer, R> >::type * dummy = 0)
00530     {
00531         return arg_stream::get_next_arg<R>(argstream);
00532     }
00533 
00534     template <typename R>
00535     R get_next_arg()
00536     {
00537         return transforming_get<R>();
00538     }
00539 };
00540 
00541 template <typename ArgStream, typename Transformer>
00542 with_transform<ArgStream, Transformer> make_transforming(ArgStream & as, Transformer & transformer)
00543 {
00544     return with_transform<ArgStream, Transformer>(as, transformer);
00545 }
00546 
00547 } // namespace arg_stream
00548 } // namespace adobe
00549 
00550 
00551 #endif // include_guard

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