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 |