All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
parserHelpers.h
1 //
2 // Copyright 2016 Pixar
3 //
4 // Licensed under the Apache License, Version 2.0 (the "Apache License")
5 // with the following modification; you may not use this file except in
6 // compliance with the Apache License and the following modification to it:
7 // Section 6. Trademarks. is deleted and replaced with:
8 //
9 // 6. Trademarks. This License does not grant permission to use the trade
10 // names, trademarks, service marks, or product names of the Licensor
11 // and its affiliates, except as required to comply with Section 4(c) of
12 // the License and to reproduce the content of the NOTICE file.
13 //
14 // You may obtain a copy of the Apache License at
15 //
16 // http://www.apache.org/licenses/LICENSE-2.0
17 //
18 // Unless required by applicable law or agreed to in writing, software
19 // distributed under the Apache License with the above modification is
20 // distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
21 // KIND, either express or implied. See the Apache License for the specific
22 // language governing permissions and limitations under the Apache License.
23 //
24 #ifndef PXR_USD_SDF_PARSER_HELPERS_H
25 #define PXR_USD_SDF_PARSER_HELPERS_H
26 
27 #include "pxr/pxr.h"
28 #include "pxr/usd/sdf/types.h"
29 #include "pxr/base/arch/inttypes.h"
30 
31 #include <boost/numeric/conversion/cast.hpp>
32 #include <boost/type_traits/is_floating_point.hpp>
33 #include <boost/type_traits/is_integral.hpp>
34 #include <boost/type_traits/is_signed.hpp>
35 #include <boost/utility/enable_if.hpp>
36 #include <boost/variant.hpp>
37 
38 #include <climits>
39 #include <functional>
40 #include <limits>
41 #include <map>
42 #include <string>
43 #include <vector>
44 
45 PXR_NAMESPACE_OPEN_SCOPE
46 
47 bool Sdf_BoolFromString(const std::string &, bool *parseOk);
48 
49 namespace Sdf_ParserHelpers {
50 
51 using boost::variant;
52 
53 using std::string;
54 using std::vector;
55 using std::map;
56 
57 // Internal variant type.
58 typedef boost::variant<uint64_t, int64_t, double,
59  std::string, TfToken, SdfAssetPath> _Variant;
60 
62 // Utilities that implement the Sdf_ParserHelpers::Value::Get<T>() method. The
63 // _GetImpl<T> class template provides the right implementation for T. There
64 // are several partial specializations that provide the right behavior for
65 // various types.
66 
67 // General Get case, requires exact match.
68 template <class T, class Enable = void>
69 struct _GetImpl
70 {
71  typedef const T &ResultType;
72  static const T &Visit(_Variant const &variant) {
73  return boost::get<T>(variant);
74  }
75 };
76 
78 // _GetImpl<T> for integral type T. Convert finite doubles by static_cast,
79 // throw bad_get for non-finite doubles. Throw bad_get for out-of-range
80 // integral values.
81 template <class T>
82 struct _GetImpl<
83  T, typename boost::enable_if<boost::is_integral<T> >::type>
84  : public boost::static_visitor<T>
85 {
86  typedef T ResultType;
87 
88  T Visit(_Variant const &variant) {
89  return boost::apply_visitor(*this, variant);
90  }
91 
92  // Fallback case: throw bad_get.
93  template <class Held>
94  T operator()(Held held) { throw boost::bad_get(); }
95 
96  // Attempt to cast unsigned and signed int64_t.
97  T operator()(uint64_t in) { return _Cast(in); }
98  T operator()(int64_t in) { return _Cast(in); }
99 
100  // Attempt to cast finite doubles, throw otherwise.
101  T operator()(double in) {
102  if (std::isfinite(in))
103  return _Cast(in);
104  throw boost::bad_get();
105  }
106 
107 private:
108  template <class In>
109  T _Cast(In in) {
110  try {
111  return boost::numeric_cast<T>(in);
112  } catch (const boost::bad_numeric_cast &) {
113  throw boost::bad_get();
114  }
115  }
116 };
118 
120 // _GetImpl<T> for floating point type T. Attempts to cast numeric values.
121 // Also handles strings like "inf", "-inf", and "nan" to produce +/- infinity
122 // and a quiet NaN.
123 template <class T>
124 struct _GetImpl<
125  T, typename boost::enable_if<boost::is_floating_point<T> >::type>
126  : public boost::static_visitor<T>
127 {
128  typedef T ResultType;
129 
130  T Visit(_Variant const &variant) {
131  return boost::apply_visitor(*this, variant);
132  }
133 
134  // Fallback case: throw bad_get.
135  template <class Held>
136  T operator()(Held held) { throw boost::bad_get(); }
137 
138  // For numeric types, attempt to cast.
139  T operator()(uint64_t in) { return _Cast(in); }
140  T operator()(int64_t in) { return _Cast(in); }
141  T operator()(double in) { return static_cast<T>(in); }
142 
143  // Convert special strings if possible.
144  T operator()(const std::string &str) { return _FromString(str); }
145  T operator()(const TfToken &tok) { return _FromString(tok.GetString()); }
146 
147 private:
148  T _FromString(const std::string &str) const {
149  // Special case the strings 'inf', '-inf' and 'nan'.
150  if (str == "inf")
151  return std::numeric_limits<T>::infinity();
152  if (str == "-inf")
153  return -std::numeric_limits<T>::infinity();
154  if (str == "nan")
155  return std::numeric_limits<T>::quiet_NaN();
156  throw boost::bad_get();
157  }
158 
159  template <class In>
160  T _Cast(In in) {
161  try {
162  return boost::numeric_cast<T>(in);
163  } catch (const boost::bad_numeric_cast &) {
164  throw boost::bad_get();
165  }
166  }
167 };
168 
169 
171 
172 // Get an asset path: converts string to asset path, otherwise throw bad_get.
173 template <>
174 struct _GetImpl<SdfAssetPath>
175 {
176  typedef SdfAssetPath ResultType;
177 
178  SdfAssetPath Visit(_Variant const &variant) {
179  if (std::string const *str = boost::get<std::string>(&variant))
180  return SdfAssetPath(*str);
181  return boost::get<SdfAssetPath>(variant);
182  }
183 };
184 
185 // Get a bool. Numbers are considered true if nonzero, false otherwise.
186 // Strings and tokens get parsed via Sdf_BoolFromString. Otherwise throw
187 // bad_get.
188 template <>
189 struct _GetImpl<bool> : public boost::static_visitor<bool>
190 {
191  typedef bool ResultType;
192 
193  bool Visit(_Variant const &variant) {
194  return boost::apply_visitor(*this, variant);
195  }
196 
197  // Parse string via Sdf_BoolFromString.
198  bool operator()(const std::string &str) {
199  bool parseOK = false;
200  bool result = Sdf_BoolFromString(str, &parseOK);
201  if (!parseOK)
202  throw boost::bad_get();
203  return result;
204  }
205 
206  // Treat tokens as strings.
207  bool operator()(const TfToken &tok) { return (*this)(tok.GetString()); }
208 
209  // For numbers, return true if not zero.
210  template <class Number>
211  typename boost::enable_if<boost::is_arithmetic<Number>, bool>::type
212  operator()(Number val) {
213  return val != static_cast<Number>(0);
214  }
215 
216  // For anything else, throw bad_get().
217  template <class T>
218  typename boost::disable_if<boost::is_arithmetic<T>, bool>::type
219  operator()(T) { throw boost::bad_get(); }
220 };
221 
222 // A parser value. This is used as the fundamental value object in the text
223 // parser. It can hold one of a few different types: (u)int64_t, double,
224 // string, TfToken, and SdfAssetPath. The lexer only ever produces Value
225 // objects holding (u)int64_t, double, and string. The presence of TfToken and
226 // SdfAssetPath here are for a relatively obscure case where we're parsing a
227 // value whose type is unknown to the parser. See
228 // StartRecordingString/StopRecordingString/IsRecordingString in
229 // parserValueContext.{cpp.h}. We'd like to change this.
230 //
231 // Value's primary function is to provide a Get<T>() convenience API that
232 // handles appropriate conversions from the held types. For example, it is okay
233 // to call Get<float>() on a Value that's holding an integral type, a double, or
234 // a string if that string's value is one of 'inf', '-inf', or 'nan'. Similarly
235 // Get<bool>() works on numbers and strings like 'yes', 'no', 'on', 'off',
236 // 'true', 'false'. If a Get<T>() call fails, it throws boost::bad_get, which
237 // the parser responds to and raises a parse error.
238 //
239 // The lexer constructs Value objects from input tokens. It creates them to
240 // retain all the input information possible. For example, negative integers
241 // are stored as int64_t Values, positive numbers are stored as uint64_t values,
242 // and so on. As a special case of this, '-0' is stored as a double, since it
243 // is the only way to preserve a signed zero (integral types have no signed
244 // zero).
245 struct Value
246 {
247  // Default constructor leaves the value in an undefined state.
248  Value() {}
249 
250  // Construct and implicitly convert from an integral type \p Int. If \p Int
251  // is signed, the resulting value holds an 'int64_t' internally. If \p Int
252  // is unsigned, the result value holds an 'uint64_t'.
253  template <class Int>
254  Value(Int in, typename boost::enable_if<
255  boost::is_integral<Int> >::type * = 0) {
256  if (boost::is_signed<Int>::value) {
257  _variant = static_cast<int64_t>(in);
258  } else {
259  _variant = static_cast<uint64_t>(in);
260  }
261  }
262 
263  // Construct and implicitly convert from a floating point type \p Flt. The
264  // resulting value holds a double internally.
265  template <class Flt>
266  Value(Flt in, typename boost::enable_if<
267  boost::is_floating_point<Flt> >::type * = 0) :
268  _variant(static_cast<double>(in)) {}
269 
270  // Construct and implicitly convert from std::string.
271  Value(const std::string &in) : _variant(in) {}
272 
273  // Construct and implicitly convert from TfToken.
274  Value(const TfToken &in) : _variant(in) {}
275 
276  // Construct and implicitly convert from SdfAssetPath.
277  Value(const SdfAssetPath &in) : _variant(in) {}
278 
279  // Attempt to get a value of type T from this Value, applying appropriate
280  // conversions. If this value cannot be converted to T, throw
281  // boost::bad_get.
282  template <class T>
283  typename _GetImpl<T>::ResultType Get() const {
284  return _GetImpl<T>().Visit(_variant);
285  }
286 
287  // Hopefully short-lived API that applies an external visitor to the held
288  // variant type.
289  template <class Visitor>
290  typename Visitor::result_type
291  ApplyVisitor(const Visitor &visitor) {
292  return boost::apply_visitor(visitor, _variant);
293  }
294 
295  template <class Visitor>
296  typename Visitor::result_type
297  ApplyVisitor(Visitor &visitor) {
298  return boost::apply_visitor(visitor, _variant);
299  }
300 
301  template <class Visitor>
302  typename Visitor::result_type
303  ApplyVisitor(const Visitor &visitor) const {
304  return _variant.apply_visitor(visitor);
305  }
306 
307  template <class Visitor>
308  typename Visitor::result_type
309  ApplyVisitor(Visitor &visitor) const {
310  return _variant.apply_visitor(visitor);
311  }
312 
313 private:
314  _Variant _variant;
315 };
316 
317 typedef std::function<VtValue (vector<unsigned int> const &,
318  vector<Value> const &,
319  size_t &, string *)> ValueFactoryFunc;
320 
321 struct ValueFactory {
322  ValueFactory() {}
323 
324  ValueFactory(std::string typeName_, SdfTupleDimensions dimensions_,
325  bool isShaped_, ValueFactoryFunc func_)
326  : typeName(typeName_),
327  dimensions(dimensions_),
328  isShaped(isShaped_),
329  func(func_) {}
330 
331  std::string typeName;
332  SdfTupleDimensions dimensions;
333  bool isShaped;
334  ValueFactoryFunc func;
335 };
336 
337 ValueFactory const &GetValueFactoryForMenvaName(std::string const &name,
338  bool *found);
339 };
340 
347 bool Sdf_BoolFromString(const std::string &s, bool *parseOk = NULL);
348 
349 // Read the quoted string at [x..x+n], trimming 'trimBothSides' number
350 // of chars from either side, and evaluating any embedded escaped characters.
351 // If numLines is given, it will be populated with the number of newline
352 // characters present in the original string.
353 std::string Sdf_EvalQuotedString(const char* x, size_t n, size_t trimBothSides,
354  unsigned int* numLines = NULL);
355 
356 // Read the string representing an asset path at [x..x+n]. If tripleDelimited
357 // is true, the string is assumed to have 3 delimiters on both sides of the
358 // asset path, otherwise the string is assumed to have just 1.
359 std::string Sdf_EvalAssetPath(const char* x, size_t n, bool tripleDelimited);
360 
361 PXR_NAMESPACE_CLOSE_SCOPE
362 
363 #endif // PXR_USD_SDF_PARSER_HELPERS_H
std::string const & GetString() const
Return the string that this token represents.
Definition: token.h:209
Token for efficient comparison, assignment, and hashing of known strings.
Definition: token.h:89
Contains an asset path and an optional resolved path.
Definition: assetPath.h:43
Represents the shape of a value type (or that of an element in an array).
Definition: valueTypeName.h:46