HDK
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
resolverContext.h
Go to the documentation of this file.
1 //
2 // Copyright 2020 Pixar
3 //
4 // Licensed under the terms set forth in the LICENSE.txt file available at
5 // https://openusd.org/license.
6 //
7 #ifndef PXR_USD_AR_RESOLVER_CONTEXT_H
8 #define PXR_USD_AR_RESOLVER_CONTEXT_H
9 
10 /// \file ar/resolverContext.h
11 
12 #include "pxr/pxr.h"
13 #include "pxr/usd/ar/api.h"
14 #include "pxr/usd/ar/ar.h"
15 
16 #include "pxr/base/tf/hash.h"
18 
19 #ifdef PXR_PYTHON_SUPPORT_ENABLED
20 // XXX: This include is a hack to avoid build errors due to
21 // incompatible macro definitions in pyport.h on macOS.
22 #include <locale>
23 #include "pxr/base/tf/pyLock.h"
24 #endif
25 
27 
28 #include <algorithm>
29 #include <memory>
30 #include <string>
31 #include <type_traits>
32 #include <typeinfo>
33 #include <vector>
34 
36 
37 /// \class ArIsContextObject
38 ///
39 /// Metafunction to determine whether the templated object type is a
40 /// valid context object.
41 ///
42 template <class T>
44 {
45  static const bool value = false;
46 };
47 
48 /// Default implementation for providing debug info on the contained context.
49 template <class Context>
50 std::string ArGetDebugString(const Context& context);
51 
52 // Metafunctions for determining if a variadic list of objects
53 // are valid for use with the ArResolverContext c'tor.
54 class ArResolverContext;
55 
56 template <class ...Objects> struct Ar_AllValidForContext;
57 
58 template <class Object, class ...Other>
59 struct Ar_AllValidForContext<Object, Other...>
60 {
61  static const bool value =
65 };
66 
67 template <>
69 {
70  static const bool value = true;
71 };
72 
73 /// \class ArResolverContext
74 ///
75 /// An asset resolver context allows clients to provide additional data
76 /// to the resolver for use during resolution. Clients may provide this
77 /// data via context objects of their own (subject to restrictions below).
78 /// An ArResolverContext is simply a wrapper around these objects that
79 /// allows it to be treated as a single type. Note that an ArResolverContext
80 /// may not hold multiple context objects with the same type.
81 ///
82 /// A client-defined context object must provide the following:
83 /// - Default and copy constructors
84 /// - operator<
85 /// - operator==
86 /// - An overload for size_t hash_value(const T&)
87 ///
88 /// Note that the user may define a free function:
89 ///
90 /// std::string ArGetDebugString(const Context& ctx);
91 /// (Where Context is the type of the user's path resolver context.)
92 ///
93 /// This is optional; a default generic implementation has been predefined.
94 /// This function should return a string representation of the context
95 /// to be utilized for debugging purposes(such as in TF_DEBUG statements).
96 ///
97 /// The ArIsContextObject template must also be specialized for this
98 /// object to declare that it can be used as a context object. This is to
99 /// avoid accidental use of an unexpected object as a context object.
100 /// The AR_DECLARE_RESOLVER_CONTEXT macro can be used to do this
101 /// as a convenience.
102 ///
103 /// \sa AR_DECLARE_RESOLVER_CONTEXT
104 /// \sa ArResolver::BindContext
105 /// \sa ArResolver::UnbindContext
106 /// \sa ArResolverContextBinder
108 {
109 public:
110  /// Construct an empty asset resolver context.
112  {
113  }
114 
115  /// Construct a resolver context using the given objects \p objs.
116  ///
117  /// Each argument must either be an ArResolverContext or a registered
118  /// context object. See class documentation for requirements on context
119  /// objects.
120  ///
121  /// If an argument is a context object, it will be added to the
122  /// constructed ArResolverContext. If an argument is an ArResolverContext,
123  /// all of the context objects it holds will be added to the constructed
124  /// ArResolverContext.
125  ///
126  /// Arguments are ordered from strong-to-weak. If a context object is
127  /// encountered with the same type as a previously-added object, the
128  /// previously-added object will remain and the other context object
129  /// will be ignored.
130  template <
131  class ...Objects,
132  typename std::enable_if<Ar_AllValidForContext<Objects...>::value>::type*
133  = nullptr>
134  ArResolverContext(const Objects&... objs)
135  {
136  _AddObjects(objs...);
137  }
138 
139  /// Construct a resolver context using the ArResolverContexts in \p ctxs.
140  ///
141  /// All of the context objects held by each ArResolverContext in \p ctxs
142  /// will be added to the constructed ArResolverContext.
143  ///
144  /// Arguments are ordered from strong-to-weak. If a context object is
145  /// encountered with the same type as a previously-added object, the
146  /// previously-added object will remain and the other context object
147  /// will be ignored.
148  AR_API
149  explicit ArResolverContext(const std::vector<ArResolverContext>& ctxs);
150 
151  /// Returns whether this resolver context is empty.
152  bool IsEmpty() const
153  {
154  return _contexts.empty();
155  }
156 
157  /// Returns pointer to the context object of the given type
158  /// held in this resolver context. Returns NULL if this resolver
159  /// context is not holding an object of the requested type.
160  template <class ContextObj>
161  const ContextObj* Get() const
162  {
163  for (const auto& context : _contexts) {
164  if (context->IsHolding(typeid(ContextObj))) {
165  return &_GetTyped<ContextObj>(*context)._context;
166  }
167  }
168  return nullptr;
169  }
170 
171  /// Returns a debug string representing the contained context objects.
172  AR_API
173  std::string GetDebugString() const;
174 
175  /// \name Operators
176  /// @{
177  AR_API
178  bool operator==(const ArResolverContext& rhs) const;
179 
180  bool operator!=(const ArResolverContext& rhs) const
181  {
182  return !(*this == rhs);
183  }
184 
185  AR_API
186  bool operator<(const ArResolverContext& rhs) const;
187 
188  /// @}
189 
190  /// Returns hash value for this asset resolver context.
191  friend size_t hash_value(const ArResolverContext& context)
192  {
193  return TfHash()(context._contexts);
194  }
195 
196 private:
197  // Type-erased storage for context objects.
198  struct _Untyped;
199  template <class Context> struct _Typed;
200 
201  void _AddObjects()
202  {
203  // Empty base case for unpacking parameter pack
204  }
205 
206  template <class Object, class ...Other>
207  void _AddObjects(const Object& obj, const Other&... other)
208  {
209  _Add(obj);
210  _AddObjects(other...);
211  }
212 
213  AR_API
214  void _Add(const ArResolverContext& ctx);
215 
216  template <class Object>
217  void _Add(const Object& obj)
218  {
219  _Add(std::shared_ptr<_Untyped>(new _Typed<Object>(obj)));
220  }
221 
222  AR_API
223  void _Add(std::shared_ptr<_Untyped>&& context);
224 
225  template <class Context>
226  static const _Typed<Context>& _GetTyped(const _Untyped& untyped)
227  {
228  return static_cast<const _Typed<Context>&>(untyped);
229  }
230 
231  struct _Untyped
232  {
233  AR_API
234  virtual ~_Untyped();
235 
236  bool IsHolding(const std::type_info& ti) const
237  {
238  return TfSafeTypeCompare(ti, GetTypeid());
239  }
240 
241  virtual _Untyped* Clone() const = 0;
242  virtual const std::type_info& GetTypeid() const = 0;
243  virtual bool LessThan(const _Untyped& rhs) const = 0;
244  virtual bool Equals(const _Untyped& rhs) const = 0;
245  virtual size_t Hash() const = 0;
246  virtual std::string GetDebugString() const = 0;
247  virtual TfPyObjWrapper GetPythonObj() const = 0;
248  };
249 
250  template <class Context>
251  struct _Typed : public _Untyped
252  {
253  virtual ~_Typed() { }
254 
255  _Typed(const Context& context) : _context(context)
256  {
257  }
258 
259  virtual _Untyped* Clone() const
260  {
261  return new _Typed<Context>(_context);
262  }
263 
264  virtual const std::type_info& GetTypeid() const
265  {
266  return typeid(Context);
267  }
268 
269  virtual bool LessThan(const _Untyped& rhs) const
270  {
271  return _context < _GetTyped<Context>(rhs)._context;
272  }
273 
274  virtual bool Equals(const _Untyped& rhs) const
275  {
276  return _context == _GetTyped<Context>(rhs)._context;
277  }
278 
279  virtual size_t Hash() const
280  {
281  return hash_value(_context);
282  }
283 
284  virtual std::string GetDebugString() const
285  {
286  return ArGetDebugString(_context);
287  }
288 
289  virtual TfPyObjWrapper GetPythonObj() const
290  {
291  #ifdef PXR_PYTHON_SUPPORT_ENABLED
292  TfPyLock lock;
293  return pxr_boost::python::object(_context);
294 #else
295  return {};
296 #endif
297  }
298 
299  Context _context;
300  };
301 
302  template <class HashState>
303  friend void TfHashAppend(
304  HashState& h, const std::shared_ptr<_Untyped>& context)
305  {
306  h.Append(context->Hash());
307  }
308 
309 #ifdef PXR_PYTHON_SUPPORT_ENABLED
310  friend class Ar_ResolverContextPythonAccess;
311 #endif
312 
313  std::vector<std::shared_ptr<_Untyped>> _contexts;
314 };
315 
316 
317 // Default implementation for streaming out held contexts.
318 AR_API
319 std::string Ar_GetDebugString(const std::type_info&, void const*);
320 
321 template <class Context>
322 std::string ArGetDebugString(const Context& context)
323 {
324  return Ar_GetDebugString(typeid(Context),
325  static_cast<void const*>(&context));
326 }
327 
329 
330 #endif
friend size_t hash_value(const ArResolverContext &context)
Returns hash value for this asset resolver context.
AR_API bool operator==(const ArResolverContext &rhs) const
bool operator!=(const ArResolverContext &rhs) const
STATIC_INLINE size_t Hash(const char *s, size_t len)
Definition: farmhash.h:2099
const ContextObj * Get() const
GLsizei const GLfloat * value
Definition: glcorearb.h:824
AR_API std::string Ar_GetDebugString(const std::type_info &, void const *)
AR_API std::string GetDebugString() const
Returns a debug string representing the contained context objects.
#define AR_API
Definition: api.h:23
AR_API bool operator<(const ArResolverContext &rhs) const
Definition: hash.h:472
GLint GLint GLsizei GLint GLenum GLenum type
Definition: glcorearb.h:108
class OCIOEXPORT Context
ArResolverContext(const Objects &...objs)
bool IsEmpty() const
Returns whether this resolver context is empty.
std::string ArGetDebugString(const Context &context)
Default implementation for providing debug info on the contained context.
ArResolverContext()
Construct an empty asset resolver context.
GLfloat GLfloat GLfloat GLfloat h
Definition: glcorearb.h:2002
friend void TfHashAppend(HashState &h, const std::shared_ptr< _Untyped > &context)
PXR_NAMESPACE_CLOSE_SCOPE PXR_NAMESPACE_OPEN_SCOPE
Definition: path.h:1425
#define PXR_NAMESPACE_CLOSE_SCOPE
Definition: pxr.h:74
Context provides a wrapper around the Core library context object.
Definition: ImfContext.h:30
PXR_NAMESPACE_OPEN_SCOPE bool TfSafeTypeCompare(const std::type_info &t1, const std::type_info &t2)