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 SDF_PARSER_HELPERS_H
25 #define 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 namespace Sdf_ParserHelpers {
48 
49 using boost::variant;
50 
51 using std::string;
52 using std::vector;
53 using std::map;
54 
55 // Internal variant type.
56 typedef boost::variant<uint64_t, int64_t, double,
57  std::string, TfToken, SdfAssetPath> _Variant;
58 
60 // Utilities that implement the Sdf_ParserHelpers::Value::Get<T>() method. The
61 // _GetImpl<T> class template provides the right implementation for T. There
62 // are several partial specializations that provide the right behavior for
63 // various types.
64 
65 // General Get case, requires exact match.
66 template <class T, class Enable = void>
67 struct _GetImpl
68 {
69  typedef const T &ResultType;
70  static const T &Visit(_Variant const &variant) {
71  return boost::get<T>(variant);
72  }
73 };
74 
76 // _GetImpl<T> for integral type T. Convert finite doubles by static_cast,
77 // throw bad_get for non-finite doubles. Throw bad_get for out-of-range
78 // integral values.
79 template <class T>
80 struct _GetImpl<
81  T, typename boost::enable_if<boost::is_integral<T> >::type>
82  : public boost::static_visitor<T>
83 {
84  typedef T ResultType;
85 
86  T Visit(_Variant const &variant) {
87  return boost::apply_visitor(*this, variant);
88  }
89 
90  // Fallback case: throw bad_get.
91  template <class Held>
92  T operator()(Held held) { throw boost::bad_get(); }
93 
94  // Attempt to cast unsigned and signed int64_t.
95  T operator()(uint64_t in) { return _Cast(in); }
96  T operator()(int64_t in) { return _Cast(in); }
97 
98  // Attempt to cast finite doubles, throw otherwise.
99  T operator()(double in) {
100  if (std::isfinite(in))
101  return _Cast(in);
102  throw boost::bad_get();
103  }
104 
105 private:
106  template <class In>
107  T _Cast(In in) {
108  try {
109  return boost::numeric_cast<T>(in);
110  } catch (const boost::bad_numeric_cast &) {
111  throw boost::bad_get();
112  }
113  }
114 };
116 
118 // _GetImpl<T> for floating point type T. Attempts to cast numeric values.
119 // Also handles strings like "inf", "-inf", and "nan" to produce +/- infinity
120 // and a quiet NaN.
121 template <class T>
122 struct _GetImpl<
123  T, typename boost::enable_if<boost::is_floating_point<T> >::type>
124  : public boost::static_visitor<T>
125 {
126  typedef T ResultType;
127 
128  T Visit(_Variant const &variant) {
129  return boost::apply_visitor(*this, variant);
130  }
131 
132  // Fallback case: throw bad_get.
133  template <class Held>
134  T operator()(Held held) { throw boost::bad_get(); }
135 
136  // For numeric types, attempt to cast.
137  T operator()(uint64_t in) { return _Cast(in); }
138  T operator()(int64_t in) { return _Cast(in); }
139  T operator()(double in) { return static_cast<T>(in); }
140 
141  // Convert special strings if possible.
142  T operator()(const std::string &str) { return _FromString(str); }
143  T operator()(const TfToken &tok) { return _FromString(tok.GetString()); }
144 
145 private:
146  T _FromString(const std::string &str) const {
147  // Special case the strings 'inf', '-inf' and 'nan'.
148  if (str == "inf")
149  return std::numeric_limits<T>::infinity();
150  if (str == "-inf")
151  return -std::numeric_limits<T>::infinity();
152  if (str == "nan")
153  return std::numeric_limits<T>::quiet_NaN();
154  throw boost::bad_get();
155  }
156 
157  template <class In>
158  T _Cast(In in) {
159  try {
160  return boost::numeric_cast<T>(in);
161  } catch (const boost::bad_numeric_cast &) {
162  throw boost::bad_get();
163  }
164  }
165 };
166 
167 
169 
170 // Get an asset path: converts string to asset path, otherwise throw bad_get.
171 template <>
172 struct _GetImpl<SdfAssetPath>
173 {
174  typedef SdfAssetPath ResultType;
175 
176  SdfAssetPath Visit(_Variant const &variant) {
177  if (std::string const *str = boost::get<std::string>(&variant))
178  return SdfAssetPath(*str);
179  return boost::get<SdfAssetPath>(variant);
180  }
181 };
182 
183 // Get a bool. Numbers are considered true if nonzero, false otherwise.
184 // Strings and tokens get parsed via SdfBoolFromString. Otherwise throw
185 // bad_get.
186 template <>
187 struct _GetImpl<bool> : public boost::static_visitor<bool>
188 {
189  typedef bool ResultType;
190 
191  bool Visit(_Variant const &variant) {
192  return boost::apply_visitor(*this, variant);
193  }
194 
195  // Parse string via SdfBoolFromString.
196  bool operator()(const std::string &str) {
197  bool parseOK = false;
198  bool result = SdfBoolFromString(str, &parseOK);
199  if (!parseOK)
200  throw boost::bad_get();
201  return result;
202  }
203 
204  // Treat tokens as strings.
205  bool operator()(const TfToken &tok) { return (*this)(tok.GetString()); }
206 
207  // For numbers, return true if not zero.
208  template <class Number>
209  typename boost::enable_if<boost::is_arithmetic<Number>, bool>::type
210  operator()(Number val) {
211  return val != static_cast<Number>(0);
212  }
213 
214  // For anything else, throw bad_get().
215  template <class T>
216  typename boost::disable_if<boost::is_arithmetic<T>, bool>::type
217  operator()(T) { throw boost::bad_get(); }
218 };
219 
220 // A parser value. This is used as the fundamental value object in the text
221 // parser. It can hold one of a few different types: (u)int64_t, double,
222 // string, TfToken, and SdfAssetPath. The lexer only ever produces Value
223 // objects holding (u)int64_t, double, and string. The presence of TfToken and
224 // SdfAssetPath here are for a relatively obscure case where we're parsing a
225 // value whose type is unknown to the parser. See
226 // StartRecordingString/StopRecordingString/IsRecordingString in
227 // parserValueContext.{cpp.h}. We'd like to change this.
228 //
229 // Value's primary function is to provide a Get<T>() convenience API that
230 // handles appropriate conversions from the held types. For example, it is okay
231 // to call Get<float>() on a Value that's holding an integral type, a double, or
232 // a string if that string's value is one of 'inf', '-inf', or 'nan'. Similarly
233 // Get<bool>() works on numbers and strings like 'yes', 'no', 'on', 'off',
234 // 'true', 'false'. If a Get<T>() call fails, it throws boost::bad_get, which
235 // the parser responds to and raises a parse error.
236 //
237 // The lexer constructs Value objects from input tokens. It creates them to
238 // retain all the input information possible. For example, negative integers
239 // are stored as int64_t Values, positive numbers are stored as uint64_t values,
240 // and so on. As a special case of this, '-0' is stored as a double, since it
241 // is the only way to preserve a signed zero (integral types have no signed
242 // zero).
243 struct Value
244 {
245  // Default constructor leaves the value in an undefined state.
246  Value() {}
247 
248  // Construct and implicitly convert from an integral type \p Int. If \p Int
249  // is signed, the resulting value holds an 'int64_t' internally. If \p Int
250  // is unsigned, the result value holds an 'uint64_t'.
251  template <class Int>
252  Value(Int in, typename boost::enable_if<
253  boost::is_integral<Int> >::type * = 0) {
254  if (boost::is_signed<Int>::value) {
255  _variant = static_cast<int64_t>(in);
256  } else {
257  _variant = static_cast<uint64_t>(in);
258  }
259  }
260 
261  // Construct and implicitly convert from a floating point type \p Flt. The
262  // resulting value holds a double internally.
263  template <class Flt>
264  Value(Flt in, typename boost::enable_if<
265  boost::is_floating_point<Flt> >::type * = 0) :
266  _variant(static_cast<double>(in)) {}
267 
268  // Construct and implicitly convert from std::string.
269  Value(const std::string &in) : _variant(in) {}
270 
271  // Construct and implicitly convert from TfToken.
272  Value(const TfToken &in) : _variant(in) {}
273 
274  // Construct and implicitly convert from SdfAssetPath.
275  Value(const SdfAssetPath &in) : _variant(in) {}
276 
277  // Attempt to get a value of type T from this Value, applying appropriate
278  // conversions. If this value cannot be converted to T, throw
279  // boost::bad_get.
280  template <class T>
281  typename _GetImpl<T>::ResultType Get() const {
282  return _GetImpl<T>().Visit(_variant);
283  }
284 
285  // Hopefully short-lived API that applies an external visitor to the held
286  // variant type.
287  template <class Visitor>
288  typename Visitor::result_type
289  ApplyVisitor(const Visitor &visitor) {
290  return boost::apply_visitor(visitor, _variant);
291  }
292 
293  template <class Visitor>
294  typename Visitor::result_type
295  ApplyVisitor(Visitor &visitor) {
296  return boost::apply_visitor(visitor, _variant);
297  }
298 
299  template <class Visitor>
300  typename Visitor::result_type
301  ApplyVisitor(const Visitor &visitor) const {
302  return _variant.apply_visitor(visitor);
303  }
304 
305  template <class Visitor>
306  typename Visitor::result_type
307  ApplyVisitor(Visitor &visitor) const {
308  return _variant.apply_visitor(visitor);
309  }
310 
311 private:
312  _Variant _variant;
313 };
314 
315 typedef std::function<VtValue (vector<unsigned int> const &,
316  vector<Value> const &,
317  size_t &, string *)> ValueFactoryFunc;
318 
319 struct ValueFactory {
320  ValueFactory() {}
321 
322  ValueFactory(std::string typeName_, SdfTupleDimensions dimensions_,
323  bool isShaped_, ValueFactoryFunc func_)
324  : typeName(typeName_),
325  dimensions(dimensions_),
326  isShaped(isShaped_),
327  func(func_) {}
328 
329  std::string typeName;
330  SdfTupleDimensions dimensions;
331  bool isShaped;
332  ValueFactoryFunc func;
333 };
334 
335 ValueFactory const &GetValueFactoryForMenvaName(std::string const &name,
336  bool *found);
337 };
338 
339 // Read the quoted string at [x..x+n], trimming 'trimBothSides' number
340 // of chars from either side, and evaluating any embedded escaped characters.
341 // If numLines is given, it will be populated with the number of newline
342 // characters present in the original string.
343 std::string Sdf_EvalQuotedString(const char* x, size_t n, size_t trimBothSides,
344  unsigned int* numLines = NULL);
345 
346 // Read the string representing an asset path at [x..x+n]. If tripleDelimited
347 // is true, the string is assumed to have 3 delimiters on both sides of the
348 // asset path, otherwise the string is assumed to have just 1.
349 std::string Sdf_EvalAssetPath(const char* x, size_t n, bool tripleDelimited);
350 
351 PXR_NAMESPACE_CLOSE_SCOPE
352 
353 #endif // SDF_PARSER_HELPERS_H
std::string const & GetString() const
Return the string that this token represents.
Definition: token.h:209
SDF_API bool SdfBoolFromString(const std::string &, bool *parseOk=NULL)
Converts a string to a bool.
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