FireBreath  1.4.0
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Pages
ConverterUtils.h
1 /**********************************************************\
2 Original Author: Georg Fritzsche
3 
4 Created: November 9, 2009
5 License: Dual license model; choose one of two:
6  New BSD License
7  http://www.opensource.org/licenses/bsd-license.php
8  - or -
9  GNU Lesser General Public License, version 2.1
10  http://www.gnu.org/licenses/lgpl-2.1.html
11 
12 Copyright 2009 Georg Fritzsche, Firebreath development team
13 \**********************************************************/
14 
15 #if !defined(CONVERTER_UTILS_H)
16 #define CONVERTER_UTILS_H
17 
18 #if defined(_MSC_VER)
19 # pragma once
20 #endif
21 
22 #include <boost/type_traits/remove_reference.hpp>
23 #include <boost/type_traits/remove_const.hpp>
24 #include <boost/mpl/contains.hpp>
25 #include <boost/mpl/vector.hpp>
26 
27 namespace FB {
28  class variant;
29  typedef std::vector<variant> VariantList;
30  namespace detail
31  {
32  // helper meta function that removes all pointers etc. from a type
33  template<typename T>
34  struct plain_type {
35  typedef typename boost::remove_const<typename boost::remove_reference<T>::type>::type type;
36  };
37 
38  // actual conversion functions are wrapped in this struct to allow partial specialization
39  template<typename To, typename From>
40  struct converter {
41  static inline To convert(const From& f);
42  static inline To convert(const From& f, size_t index);
43  };
44 
45  // helper functions for method calls
46  namespace methods
47  {
48  template<typename LastArgType>
49  inline
50  bool checkArgumentCount(const FB::VariantList& l, size_t n);
51 
52  template<typename ArgType>
53  inline
54  ArgType convertLastArgument(const FB::VariantList& l, size_t n);
55  }
56  } // namespace detail
57 
58  // "soft" conversion wrapper function
59  template<typename To>
60  inline
61  To convertArgumentSoft(const FB::VariantList& args, const size_t index,
62  typename boost::disable_if<boost::mpl::or_<
63  FB::meta::is_optional<To>,
64  boost::mpl::or_<
65  boost::is_same<To, FB::variant>,
66  boost::is_same<To, boost::tribool>
67  >
68  > >::type* p=0)
69  {
70  if (args.size() >= index)
71  return FB::detail::converter<To, FB::variant>::convert(args[index-1], index);
72  else {
73  std::stringstream ss;
74  ss << "Error: Argument " << index
75  << " is not optional.";
76  throw FB::invalid_arguments(ss.str());
77  }
78  }
79 
80  template<typename To>
81  inline
82  To convertArgumentSoft(const FB::VariantList& args, const size_t index,
83  typename boost::enable_if<FB::meta::is_optional<To> >::type* p=0)
84  {
85  if (args.size() >= index)
86  return FB::detail::converter<To, FB::variant>::convert(args[index-1], index);
87  else
88  return To(); // Empty optional argument
89  }
90 
91  template<typename To>
92  inline
93  To convertArgumentSoft(const FB::VariantList& args, const size_t index,
94  typename boost::enable_if<boost::is_same<To, boost::tribool> >::type* p=0)
95  {
96  if (args.size() >= index)
97  return FB::detail::converter<To, FB::variant>::convert(args[index-1], index);
98  else
99  return boost::tribool(); // Empty variant argument
100  }
101 
102  template<typename To>
103  inline
104  To convertArgumentSoft(const FB::VariantList& args, const size_t index,
105  typename boost::enable_if<boost::is_same<To, FB::variant> >::type* p=0)
106  {
107  if (args.size() >= index)
108  return FB::detail::converter<To, FB::variant>::convert(args[index-1], index);
109  else
110  return FB::variant(); // Empty variant argument
111  }
112  // conversion wrapper function
113  template<typename To, typename From>
114  inline
115  To convertArgument(const From& from)
116  {
117  return FB::detail::converter<To, From>::convert(from);
118  }
119 
120  // conversion wrapper function
121  template<typename To, typename From>
122  inline
123  To convertArgument(const From& from, const size_t index, boost::disable_if< FB::meta::is_optional<To> >*p = 0)
124  {
125  return FB::detail::converter<To, From>::convert(from, index);
126  }
127 } // namespace FB
128 
129 namespace FB { namespace detail
130 {
131  // specialization of converter for conversions from FB::variant
132  template<typename To>
133  struct converter<To, FB::variant>
134  {
135  static inline To convert(const FB::variant& from)
136  {
137  try {
138  return from.convert_cast<To>();
139  } catch(const FB::bad_variant_cast& e) {
140  std::stringstream ss;
141  ss << "Invalid argument conversion "
142  << "from " << e.from
143  << " to " << e.to;
144  throw FB::invalid_arguments(ss.str());
145  }
146  }
147 
148  static inline To convert(const FB::variant& from, size_t index)
149  {
150  try {
151  return from.convert_cast<To>();
152  } catch(const FB::bad_variant_cast& e) {
153  std::stringstream ss;
154  ss << "Invalid argument conversion "
155  << "from " << e.from
156  << " to " << e.to
157  << " at index " << index;
158  throw FB::invalid_arguments(ss.str());
159  }
160  }
161  };
162 
163  // specialization for conversion from variant to variant
164  template<>
165  struct converter<FB::variant, FB::variant>
166  {
167  static inline FB::variant convert(const FB::variant& from)
168  {
169  return from;
170  }
171 
172  static inline FB::variant convert(const FB::variant& from, size_t index)
173  {
174  return from;
175  }
176  };
177 
178  namespace methods
179  {
180  // checking argument count if last arg isn't a catch-all type
181  template<typename LastArgType>
182  inline
183  bool checkArgumentCount(const FB::VariantList& l, size_t n)
184  {
185  if(l.size() != n) {
186  std::stringstream ss;
187  ss << "Invalid Argument Count, expected " << n << " arguments";
188  throw FB::invalid_arguments(ss.str());
189  }
190 
191  return true;
192  }
193 
194  // if the last argument is a catch-all type, we only have a lower bound
195  template<>
196  inline
197  bool checkArgumentCount<FB::CatchAll>(const FB::VariantList& l, size_t n)
198  {
199  if(l.size() < (n-1)) {
200  std::stringstream ss;
201  ss << "Invalid Argument Count, expected at least " << (n-1) << " arguments";
202  throw FB::invalid_arguments(ss.str());
203  }
204 
205  return true;
206  }
207 
208  // default handling for the last parameter is just converting
209  template<typename ArgType>
210  inline
211  ArgType convertLastArgument(const FB::VariantList& l, size_t n)
212  {
213  // If this is the last parameter and
214  if (l.size() > n) {
215  std::stringstream ss;
216  ss << "Too many arguments, expected " << n << ".";
217  throw FB::invalid_arguments(ss.str());
218  }
219  return FB::convertArgumentSoft<ArgType>(l, n);
220  }
221 
222  // if the last argument is CatchAll, fill it with all remaining parameters
223  template<>
224  inline
225  FB::CatchAll convertLastArgument<FB::CatchAll>(const FB::VariantList& l, size_t n)
226  {
227  FB::CatchAll result;
228  long count = (long)l.size() - ((long)n - 1);
229  if(count < 1)
230  return result;
231  for( ; n <= l.size(); ++n)
232  result.value.push_back(l[n-1]);
233  return result;
234  }
235  } // namespace methods
236 } } // namespace FB { namespace detail
237 
238 #endif // #if !defined(CONVERTER_UTILS_H)
239 
const T convert_cast() const
Converts the stored value to the requested type if possible and returns the resulting value...
Definition: variant.h:667
Accepts any datatype, used in all interactions with javascript. Provides tools for getting back out t...
Definition: variant.h:198
Thrown by a JSAPI object when the argument(s) provided to a SetProperty or Invoke call are found to b...
Definition: JSExceptions.h:47
std::vector< variant > VariantList
Defines an alias representing list of variants.
Definition: APITypes.h:64
Thrown when variant::cast<type> or variant::convert_cast<type> fails because the type of the value st...
Definition: variant.h:133
When used as a parameter on a JSAPIAuto function this matches 0 or more variants – in other words...
Definition: APITypes.h:208