-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathDynamicArrayHandle.tex
242 lines (193 loc) · 11.4 KB
/
DynamicArrayHandle.tex
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
% -*- latex -*-
\chapter{Dynamic Array Handles}
\label{chap:DynamicArrayHandle}
\index{dynamic array handle|(}
\index{array handle!dynamic|(}
The \textidentifier{ArrayHandle} class uses templating to make very
efficient and type-safe access to data. However, it is sometimes
inconvenient or impossible to specify the element type and storage at
run-time. The \textidentifier{DynamicArrayHandle} class provides a mechanism
to manage arrays of data with unspecified types.
\vtkmcont{DynamicArrayHandle} holds a reference to an array. Unlike
\textidentifier{ArrayHandle}, \textidentifier{DynamicArrayHandle} is
\emph{not} templated. Instead, it uses C++ run-type type information to
store the array without type and cast it when appropriate.
\index{dynamic array handle!construct}
A \textidentifier{DynamicArrayHandle} can be established by constructing it
with or assigning it to an \textidentifier{ArrayHandle}. The following
example demonstrates how a \textidentifier{DynamicArrayHandle} might be
used to load an array whose type is not known until run-time.
\vtkmlisting{Creating a \textidentifier{DynamicArrayHandle}.}{CreateDynamicArrayHandle.cxx}
\section{Querying and Casting}
\label{sec:DynamicArrayHandleQueryingAndCasting}
\index{dynamic array handle!query}
Data pointed to by a \textidentifier{DynamicArrayHandle} is not directly
accessible. However, there are a few generic queries you can make without
directly knowing the data type. The \textcode{GetNumberOfValues} method
returns the length of the array with respect to its base data type. It is
also common in VTK-m to use data types, such as \vtkm{Vec}, with multiple
components per value. The \textcode{GetNumberOfComponents} method returns
the number of components in a vector-like type (or 1 for scalars).
\vtkmlisting{Non type-specific queries on \textidentifier{DynamicArrayHandle}.}{NonTypeQueriesDynamicArrayHandle.cxx}
\index{dynamic array handle!new instance}
It is also often desirable to create a new array based on the underlying
type of a \textidentifier{DynamicArrayHandle}. For example, when a filter
creates a field, it is common to make this output field the same type as
the input. To satisfy this use case, \textidentifier{DynamicArrayHandle}
has a method named \textcode{NewInstance} that creates a new empty array
with the same underlying type as the original array.
\vtkmlisting{Using \textidentifier{DynamicArrayHandle}\textcode{::NewInstance()}.}{DynamicArrayHandleNewInstance.cxx}
Before the data with a \textidentifier{DynamicArrayHandle} can be accessed,
the type and storage of the array must be established. This is usually done
internally within VTK-m when a worklet \fix{or filter?} is invoked.
However, it is also possible to query the types and cast to a concrete
\textidentifier{ArrayHandle}.
\index{dynamic array handle!query}
You can query the component type and storage type using the
\textcode{IsType}, \textcode{IsSameType}, and
\textcode{IsTypeAndStorage} methods. \textcode{IsType} takes an
example array handle type and returns whether the underlying array matches
the given static array type. \textcode{IsSameType} behaves the same as
\textcode{IsType} but accepts an instance of an
\textidentifier{ArrayHandle} object to automatically resolve the template
parameters. \textcode{IsTypeAndStorage} takes an example
component type and an example storage type as arguments and returns whether
the underlying array matches both types.
\vtkmlisting{Querying the component and storage types of a \textidentifier{DynamicArrayHandle}.}{QueryDynamicArrayHandle.cxx}
\index{dynamic array handle!cast}
Once the type of the \textidentifier{DynamicArrayHandle} is known, it can
be cast to a concrete \textidentifier{ArrayHandle}, which has access to the
data as described in Chapter~\ref{chap:ArrayHandle}. The easiest way to do
this is to use the \textcode{CopyTo} method. This templated method takes a
reference to an \textidentifier{ArrayHandle} as an argument and sets that
array handle to point to the array in \textidentifier{DynamicArrayHandle}.
If the given types are incorrect, then \textcode{CopyTo} throws
a \vtkmcont{ErrorControlBadValue} exception.
\vtkmlisting{Casting a \textidentifier{DynamicArrayHandle} to a concrete
\textidentifier{ArrayHandle}.}{CastDynamicArrayHandle.cxx}
\begin{commonerrors}
Remember that \textidentifier{ArrayHandle} and
\textidentifier{DynamicArrayHandle} represent pointers to the data, so
this ``copy'' is a shallow copy. There is still only one copy of the
data, and if you change the data in one array handle that change is
reflected in the other.
\end{commonerrors}
\section{Casting to Unknown Types}
\index{dynamic array handle!cast|(}
Using \textcode{CopyTo} is fine as long as the correct types are
known, but often times they are not. For this use case
\textidentifier{DynamicArrayHandle} has a method named
\textcode{CastAndCall} that attempts to cast the array to some set of
types.
The \textcode{CastAndCall} method accepts a functor to run on the
appropriately cast array. The functor must have an overloaded const
parentheses operator that accepts an \textidentifier{ArrayHandle} of the
appropriate type.
\vtkmlisting[ex:UsingCastAndCall]{Operating on \textidentifier{DynamicArrayHandle} with \textcode{CastAndCall}.}{UsingCastAndCall.cxx}
\begin{commonerrors}
It is possible to store any form of \textidentifier{ArrayHandle} in a
\textidentifier{DynamicArrayHandle}, but it is not possible for
\textcode{CastAndCall} to check every possible form of
\textidentifier{ArrayHandle}. If \textcode{CastAndCall} cannot determine
the \textidentifier{ArrayHandle} type, then an
\textidentifier{ErrorControlBadValue} is thrown. The following section
describes how to specify the forms of \textidentifier{ArrayHandle} to try.
\end{commonerrors}
\section{Specifying Cast Lists}
\label{sec:DynamicArrayHandleSpecifyingCastLists}
The \textcode{CastAndCall} method can only check a finite number of types.
The default form of \textcode{CastAndCall} uses a default set of common
types. These default lists can be overridden using the VTK-m list tags
facility, which is discussed at length in Section~\ref{sec:ListTags}. There
are separate lists for value types and for storage types.
Common type lists for value are defined in
\vtkmheader{vtkm}{TypeListTag.h} and are documented in
Section~\ref{sec:TypeLists}. This header also defines
\vtkmmacro{VTKM\_DEFAULT\_TYPE\_LIST\_TAG}, which defines the default list
of value types tried in \textcode{CastAndCall}.
\index{tag!storage lists|(}
\index{lists!storage|(}
\index{storage lists|(}
Common storage lists are defined in
\vtkmheader{vtkm/cont}{StorageListTag.h}. There is only one common storage
distributed with VTK-m: \textidentifier{StorageBasic}. A list tag
containing this type is defined as \vtkmcont{StorageListTagBasic}.
As with other lists, it is possible to create new storage type lists
using the existing type lists and the list bases from
Section~\ref{sec:BuildingListTags}.
The \vtkmheader{vtkm/cont}{StorageListTag.h} header also defines a macro
named \vtkmmacro{VTKM\_DEFAULT\_STORAGE\_LIST\_TAG} that defines a
default list of types to use in classes like
\textidentifier{DynamicArrayHandle}. This list can be overridden by
defining the \vtkmmacro{VTKM\_DEFAULT\_STORAGE\_LIST\_TAG} macro
\emph{before} any VTK-m headers are included. If included after a VTK-m
header, the list is not likely to take effect. Do not ignore compiler
warnings about the macro being redefined, which you will not get if defined
correctly.
\index{storage lists|)}
\index{lists!storage|)}
\index{tag!storage lists|)}
There is a form of \textcode{CastAndCall} that accepts tags for the list of
component types and storage types. This can be used when the specific
lists are known at the time of the call. However, when creating generic
operations like the \textcode{PrintArrayContents} function in
Example~\ref{ex:UsingCastAndCall}, passing these tags is inconvenient at
best.
To address this use case, \textidentifier{DynamicArrayHandle} has a pair of
methods named \textcode{ResetTypeList} and
\textcode{ResetStorageList}. These methods return a new object with that
behaves just like a \textidentifier{DynamicArrayHandle} with identical
state except that the cast and call functionality uses the specified
component type or storage type instead of the default. (Note that
\textcode{PrintArrayContents} in Example~\ref{ex:UsingCastAndCall} is
templated on the type of \textidentifier{DynamicArrayHandle}. This is to
accommodate using the objects from the \textcode{Reset*List} methods, which
have the same behavior but different type names.)
So the default component type list contains a subset of the basic VTK-m
types. If you wanted to accommodate more types, you could use
\textcode{ResetTypeList}.
\vtkmlisting{Trying all component types in a \textidentifier{DynamicArrayHandle}.}{CastAndCallAllTypes.cxx}
Likewise, if you happen to know a particular type of the dynamic array,
that can be specified to reduce the amount of object code created by
templates in the compiler.
\vtkmlisting{Specifying a single component type in a \textidentifier{DynamicArrayHandle}.}{CastAndCallSingleType.cxx}
Storage type lists can be changed similarly.
\vtkmlisting{Specifying different storage types in a \textidentifier{DynamicArrayHandle}.}{CastAndCallStorage.cxx}
\begin{commonerrors}
The \textcode{ResetTypeList} and \textcode{ResetStorageList} do not
change the object they are called on. Rather, they return a new object
with different type information. Calling these methods has no effect
unless you do something with the returned value.
\end{commonerrors}
Both the component type list and the storage type list can be modified by
chaining these reset calls.
\vtkmlisting{Specifying both component and storage types in a \textidentifier{DynamicArrayHandle}.}{CastAndCallTypeAndStorage.cxx}
The \textcode{ResetTypeList} and \textcode{ResetStorageList} work by
returning a \vtkmcont{DynamicArrayHandleBase} object.
\textidentifier{DynamicArrayHandleBase} specifies the value and storage tag
lists as template arguments and otherwise behaves just like
\textidentifier{DynamicArrayHandle}.
\begin{didyouknow}
I lied earlier when I said at the beginning of this chapter that
\textidentifier{DynamicArrayHandle} is a class that is not templated.
This symbol is really just a \textcode{typedef} of
\textidentifier{DynamicArrayHandleBase}. Because the
\textidentifier{DynamicArrayHandle} fully specifies the template
arguments, it behaves like a class, but if you get a compiler error it
will show up as \textidentifier{DynamicArrayHandleBase}.
\end{didyouknow}
Most code does not need to worry about working directly with
\textidentifier{DynamicArrayHandleBase}. However, it is sometimes useful to
declare it in templated functions that accept dynamic array handles so that
works with every type list. The function in
Example~\ref{ex:UsingCastAndCall} did this by making the dynamic array
handle class itself the template argument. This will work, but it is prone
to error because the template will resolve to any type of argument. When
passing objects that are not dynamic array handles will result in strange
and hard to diagnose errors. Instead, we can define the same function using
\textidentifier{DyamicArrayHandleBase} so that the template will only match
dynamic array handle types.
\vtkmlisting{Using \textidentifier{DynamicArrayHandleBase} to accept generic dynamic array handles.}{DynamicArrayHandleBase.cxx}
\index{dynamic array handle!cast|)}
\index{array handle!dynamic|)}
\index{dynamic array handle|)}