Adobe Source Libraries 1.49.0
A collection of C++ libraries.
Loading...
Searching...
No Matches
arg_stream.hpp
Go to the documentation of this file.
1/*
2 Copyright 2013 Adobe
3 Distributed under the Boost Software License, Version 1.0.
4 (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
5*/
6#ifndef ADOBE_ARG_STREAM_H
7#define ADOBE_ARG_STREAM_H
8
9#include <boost/function_types/function_arity.hpp>
10#include <boost/function_types/function_type.hpp>
11#include <boost/function_types/result_type.hpp>
12
13#include <boost/mpl/begin.hpp>
14#include <boost/mpl/deref.hpp>
15#include <boost/mpl/end.hpp>
16#include <boost/mpl/next.hpp>
17
18// Apple sucks
19#ifdef nil
20#undef nil
21#endif
22
23#include <boost/fusion/include/cons.hpp>
24#include <boost/fusion/include/invoke.hpp>
25#include <boost/fusion/include/push_back.hpp>
26
27#include <boost/utility/enable_if.hpp>
28
29#include <adobe/type_inspection.hpp> // ADOBE_HAS_TYPE/ADOBE_HAS_MEMBER
30
31#include <functional>
32
33namespace adobe {
34
73
74namespace arg_stream {
75
76
82struct no_more_args : std::exception {};
83
84
85namespace detail {
87
88template <typename T>
89struct has_eof_member {
90 static const bool value = ADOBE_HAS_TYPE(T, eof);
91};
92} // namespace detail
93
105template <typename T>
106struct traits {
107 static const bool has_eof_member = detail::has_eof_member<T>::value;
108};
109
110
111namespace detail {
112template <class ArgStream>
113static bool
114eof_check(ArgStream& as,
115 typename boost::enable_if_c<traits<ArgStream>::has_eof_memberfunction>::type* dummy = 0) {
116 return as.eof();
117}
118
119template <class ArgStream>
120static bool eof_check(
121 ArgStream& as,
122 typename boost::disable_if_c<traits<ArgStream>::has_eof_memberfunction>::type* dummy = 0) {
123 return false;
124}
125
126template <class ArgStream>
127static bool eof_check(ArgStream* as) {
128 return as ? eof_check(*as) : true;
129}
130} // namespace detail
131
147template <typename ArgStream>
148bool eof(ArgStream const& as) {
149 return detail::eof_check(as);
150}
151
166template <typename R, typename ArgStream>
167R get_next_arg(ArgStream const& as) {
168 return as.get_next_arg<R>();
169}
170// specialize these or let them fallback to the above specialization
171template <typename R, typename ArgStream>
172R get_next_arg(ArgStream& as) {
173 return as.get_next_arg<R>();
174}
175template <typename R, typename ArgStream>
176R get_next_arg(ArgStream* as) {
177 return get_next_arg<R>(*as);
178}
179template <typename R, typename ArgStream>
180R get_next_arg(ArgStream const* as) {
181 return get_next_arg<R>(*as);
182}
183
184
192template <typename F>
193struct signature {
194 typedef F type;
195};
196// specialize for std::function
197template <typename F>
198struct signature<std::function<F>> {
199 typedef F type;
200};
201
210template <typename F>
212 typedef typename boost::function_types::result_type<typename signature<F>::type>::type type;
213};
214
215namespace detail {
216// how it all works...
217
218
219template <typename T>
220struct remove_cv_ref : boost::remove_cv<typename boost::remove_reference<T>::type> {};
221
222
223// see also boost::function_types 'interpreter' example
224// we convert the function signature into a mpl sequence (it *is* an mpl sequence, since it
225// implements mpl::begin/end/etc)
226// we recursively push the args onto a fusion sequence, calling get_next_arg as we go.
227// the recursion ends when we get to the end of the mpl-sequence-function-sigature
228// (see the specialized case where From == To)
229// and then luckily fusion has a magic invoke function we can use
230template <typename F,
231 class From = typename boost::mpl::begin<
232 boost::function_types::parameter_types<typename signature<F>::type>>::type,
233 class To = typename boost::mpl::end<
234 boost::function_types::parameter_types<typename signature<F>::type>>::type>
235struct invoker {
236 // add an argument to a Fusion cons-list for each parameter type
237 template <typename Args, typename ArgStream>
238 static inline typename result_type<F>::type apply(F func, ArgStream& astream,
239 Args const& args) {
240 typedef typename remove_cv_ref<typename boost::mpl::deref<From>::type>::type arg_type;
241 typedef typename boost::mpl::next<From>::type next_iter_type;
242
243 return invoker<F, next_iter_type, To>::apply(
244 func, astream, boost::fusion::push_back(args, get_next_arg<arg_type>(astream)));
245 }
246};
247
248// specialize final case
249template <typename F, class To>
250struct invoker<F, To, To> {
251 template <typename Args, typename ArgStream>
252 static inline typename result_type<F>::type apply(F func, ArgStream&, Args const& args) {
253 return boost::fusion::invoke(func, args);
254 }
255};
256
257} // namespace detail
258
259
268template <typename F, typename ArgStream>
269typename result_type<F>::type call(F f, ArgStream& astream) {
270 return detail::invoker<F>::template apply(f, astream, boost::fusion::nil());
271}
272
278template <class T, typename F, typename ArgStream>
279typename result_type<F>::type call(T* that, F f, ArgStream& astream) {
280 // object gets pushed on as first arg of fusion list,
281 // and remove first arg from signature (the object that the member function belongs to)
282 // using
283 // mpl::next
284 boost::fusion::nil args;
285 return detail::invoker<
286 F,
287 typename boost::mpl::next<typename boost::mpl::begin<boost::function_types::parameter_types<
288 typename signature<F>::type, boost::add_pointer<boost::mpl::placeholders::_>>>::type>::
289 type,
290 typename boost::mpl::end<boost::function_types::parameter_types<
291 typename signature<F>::type, boost::add_pointer<boost::mpl::placeholders::_>>>::type>::
292 template apply(f, astream, boost::fusion::push_back(args, that));
293}
294
295
305template <typename ArgStreamFirst, typename ArgStreamSecond>
306struct chain {
307 template <class ArgStream>
308 bool eof(ArgStream* as) {
309 return detail::eof_check(as);
310 }
311
312 typedef ArgStreamFirst first_type;
313 typedef ArgStreamSecond second_type;
314 ArgStreamFirst* first;
315 ArgStreamSecond* second;
316
317 chain(ArgStreamFirst& first_stream, ArgStreamSecond& second_stream)
318 : first(&first_stream), second(&second_stream) {}
319
320 template <typename T>
322 if (!eof(first)) {
323 try {
324 return first->get_next_arg<T>();
325 } catch (arg_stream::no_more_args&) {
326 first = 0;
327 }
328 }
329
330 return second->get_next_arg<T>();
331 }
332
333 bool eof() const { return eof(first) && eof(second); }
334};
335
336template <typename S1, typename S2>
337struct traits<chain<S1, S2>> {
338 static const bool has_eof_memberfunction = true;
339};
340
344template <typename ArgStreamFirst, typename ArgStreamSecond>
346 ArgStreamSecond& second_stream) {
347 return chain<ArgStreamFirst, ArgStreamSecond>(first_stream, second_stream);
348}
349
353struct nonarg {
354 bool eof() { return true; }
355
356 template <typename R>
359
360 return *(R*)32; // some compilers need a return; here's a bad one (but that doesn't require
361 // default construction)
362 }
363};
364
365template <>
366struct traits<nonarg> {
367 static const bool has_eof_memberfunction = true;
368};
369
376template <typename T>
377struct single {
378 typedef T value_type;
379
381 unsigned int repeat; // yep, unsigned.
382
383 single(typename boost::add_reference<T const>::type t, unsigned int count = 1)
384 : value(t), repeat(count) {}
385
386 bool eof() { return repeat == 0; }
387
388 template <typename R>
391 typename boost::enable_if<boost::is_convertible<value_type, R>>::type* dummy = 0) {
392 return R(value);
393 }
394 template <typename R>
397 typename boost::disable_if<boost::is_convertible<value_type, R>>::type* dummy = 0) {
398 throw adobe::bad_cast();
399 return *(R*)value;
400 }
401
402 template <typename R>
404 if (repeat) {
405 repeat--;
406 } else {
408 }
409
411 }
412};
413
414template <typename T>
415struct traits<single<T>> {
416 static const bool has_eof_memberfunction = true;
417};
418
419template <typename ArgStream, typename Transformer>
421 ADOBE_HAS_TEMPLATE1_IMPL(arg_stream_inverse_lookup);
422
423 template <typename Class>
425 static const bool value = ADOBE_HAS_TEMPLATE1(Class, arg_stream_inverse_lookup);
426 };
427
428 template <typename Class, typename R, bool>
430 static const bool value = false;
431 };
432 template <typename Class, typename R>
437
438 template <typename Class, typename R>
443
444 typedef ArgStream value_type;
445 typedef ArgStream arg_stream_type;
446 typedef Transformer transformer_type;
447
448 ArgStream& argstream;
449 Transformer& transformer;
450
451 with_transform(ArgStream& as, Transformer& trans) : argstream(as), transformer(trans) {}
452
453 bool eof() { return detail::eof_check(argstream); }
454
455 template <typename R>
456 R transforming_get(typename boost::enable_if<has_transform<Transformer, R>>::type* dummy = 0) {
457 typedef typename Transformer::template arg_stream_inverse_lookup<R>::type Rfrom;
458 return transformer.template arg_stream_transform<R>(
460 }
461 template <typename R>
462 R transforming_get(typename boost::disable_if<has_transform<Transformer, R>>::type* dummy = 0) {
464 }
465
466 template <typename R>
468 return transforming_get<R>();
469 }
470};
471
472template <typename ArgStream, typename Transformer>
473with_transform<ArgStream, Transformer> make_transforming(ArgStream& as, Transformer& transformer) {
474 return with_transform<ArgStream, Transformer>(as, transformer);
475}
476
477} // namespace arg_stream
478} // namespace adobe
479
480
481#endif // include_guard
An exception class thrown during ASL failures to cast.
Definition typeinfo.hpp:33
R get_next_arg(ArgStream const &as)
arg_stream::get_next_arg<T>(argstream) returns the next arg as a T
result_type< F >::type call(F f, ArgStream &astream)
Calls function/callable-object f with function arguments supplied by the arg_stream.
bool eof(ArgStream const &as)
arg_stream::eof(argstream) returns true if there are no more args available.
boost::range_difference< InputRange >::type count(InputRange &range, T &value)
count implementation
Definition count.hpp:40
#define ADOBE_HAS_TYPE_IMPL(TypeInQuestion)
Implementation part of ADOBE_HAS_TYPE macro. Required before using ADOBE_HAS_TYPE.
#define ADOBE_HAS_TYPE(C, TypeInQuestion)
returns true iff C has an internal type named 'TypeInQuestion'. ie returns true iff C::TypeInQuestion...
#define ADOBE_HAS_TEMPLATE1(C, TemplateInQuestion)
returns true iff C has an internal template named 'TemplateInQuestion' with 1 (nondefault) template p...
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
with_transform< ArgStream, Transformer > make_transforming(ArgStream &as, Transformer &transformer)
STL namespace.
chain 2 arg_streams together by calling the first stream until depleted, then calling the second.
ArgStreamFirst first_type
ArgStreamFirst * first
ArgStreamSecond second_type
ArgStreamSecond * second
bool eof(ArgStream *as)
chain(ArgStreamFirst &first_stream, ArgStreamSecond &second_stream)
the empty-set arg stream has no arguments. Not sure what this might be useful for.
result_type<F>::type is the return type of the function f.
boost::function_types::result_type< typenamesignature< F >::type >::type type
returns the function signature of the callable object type F
holds a single value, and returns it as an arg n (default 1) times
R convert_or_throw(value_type &value, typename boost::disable_if< boost::is_convertible< value_type, R > >::type *dummy=0)
single(typename boost::add_reference< T const >::type t, unsigned int count=1)
R convert_or_throw(value_type &value, typename boost::enable_if< boost::is_convertible< value_type, R > >::type *dummy=0)
defines any traits that help with the implementation of arg_stream::call() and/or helper objects like...
static const bool has_eof_member
static const bool value
static const bool value
R transforming_get(typename boost::enable_if< has_transform< Transformer, R > >::type *dummy=0)
with_transform(ArgStream &as, Transformer &trans)
R transforming_get(typename boost::disable_if< has_transform< Transformer, R > >::type *dummy=0)
ADOBE_HAS_TEMPLATE1_IMPL(arg_stream_inverse_lookup)
is T::type a valid type (or a compile error?)