Loading...
Searching...
No Matches
visitValue.h
1//
2// Copyright 2022 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_BASE_VT_VISIT_VALUE_H
8#define PXR_BASE_VT_VISIT_VALUE_H
9
10#include "pxr/pxr.h"
11
12#include "pxr/base/tf/meta.h"
13#include "pxr/base/tf/pxrTslRobinMap/robin_map.h"
15#include "pxr/base/vt/value.h"
16
17#include <optional>
18#include <typeinfo>
19
20#ifndef VT_VISIT_VALUE_EXT_TYPES
21# define VT_VISIT_VALUE_EXT_TYPES PXR_NS_GLOBAL::TfMetaList<>
22#endif
23
24PXR_NAMESPACE_OPEN_SCOPE
25
26namespace Vt_ValueVisitDetail {
27
28// These two overloads do SFINAE to detect whether the visitor can be invoked
29// with the given held type T. If the visitor cannot be invoked with T, it is
30// instead invoked with the VtValue itself. We use the int/long trick and pass
31// 0 in the caller to disambiguate in case both are viable.
32template <class T, class Visitor, class ...Args>
33auto
34Visit(VtValue const &val, Visitor &&visitor, int, Args &&...args) ->
35 decltype(std::forward<Visitor>(visitor)(
36 val.UncheckedGet<T>(), std::forward<Args>(args)...))
37{
38 return std::forward<Visitor>(visitor)(
39 val.UncheckedGet<T>(), std::forward<Args>(args)...);
40}
41
42template <class T, class Visitor, class ...Args>
43auto
44Visit(VtValue const &val, Visitor &&visitor, long, Args &&...args) {
45 return std::forward<Visitor>(visitor)(val, std::forward<Args>(args)...);
46}
47
48} // Vt_ValueVisitDetail
49
50// Hash table mapping type_info -> index for extended type dispatch.
51// Shared across all visitor types for the same type list.
52template <class ...Ts>
53struct Vt_ExtTypeIndexTable {
54 static int Lookup(std::type_info const &ti) {
55 static const Vt_ExtTypeIndexTable instance;
56 auto it = instance._map.find(&ti);
57 return (it != instance._map.end()) ? it->second : -1;
58 }
59private:
60 struct _Hash {
61 size_t operator()(std::type_info const *ti) const {
62 return ti->hash_code();
63 }
64 };
65 struct _Equal {
66 bool operator()(std::type_info const *a,
67 std::type_info const *b) const {
68 return TfSafeTypeCompare(*a, *b);
69 }
70 };
71 Vt_ExtTypeIndexTable() {
72 int idx = 0;
73 ((_map.emplace(&typeid(Ts), idx++)), ...);
74 }
76};
77
78// Helper: a single dispatch thunk for VtVisitValue, used in function pointer
79// tables for large extended type lists.
80template <class T, class Ret, class Visitor, class ...Args>
81Ret
82Vt_VisitValueExtDispatchOne(
83 VtValue const &val, Visitor &&visitor, Args &&...args)
84{
85 return Vt_ValueVisitDetail::Visit<T>(
86 val, std::forward<Visitor>(visitor), 0,
87 std::forward<Args>(args)...);
88}
89
90constexpr size_t Vt_VisitValueHashThreshold = 8;
91
92// Extended type dispatch for VtVisitValue. For small type lists (<=
93// Vt_VisitValueHashThreshold), uses a linear search via a short-circuiting fold
94// expression. For larger lists, uses a hash-table lookup + function-pointer
95// dispatch.
96template <class ...Ts, class Visitor, class ...Args>
97auto
98Vt_VisitValueExtDispatch(
99 TfMetaList<Ts...>,
100 VtValue const &val, Visitor &&visitor, Args &&...args)
101{
102 using Ret = decltype(
103 Vt_ValueVisitDetail::Visit<VtValue>(
104 val, std::forward<Visitor>(visitor), 0,
105 std::forward<Args>(args)...));
106
107 if constexpr (sizeof...(Ts) == 0) {
108 return Vt_ValueVisitDetail::Visit<VtValue>(
109 val, std::forward<Visitor>(visitor), 0,
110 std::forward<Args>(args)...);
111 }
112 else if constexpr (sizeof...(Ts) <= Vt_VisitValueHashThreshold) {
113 std::optional<Ret> result;
114 ((!result && val.IsHolding<Ts>() &&
115 (result.emplace(Vt_ValueVisitDetail::Visit<Ts>(
116 val, std::forward<Visitor>(visitor), 0,
117 std::forward<Args>(args)...)), true)) || ...);
118 if (!result) {
119 return Vt_ValueVisitDetail::Visit<VtValue>(
120 val, std::forward<Visitor>(visitor), 0,
121 std::forward<Args>(args)...);
122 }
123 return std::move(*result);
124 }
125 else {
126 int idx = Vt_ExtTypeIndexTable<Ts...>::Lookup(val.GetTypeid());
127 if (idx >= 0) {
128 using FnPtr = Ret (*)(VtValue const &, Visitor &&, Args &&...);
129 static constexpr FnPtr table[] = {
130 &Vt_VisitValueExtDispatchOne<Ts, Ret, Visitor, Args...>...
131 };
132 return table[idx](
133 val, std::forward<Visitor>(visitor),
134 std::forward<Args>(args)...);
135 }
136 return Vt_ValueVisitDetail::Visit<VtValue>(
137 val, std::forward<Visitor>(visitor), 0,
138 std::forward<Args>(args)...);
139 }
140}
141
142// Helper: dispatch thunk for VtVisitValueType.
143template <class T, class Ret,
144 template <class, class...> class Visitor, class ...TypeArgs,
145 class ...FnArgs>
146Ret
147Vt_VisitValueTypeExtDispatchOne(FnArgs &&...args)
148{
149 return Visitor<T, TypeArgs...>::Visit(std::forward<FnArgs>(args)...);
150}
151
152// Extended type dispatch for VtVisitValueType.
153template <template <class T, class ...> class Visitor, typename ...TypeArgs,
154 class ...Ts, typename ...FnArgs>
155auto
156Vt_VisitValueTypeExtDispatch(
157 TfMetaList<Ts...>,
158 VtValue const &val, FnArgs &&...args)
159{
160 using Ret = decltype(
161 Visitor<VtValue, TypeArgs...>::Visit(std::forward<FnArgs>(args)...));
162
163 if constexpr (sizeof...(Ts) == 0) {
164 return Visitor<VtValue, TypeArgs...>::Visit(
165 std::forward<FnArgs>(args)...);
166 }
167 else if constexpr (sizeof...(Ts) <= Vt_VisitValueHashThreshold) {
168 std::optional<Ret> result;
169 ((!result && val.IsHolding<Ts>() &&
170 (result.emplace(Visitor<Ts, TypeArgs...>::Visit(
171 std::forward<FnArgs>(args)...)), true)) || ...);
172 if (!result) {
173 return Visitor<VtValue, TypeArgs...>::Visit(
174 std::forward<FnArgs>(args)...);
175 }
176 return std::move(*result);
177 }
178 else {
179 int idx = Vt_ExtTypeIndexTable<Ts...>::Lookup(val.GetTypeid());
180 if (idx >= 0) {
181 using FnPtr = Ret (*)(FnArgs &&...);
182 static constexpr FnPtr table[] = {
183 &Vt_VisitValueTypeExtDispatchOne<
184 Ts, Ret, Visitor, TypeArgs...>...
185 };
186 return table[idx](std::forward<FnArgs>(args)...);
187 }
188 return Visitor<VtValue, TypeArgs...>::Visit(
189 std::forward<FnArgs>(args)...);
190 }
191}
192
193// Helper: dispatch thunk for VtVisitValueType (template-template variant).
194template <class T, class Ret,
195 template <class, template <class...> class, class...> class Visitor,
196 template <class...> class Tmpl, class ...TypeArgs,
197 class ...FnArgs>
198Ret
199Vt_VisitValueTypeTmplExtDispatchOne(FnArgs &&...args)
200{
201 return Visitor<T, Tmpl, TypeArgs...>::Visit(std::forward<FnArgs>(args)...);
202}
203
204// Extended type dispatch for VtVisitValueType (template-template variant).
205template <template <class T, template <class...> class, class ...> class Visitor,
206 template <class...> class Tmpl, typename ...TypeArgs,
207 class ...Ts, typename ...FnArgs>
208auto
209Vt_VisitValueTypeTmplExtDispatch(
210 TfMetaList<Ts...>,
211 VtValue const &val, FnArgs &&...args)
212{
213 using Ret = decltype(
214 Visitor<VtValue, Tmpl, TypeArgs...>::Visit(
215 std::forward<FnArgs>(args)...));
216
217 if constexpr (sizeof...(Ts) == 0) {
218 return Visitor<VtValue, Tmpl, TypeArgs...>::Visit(
219 std::forward<FnArgs>(args)...);
220 }
221 else if constexpr (sizeof...(Ts) <= Vt_VisitValueHashThreshold) {
222 std::optional<Ret> result;
223 ((!result && val.IsHolding<Ts>() &&
224 (result.emplace(Visitor<Ts, Tmpl, TypeArgs...>::Visit(
225 std::forward<FnArgs>(args)...)), true)) || ...);
226 if (!result) {
227 return Visitor<VtValue, Tmpl, TypeArgs...>::Visit(
228 std::forward<FnArgs>(args)...);
229 }
230 return std::move(*result);
231 }
232 else {
233 int idx = Vt_ExtTypeIndexTable<Ts...>::Lookup(val.GetTypeid());
234 if (idx >= 0) {
235 using FnPtr = Ret (*)(FnArgs &&...);
236 static constexpr FnPtr table[] = {
237 &Vt_VisitValueTypeTmplExtDispatchOne<
238 Ts, Ret, Visitor, Tmpl, TypeArgs...>...
239 };
240 return table[idx](std::forward<FnArgs>(args)...);
241 }
242 return Visitor<VtValue, Tmpl, TypeArgs...>::Visit(
243 std::forward<FnArgs>(args)...);
244 }
245}
246
247
259template <class ExtTypes>
261
266 template <class Visitor, class ...Args>
267 static auto VisitValue(
268 VtValue const &value, Visitor &&visitor, Args&&...args)
269 {
270 switch (value.GetKnownValueTypeIndex()) {
271#define VT_CASE_FOR_TYPE_INDEX(unused, elem) \
272 case VtGetKnownValueTypeIndex<VT_TYPE(elem)>(): \
273 return Vt_ValueVisitDetail::Visit<VT_TYPE(elem)>( \
274 value, std::forward<Visitor>(visitor), 0, \
275 std::forward<Args>(args)...); \
276 break;
277VT_FOR_EACH_VALUE_TYPE(VT_CASE_FOR_TYPE_INDEX)
278#undef VT_CASE_FOR_TYPE_INDEX
279 default:
280 return Vt_VisitValueExtDispatch(
281 ExtTypes{},
282 value, std::forward<Visitor>(visitor),
283 std::forward<Args>(args)...);
284 };
285 }
286
290 template <
291 template <class T, class ...> class Visitor,
292 typename ...TypeArgs,
293 typename ...FnArgs
294 >
295 static auto VisitType(VtValue const &value, FnArgs&&...args)
296 {
297 switch (value.GetKnownValueTypeIndex()) {
298#define VT_CASE_FOR_TYPE_INDEX(unused, elem) \
299 case VtGetKnownValueTypeIndex<VT_TYPE(elem)>(): \
300 return Visitor<VT_TYPE(elem), TypeArgs...>::Visit( \
301 std::forward<FnArgs>(args)...); \
302 break;
303VT_FOR_EACH_VALUE_TYPE(VT_CASE_FOR_TYPE_INDEX)
304#undef VT_CASE_FOR_TYPE_INDEX
305 default:
306 return Vt_VisitValueTypeExtDispatch<Visitor, TypeArgs...>(
307 ExtTypes{}, value, std::forward<FnArgs>(args)...);
308 };
309 }
310
313 template <
314 template <class T, template <class...> class, class ...> class Visitor,
315 template <class...> class Tmpl,
316 typename ...TypeArgs,
317 typename ...FnArgs
318 >
319 static auto VisitType(VtValue const &value, FnArgs&&...args)
320 {
321 switch (value.GetKnownValueTypeIndex()) {
322#define VT_CASE_FOR_TYPE_INDEX(unused, elem) \
323 case VtGetKnownValueTypeIndex<VT_TYPE(elem)>(): \
324 return Visitor<VT_TYPE(elem), Tmpl, TypeArgs...>::Visit( \
325 std::forward<FnArgs>(args)...); \
326 break;
327VT_FOR_EACH_VALUE_TYPE(VT_CASE_FOR_TYPE_INDEX)
328#undef VT_CASE_FOR_TYPE_INDEX
329 default:
330 return Vt_VisitValueTypeTmplExtDispatch<Visitor, Tmpl, TypeArgs...>(
331 ExtTypes{}, value, std::forward<FnArgs>(args)...);
332 };
333 }
334};
335
336PXR_NAMESPACE_CLOSE_SCOPE
337
338#ifdef doxygen
339
439template <class Visitor, class ...Args>
440auto VtVisitValue(VtValue const &value, Visitor &&visitor, Args &&...args);
441
505template <
506 template <class T, class ...> class Visitor,
507 typename ...TypeArgs,
508 typename ...FnArgs
509 >
510auto VtVisitValueType(VtValue const &value, FnArgs &&...args);
511
540template <
541 template <class T, template <class...> class, class ...> class Visitor,
542 template <class...> class Tmpl,
543 typename ...TypeArgs,
544 typename ...FnArgs
545 >
546auto VtVisitValueType(VtValue const &value, FnArgs &&...args);
547
548#else // !doxygen
549
550#define VtVisitValue \
551 VtVisitValueWithExtTypes<VT_VISIT_VALUE_EXT_TYPES>::VisitValue
552
553#define VtVisitValueType \
554 VtVisitValueWithExtTypes<VT_VISIT_VALUE_EXT_TYPES>::VisitType
555
556#endif // doxygen
557
558#endif // PXR_BASE_VT_VISIT_VALUE_H
Provides a container which may hold any type, and provides introspection and iteration over array typ...
Definition value.h:90
bool IsHolding() const
Return true if this value is holding an object of type T, false otherwise.
Definition value.h:1002
VT_API std::type_info const & GetTypeid() const
Return the typeid of the type held by this value.
Implementation of a hash map using open-addressing and the robin hood hashing algorithm with backward...
Definition robin_map.h:96
Safely compare C++ RTTI type structures.
bool TfSafeTypeCompare(const std::type_info &t1, const std::type_info &t2)
Safely compare std::type_info structures.
Provides VtVisitValue() and VtVisitValueType() dispatch, parameterized on a compile-time list of exte...
Definition visitValue.h:260
static auto VisitType(VtValue const &value, FnArgs &&...args)
Invoke Visitor<T, TypeArgs...>::Visit(args...) where T is the held type.
Definition visitValue.h:295
static auto VisitValue(VtValue const &value, Visitor &&visitor, Args &&...args)
Invoke visitor with value's held object if value holds a known or extended type.
Definition visitValue.h:267
static auto VisitType(VtValue const &value, FnArgs &&...args)
This is an overloaded member function, provided for convenience. It differs from the above function o...
Definition visitValue.h:319