diff --git a/docs/users-guide/advanced-types.rst b/docs/users-guide/advanced-types.rst new file mode 100644 index 000000000..b27a4eea7 --- /dev/null +++ b/docs/users-guide/advanced-types.rst @@ -0,0 +1,802 @@ +============================== +Advanced Types +============================== + +:chapref:`base-types:Base Types` introduced some of the base data types defined for use in |VTKm|. +However, for simplicity Chapter :chapref:`base-types:Base Types` just briefly touched the high-level concepts of these types. +In this chapter we dive into much greater depth and introduce several more types. + + +------------------------------ +Single Number Types +------------------------------ + +As described in Chapter :chapref:`base-types:Base Types`, |VTKm| provides aliases for all the base C types to ensure the representation matches the variable use. +When a specific type width is not required, then the most common types to use are :type:`vtkm::FloatDefault` for floating-point numbers, :type:`vtkm::Id` for array and similar indices, and :type:`vtkm::IdComponent` for shorter-width vector indices. + +If a specific type width is desired, then one of the following is used to clearly declare the type and width. + ++-------+-----------------------+---------------------+----------------------+ +| bytes | floating point | signed integer | unsigned integer | ++=======+=======================+=====================+======================+ +| 1 | | :type:`vtkm::Int8` | :type:`vtkm::UInt8` | ++-------+-----------------------+---------------------+----------------------+ +| 2 | | :type:`vtkm::Int16` | :type:`vtkm::UInt16` | ++-------+-----------------------+---------------------+----------------------+ +| 4 | :type:`vtkm::Float32` | :type:`vtkm::Int32` | :type:`vtkm::UInt32` | ++-------+-----------------------+---------------------+----------------------+ +| 8 | :type:`vtkm::Float64` | :type:`vtkm::Int64` | :type:`vtkm::UInt64` | ++-------+-----------------------+---------------------+----------------------+ + +These |VTKm|--defined types should be preferred over basic C types like ``int`` or ``float``. + + +------------------------------ +Vector Types +------------------------------ + +Visualization algorithms also often require operations on short vectors. +Arrays indexed in up to three dimensions are common. +Data are often defined in 2-space and 3-space, and transformations are typically done in homogeneous coordinates of length 4. +To simplify these types of operations, |VTKm| provides the :class:`vtkm::Vec` templated type, which is essentially a fixed length array of a given type. + +.. doxygenclass:: vtkm::Vec + :members: + +The default constructor of :class:`vtkm::Vec` objects leaves the values uninitialized. +All vectors have a constructor with one argument that is used to initialize all components. +All :class:`vtkm::Vec` objects also have a constructor that allows you to set the individual components (one per argument). +All :class:`vtkm::Vec` objects with a size that is greater than 4 are constructed at run time and support an arbitrary number of initial values. +Likewise, there is a :func:`vtkm::make_Vec` convenience function that builds initialized vector types with an arbitrary number of components. +Once created, you can use the bracket operator to get and set component values with the same syntax as an array. + +.. load-example:: CreatingVectorTypes + :file: GuideExampleCoreDataTypes.cxx + :caption: Creating vector types. + +.. doxygenfunction:: vtkm::make_Vec + +The types :type:`vtkm::Id2`, :type:`vtkm::Id3`, and :type:`vtkm::Id4` are type aliases of ``vtkm::Vec``, ``vtkm::Vec``, and ``vtkm::Vec``, respectively. +These are used to index arrays of 2, 3, and 4 dimensions, which is common. +Likewise, :type:`vtkm::IdComponent2`, :type:`vtkm::IdComponent3`, and :type:`vtkm::IdComponent4` are type aliases of ``vtkm::Vec``, ``vtkm::Vec``, and ``vtkm::Vec``, respectively. + +Because declaring :class:`vtkm::Vec` with all of its template parameters can be cumbersome, |VTKm| provides easy to use aliases for small vectors of base types. +As introduced in :secref:`base-types:Vector Types`, the following type aliases are available. + ++-------+------+------------------------+------------------------+-------------------------+ +| bytes | size | floating point | signed integer | unsigned integer | ++=======+======+========================+========================+=========================+ +| 1 | 2 | | :type:`vtkm::Vec2i_8` | :type:`vtkm::Vec2ui_8` | ++-------+------+------------------------+------------------------+-------------------------+ +| | 3 | | :type:`vtkm::Vec3i_8` | :type:`vtkm::Vec3ui_8` | ++-------+------+------------------------+------------------------+-------------------------+ +| | 4 | | :type:`vtkm::Vec4i_8` | :type:`vtkm::Vec4ui_8` | ++-------+------+------------------------+------------------------+-------------------------+ +| 2 | 2 | | :type:`vtkm::Vec2i_16` | :type:`vtkm::Vec2ui_16` | ++-------+------+------------------------+------------------------+-------------------------+ +| | 3 | | :type:`vtkm::Vec3i_16` | :type:`vtkm::Vec3ui_16` | ++-------+------+------------------------+------------------------+-------------------------+ +| | 4 | | :type:`vtkm::Vec4i_16` | :type:`vtkm::Vec4ui_16` | ++-------+------+------------------------+------------------------+-------------------------+ +| 4 | 2 | :type:`vtkm::Vec2f_32` | :type:`vtkm::Vec2i_32` | :type:`vtkm::Vec2ui_32` | ++-------+------+------------------------+------------------------+-------------------------+ +| | 3 | :type:`vtkm::Vec3f_32` | :type:`vtkm::Vec3i_32` | :type:`vtkm::Vec3ui_32` | ++-------+------+------------------------+------------------------+-------------------------+ +| | 4 | :type:`vtkm::Vec4f_32` | :type:`vtkm::Vec4i_32` | :type:`vtkm::Vec4ui_32` | ++-------+------+------------------------+------------------------+-------------------------+ +| 8 | 2 | :type:`vtkm::Vec2f_64` | :type:`vtkm::Vec2i_64` | :type:`vtkm::Vec2ui_64` | ++-------+------+------------------------+------------------------+-------------------------+ +| | 3 | :type:`vtkm::Vec3f_64` | :type:`vtkm::Vec3i_64` | :type:`vtkm::Vec3ui_64` | ++-------+------+------------------------+------------------------+-------------------------+ +| | 4 | :type:`vtkm::Vec4f_64` | :type:`vtkm::Vec4i_64` | :type:`vtkm::Vec4ui_64` | ++-------+------+------------------------+------------------------+-------------------------+ + +:class:`vtkm::Vec` supports component-wise arithmetic using the operators for plus (``+``), minus (``-``), multiply (``*``), and divide (``/``). +It also supports scalar to vector multiplication with the multiply operator. +The comparison operators equal (``==``) is true if every pair of corresponding components are true and not equal (``!=``) is true otherwise. +A special :func:`vtkm::Dot` function is overloaded to provide a dot product for every type of vector. + +.. load-example:: VectorOperations + :file: GuideExampleCoreDataTypes.cxx + :caption: Vector operations. + +These operators, of course, only work if they are also defined for the component type of the :class:`vtkm::Vec`. +For example, the multiply operator will work fine on objects of type ``vtkm::Vec``, but the multiply operator will not work on objects of type ``vtkm::Vec`` because you cannot multiply objects of type ``std::string``. + +In addition to generalizing vector operations and making arbitrarily long vectors, :class:`vtkm::Vec` can be repurposed for creating any sequence of homogeneous objects. +Here is a simple example of using :class:`vtkm::Vec` to hold the state of a polygon. + +.. load-example:: EquilateralTriangle + :file: GuideExampleCoreDataTypes.cxx + :caption: Repurposing a :class:`vtkm::Vec`. + +Vec-like Types +============================== + +.. index:: Vec-like + +The :class:`vtkm::Vec` class provides a convenient structure for holding and passing small vectors of data. +However, there are times when using :class:`vtkm::Vec` is inconvenient or inappropriate. +For example, the size of :class:`vtkm::Vec` must be known at compile time, but there may be need for a vector whose size is unknown until compile time. +Also, the data populating a :class:`vtkm::Vec` might come from a source that makes it inconvenient or less efficient to construct a :class:`vtkm::Vec`. +For this reason, |VTKm| also provides several |Veclike| objects that behave much like :class:`vtkm::Vec` but are a different class. +These |Veclike| objects have the same interface as :class:`vtkm::Vec` except that the ``NUM_COMPONENTS`` constant is not available on those that are sized at run time. +|Veclike| objects also come with a ``CopyInto`` method that will take their contents and copy them into a standard :class:`vtkm::Vec` class. +(The standard :class:`vtkm::Vec` class also has a :func:`vtkm::Vec::CopyInto` method for consistency.) + +C-Array Vec Wrapper +------------------------------ + +The first |Veclike| object is :class:`vtkm::VecC`, which exposes a C-type array as a :class:`vtkm::Vec`. + +.. doxygenclass:: vtkm::VecC + :members: + +The constructor for :class:`vtkm::VecC` takes a C array and a size of that array. +There is also a constant version of :class:`vtkm::VecC` named :class:`vtkm::VecCConst`, which takes a constant array and cannot be mutated. + +.. doxygenclass:: vtkm::VecCConst + :members: + +The ``vtkm/Types.h`` header defines both :class:`vtkm::VecC` and :class:`vtkm::VecCConst` as well as multiple versions of :func:`vtkm::make_VecC` to easily convert a C array to either a :class:`vtkm::VecC` or :class:`vtkm::VecCConst`. + +.. doxygenfunction:: vtkm::make_VecC(T*, vtkm::IdComponent) + +.. doxygenfunction:: vtkm::make_VecC(const T *array, vtkm::IdComponent size) + +The following example demonstrates converting values from a constant table into a :class:`vtkm::VecCConst` for further consumption. +The table and associated methods define how 8 points come together to form a hexahedron. + +.. load-example:: VecCExample + :file: GuideExampleCoreDataTypes.cxx + :caption: Using :class:`vtkm::VecCConst` with a constant array. + +.. commonerrors:: + The :class:`vtkm::VecC` and :class:`vtkm::VecCConst` classes only hold a pointer to a buffer that contains the data. + They do not manage the memory holding the data. + Thus, if the pointer given to :class:`vtkm::VecC` or :class:`vtkm::VecCConst` becomes invalid, then using the object becomes invalid. + Make sure that the scope of the :class:`vtkm::VecC` or :class:`vtkm::VecCConst` does not outlive the scope of the data it points to. + +Variable-Sized Vec +------------------------------ + +The next |Veclike| object is :class:`vtkm::VecVariable`, which provides a |Veclike| object that can be resized at run time to a maximum value. +Unlike :class:`vtkm::VecC`, :class:`vtkm::VecVariable` holds its own memory, which makes it a bit safer to use. +But also unlike :class:`vtkm::VecC`, you must define the maximum size of :class:`vtkm::VecVariable` at compile time. +Thus, :class:`vtkm::VecVariable` is really only appropriate to use when there is a predetermined limit to the vector size that is fairly small. + +.. doxygenclass:: vtkm::VecVariable + :members: + +The following example uses a :class:`vtkm::VecVariable` to store the trace of edges within a hexahedron. +This example uses the methods defined in :numref:`ex:VecVariableExample`. + +.. load-example:: VecVariableExample + :file: GuideExampleCoreDataTypes.cxx + :caption: Using :class:`vtkm::VecVariable`. + +Vecs from Portals +------------------------------ + +|VTKm| provides further examples of |Veclike| objects as well. +For example, the :class:`vtkm::VecFromPortal` and :class:`vtkm::VecFromPortalPermute` objects allow you to treat a subsection of an arbitrarily large array as a :class:`vtkm::Vec`. +These objects work by attaching to array portals, which are described in Section~\ref{sec:ArrayPortals}. + +.. todo:: Fix reference to array portals. + +.. doxygenclass:: vtkm::VecFromPortal + :members: + +.. doxygenclass:: vtkm::VecFromPortalPermute + :members: + +Point Coordinate Vec +------------------------------ + +Another example of a |Veclike| object is :class:`vtkm::VecRectilinearPointCoordinates`, which efficiently represents the point coordinates in an axis-aligned hexahedron. +Such shapes are common in structured grids. +These and other data sets are described in :chapref:`dataset:Data Sets`. + +------------------------------ +Range +------------------------------ + +|VTKm| provides a convenience structure named :class:`vtkm::Range` to help manage a range of values. +The :class:`vtkm::Range` ``struct`` contains two data members, :member:`vtkm::Range::Min` and :member:`vtkm::Range::Max`, which represent the ends of the range of numbers. +:member:`vtkm::Range::Min` and :member:`vtkm::Range::Max` are both of type :type:`vtkm::Float64`. +:member:`vtkm::Range::Min` and :member:`vtkm::Range::Max` can be directly accessed, but :class:`vtkm::Range` also comes with several helper functions to make it easier to build and use ranges. +Note that all of these functions treat the minimum and maximum value as inclusive to the range. + +.. doxygenstruct:: vtkm::Range + :members: + +The following example demonstrates the operation of :class:`vtkm::Range`. + +.. load-example:: UsingRange + :file: GuideExampleCoreDataTypes.cxx + :caption: Using :class:`vtkm::Range`. + + +------------------------------ +Bounds +------------------------------ + +|VTKm| provides a convenience structure named :class:`vtkm::Bounds` to help manage +an axis-aligned region in 3D space. Among other things, this structure is +often useful for representing a bounding box for geometry. The +:class:`vtkm::Bounds` ``struct`` contains three data members, +:member:`vtkm::Bounds::X`, :member:`vtkm::Bounds::Y`, and :member:`vtkm::Bounds::Z`, which represent the range of +the bounds along each respective axis. All three of these members are of +type :class:`vtkm::Range`, which is discussed previously in :secref:`advanced-types:Range`. +:member:`vtkm::Bounds::X`, :member:`vtkm::Bounds::Y`, and :member:`vtkm::Bounds::Z` can +be directly accessed, but :class:`vtkm::Bounds` also comes with the +following helper functions to make it easier to build and use ranges. + +.. doxygenstruct:: vtkm::Bounds + :members: + +The following example demonstrates the operation of :class:`vtkm::Bounds`. + +.. load-example:: UsingBounds + :file: GuideExampleCoreDataTypes.cxx + :caption: Using `vtkm::Bounds`. + + +------------------------------ +Index Ranges +------------------------------ + +Just as it is sometimes necessary to track a range of real values, there are times when code has to specify a continuous range of values in an index sequence like an array. +For this purpose, |VTKm| provides :class:`RangeId`, which behaves similarly to :class:`Range` except for integer values. + +.. doxygenstruct:: vtkm::RangeId + :members: + +|VTKm| also often must operate on 2D and 3D arrays (particularly for structured cell sets). +For these use cases, :class:`RangeId2` and :class:`RangeId3` are provided. + +.. doxygenstruct:: vtkm::RangeId2 + :members: + +.. doxygenstruct:: vtkm::RangeId3 + :members: + + +------------------------------ +Traits +------------------------------ + +.. index:: + single: traits + single: tag + +When using templated types, it is often necessary to get information about the type or specialize code based on general properties of the type. +|VTKm| uses *traits* classes to publish and retrieve information about types. +A traits class is simply a templated structure that provides type aliases for tag structures, empty types used for identification. +The traits classes might also contain constant numbers and helpful static functions. +See *Effective C++ Third Edition* by Scott Meyers for a description of traits classes and their uses. + +Type Traits +============================== + +.. index:: + double: traits; type + +The :class:`vtkm::TypeTraits` templated class provides basic information about a core type. +These type traits are available for all the basic C++ types as well as the core |VTKm| types described in :chapref:`base-types:Base Types`. +:class:`vtkm::TypeTraits` contains the following elements. + +.. doxygenclass:: vtkm::TypeTraits + :members: + +The :type:`vtkm::TypeTraits::NumericTag` will be an alias for one of the following tags. + +.. index:: + triple: tag; type; numeric + +.. doxygenstruct:: vtkm::TypeTraitsRealTag + +.. doxygenstruct:: vtkm::TypeTraitsIntegerTag + +The :type:`vtkm::TypeTraits::DimensionalityTag` will be an alias for one of the following tags. + +.. index:: + triple: tag; type; dimensionality + +.. doxygenstruct:: vtkm::TypeTraitsScalarTag + +.. doxygenstruct:: vtkm::TypeTraitsVectorTag + +If for some reason one of these tags do not apply, :type:`vtkm::TypeTraitsUnknownTag` will be used. + +.. doxygenstruct:: vtkm::TypeTraitsUnknownTag + +The definition of :class:`vtkm::TypeTraits` for :type:`vtkm::Float32` could like something like this. + +.. load-example:: TypeTraitsImpl + :file: GuideExampleTraits.cxx + :caption: Example definition of ``vtkm::TypeTraits``. + +Here is a simple example of using :class:`vtkm::TypeTraits` to implement a generic function that behaves like the remainder operator (``%``) for all types including floating points and vectors. + +.. load-example:: TypeTraits + :file: GuideExampleTraits.cxx + :caption: Using :class:`vtkm::TypeTraits` for a generic remainder. + +Vector Traits +============================== + +.. index:: + double: traits; vector + +The templated :class:`vtkm::Vec` class contains several items for introspection (such as the component type and its size). +However, there are other types that behave similarly to :class:`vtkm::Vec` objects but have different ways to perform this introspection. + +.. index:: Vec-like + +For example, |VTKm| contains |Veclike| objects that essentially behave the same but might have different features. +Also, there may be reason to interchangeably use basic scalar values, like an integer or floating point number, with vectors. +To provide a consistent interface to access these multiple types that represents vectors, the :class:`vtkm::VecTraits` templated class provides information and accessors to vector types.It contains the following elements. + +.. doxygenstruct:: vtkm::VecTraits + :members: + +The :type:`vtkm::VecTraits::HasMultipleComponents` could be one of the following tags. + +.. index:: + triple: tag; vector; multiple components + +.. doxygenstruct:: vtkm::VecTraitsTagMultipleComponents + +.. doxygenstruct:: vtkm::VecTraitsTagSingleComponent + +The :type:`vtkm::VecTraits::IsSizeStatic` could be one of the following tags. + +.. index:: + triple: tag; vector; static + +.. doxygenstruct:: vtkm::VecTraitsTagSizeStatic + +.. doxygenstruct:: vtkm::VecTraitsTagSizeVariable + +The definition of :class:`vtkm::VecTraits` for :type:`vtkm::Id3` could look something like this. + +.. load-example:: VecTraitsImpl + :file: GuideExampleTraits.cxx + :caption: Example definition of ``vtkm::VecTraits``. + +The real power of vector traits is that they simplify creating generic operations on any type that can look like a vector. +This includes operations on scalar values as if they were vectors of size one. +The following code uses vector traits to simplify the implementation of :index:`less` functors that define an ordering that can be used for sorting and other operations. + +.. load-example:: VecTraits + :file: GuideExampleTraits.cxx + :caption: Using :class:`vtkm::VecTraits` for less functors. + + +------------------------------ +List Templates +------------------------------ + +.. index:: + single: lists + single: template metaprogramming + single: metaprogramming + +|VTKm| internally uses template metaprogramming, which utilizes C++ templates to run source-generating programs, to customize code to various data and compute platforms. +One basic structure often uses with template metaprogramming is a list of class names (also sometimes called a tuple or vector, although both of those names have different meanings in |VTKm|). + +Many |VTKm| users only need predefined lists, such as the type lists specified in :secref:`advanced-types:Type Lists`. +Those users can skip most of the details of this section. +However, it is sometimes useful to modify lists, create new lists, or operate on lists, and these usages are documented here. + +Building Lists +============================== + +A basic list is defined with the :class:`vtkm::List` template. + +.. doxygenstruct:: vtkm::List + +It is common (but not necessary) to use the ``using`` keyword to define an alias for a list with a particular meaning. + +.. load-example:: BaseLists + :file: GuideExampleLists.cxx + :caption: Creating lists of types. + +|VTKm| defines some special and convenience versions of :class:`vtkm::List`. + +.. doxygentypedef:: vtkm::ListEmpty + +.. doxygentypedef:: vtkm::ListUniversal + +Type Lists +============================== + +.. index:: + double: type; lists + +One of the major use cases for template metaprogramming lists in |VTKm| is to identify a set of potential data types for arrays. +The :file:`vtkm/TypeList.h` header contains predefined lists for known |VTKm| types. +The following lists are provided. + +.. doxygentypedef:: vtkm::TypeListId + +.. doxygentypedef:: vtkm::TypeListId2 + +.. doxygentypedef:: vtkm::TypeListId3 + +.. doxygentypedef:: vtkm::TypeListId4 + +.. doxygentypedef:: vtkm::TypeListIdComponent + +.. doxygentypedef:: vtkm::TypeListIndex + +.. doxygentypedef:: vtkm::TypeListFieldScalar + +.. doxygentypedef:: vtkm::TypeListFieldVec2 + +.. doxygentypedef:: vtkm::TypeListFieldVec3 + +.. doxygentypedef:: vtkm::TypeListFieldVec4 + +.. doxygentypedef:: vtkm::TypeListFloatVec + +.. doxygentypedef:: vtkm::TypeListField + +.. doxygentypedef:: vtkm::TypeListScalarAll + +.. doxygentypedef:: vtkm::TypeListBaseC + +.. doxygentypedef:: vtkm::TypeListVecCommon + +.. doxygentypedef:: vtkm::TypeListVecAll + +.. doxygentypedef:: vtkm::TypeListAll + +.. doxygentypedef:: vtkm::TypeListCommon + +If these lists are not sufficient, it is possible to build new type lists using the existing type lists and the list bases from :secref:`advanced-types:Building Lists` as demonstrated in the following example. + +.. load-example:: CustomTypeLists + :file: GuideExampleLists.cxx + :caption: Defining new type lists. + +The :file:`vtkm/cont/DefaultTypes.h` header defines a macro named :c:macro:`VTKM_DEFAULT_TYPE_LIST` that defines a default list of types to use when, for example, determining the type of a field array. +This macro can change depending on |VTKm| compile options. + +Querying Lists +============================== + +:file:`vtkm/List.h` contains some templated classes to help get information about a list type. +This are particularly useful for lists that are provided as templated parameters for which you do not know the exact type. + +Is a List +------------------------------ + +The :c:macro:`VTKM_IS_LIST` does a compile-time check to make sure a particular type is actually a :class:`vtkm::List` of types. +If the compile-time check fails, then a build error will occur. +This is a good way to verify that a templated class or method that expects a list actually gets a list. + +.. doxygendefine:: VTKM_IS_LIST + +.. load-example:: VTKM_IS_LIST + :file: GuideExampleLists.cxx + :caption: Checking that a template parameter is a valid :class:`vtkm::List`. + +List Size +------------------------------ + +The size of a list can be determined by using the :type:`vtkm::ListSize` template. +The type of the template will resolve to a ``std::integral_constant`` where ``N`` is the number of types in the list. +:type:`vtkm::ListSize` does not work with :type:`vtkm::ListUniversal`. + +.. doxygentypedef:: vtkm::ListSize + +.. load-example:: ListSize + :file: GuideExampleLists.cxx + :caption: Getting the size of a :class:`vtkm::List`. + +List Contains +------------------------------ + +The :type:`vtkm::ListHas` template can be used to determine if a :class:`vtkm::List` contains a particular type. +:type:`vtkm::ListHas` takes two template parameters. +The first parameter is a form of :class:`vtkm::List`. +The second parameter is any type to check to see if it is in the list. +If the type is in the list, then :type:`vtkm::ListHas` resolves to ``std::true_type``. +Otherwise it resolves to ``std::false_type``. +:type:`vtkm::ListHas` always returns true for :type:`vtkm::ListUniversal`. + +.. doxygentypedef:: vtkm::ListHas + +.. load-example:: ListHas + :file: GuideExampleLists.cxx + :caption: Determining if a :class:`vtkm::List` contains a particular type. + +List Indices +------------------------------ + +The :type:`vtkm::ListIndexOf` template can be used to get the index of a particular type in a :class:`vtkm::List`. +:type:`vtkm::ListIndexOf` takes two template parameters. +The first parameter is a form of :class:`vtkm::List`. +The second parameter is any type to check to see if it is in the list. +The type of the template will resolve to a ``std::integral_constant`` where ``N`` is the index of the type. +If the requested type is not in the list, then :type:`vtkm::ListIndexOf` becomes ``std::integral_constant``. + +.. doxygentypedef:: vtkm::ListIndexOf + +Conversely, the :type:`vtkm::ListAt` template can be used to get the type for a particular index. +The two template parameters for :type:`vtkm::ListAt` are the :class:`vtkm::List` and an index for the list. + +.. doxygentypedef:: vtkm::ListAt + +Neither :type:`vtkm::ListIndexOf` nor :type:`vtkm::ListAt` works with :type:`vtkm::ListUniversal`. + +.. load-example:: ListIndices + :file: GuideExampleLists.cxx + :caption: Using indices with :class:`vtkm::List`. + +Operating on Lists +============================== + +In addition to providing the base templates for defining and querying lists, :file:`vtkm/List.h` also contains several features for operating on lists. + +Appending Lists +------------------------------ + +The :type:`vtkm::ListAppend` template joins together 2 or more :class:`vtkm::List` types. +The items are concatenated in the order provided to :type:`vtkm::ListAppend`. +:type:`vtkm::ListAppend` does not work with :type:`vtkm::ListUniversal`. + +.. doxygentypedef:: vtkm::ListAppend + +.. load-example:: ListAppend + :file: GuideExampleLists.cxx + :caption: Appending :class:`vtkm::List` types. + +Intersecting Lists +------------------------------ + +The :type:`vtkm::ListIntersect` template takes two :class:`vtkm::List` types and becomes a :class:`vtkm::List` containing all types in both lists. +If one of the lists is :type:`vtkm::ListUniversal`, the contents of the other list used. + +.. doxygentypedef:: vtkm::ListIntersect + +.. load-example:: ListIntersect + :file: GuideExampleLists.cxx + :caption: Intersecting :class:`vtkm::List` types. + +Resolve a Template with all Types in a List +-------------------------------------------------- + +The :type:`vtkm::ListApply` template transfers all of the types in a :class:`vtkm::List` to another template. +The first template argument of :type:`vtkm::ListApply` is the :class:`vtkm::List` to apply. +The second template argument is another template to apply to. +:type:`vtkm::ListApply` becomes an instance of the passed template with all the types in the :class:`vtkm::List`. +:type:`vtkm::ListApply` can be used to convert a :class:`vtkm::List` to some other template. +:type:`vtkm::ListApply` cannot be used with :type:`vtkm::ListUniversal`. + +.. doxygentypedef:: vtkm::ListApply + +.. load-example:: ListApply + :file: GuideExampleLists.cxx + :caption: Applying a :class:`vtkm::List` to another template. + +Transform Each Type in a List +------------------------------ + +The :type:`vtkm::ListTransform` template applies each item in a :class:`vtkm::List` to another template and constructs a list from all these applications. +The first template argument of :type:`vtkm::ListTransform` is the :class:`vtkm::List` to apply. +The second template argument is another template to apply to. +:type:`vtkm::ListTransform` becomes an instance of a new :class:`vtkm::List` containing the passed template each type. +:type:`vtkm::ListTransform` cannot be used with :type:`vtkm::ListUniversal`. + +.. doxygentypedef:: vtkm::ListTransform + +.. load-example:: ListTransform + :file: GuideExampleLists.cxx + :caption: Transforming a :class:`vtkm::List` using a custom template. + +Conditionally Removing Items from a List +---------------------------------------- + +The :type:`vtkm::ListRemoveIf` template removes items from a :class:`vtkm::List` given a predicate. +The first template argument of :type:`vtkm::ListRemoveIf` is the :class:`vtkm::List`. +The second argument is another template that is used as a predicate to determine if the type should be removed or not. +The predicate should become a type with a ``value`` member that is a static true or false value. +Any type in the list that the predicate evaluates to true is removed. +:type:`vtkm::ListRemoveIf` cannot be used with :type:`vtkm::ListUniversal`. + +.. doxygentypedef:: vtkm::ListRemoveIf + +.. load-example:: ListRemoveIf + :file: GuideExampleLists.cxx + :caption: Removing items from a :class:`vtkm::List`. + +Combine all Pairs of Two Lists +------------------------------ + +The :type:`vtkm::ListCross` takes two lists and performs a cross product of them. +It does this by creating a new :class:`vtkm::List` that contains nested :class:`vtkm::List` types, each of length 2 and containing all possible pairs of items in the first list with items in the second list. +:type:`vtkm::ListCross` is often used in conjunction with another list processing command, such as :type:`vtkm::ListTransform` to build templated types of many combinations. +:type:`vtkm::ListCross` cannot be used with :type:`vtkm::ListUniversal`. + +.. doxygentypedef:: vtkm::ListCross + +.. load-example:: ListCross + :file: GuideExampleLists.cxx + :caption: Creating the cross product of 2 :class:`vtkm::List` types. + +Call a Function For Each Type in a List +---------------------------------------- + +The :type:`vtkm::ListForEach` function takes a functor object and a :class:`vtkm::List`. +It then calls the functor object with the default object of each type in the list. +This is most typically used with C++ run-time type information to convert a run-time polymorphic object to a statically typed (and possibly inlined) call. + +.. doxygenfunction:: vtkm::ListForEach(Functor &&f, vtkm::List, Args&&... args) + +The following example shows a rudimentary version of converting a dynamically-typed array to a statically-typed array similar to what is done in |VTKm| classes like :class:`vtkm::cont::UnknownArrayHandle` (which is documented in Chapter~\ref{chap:UnknownArrayHandle}). + +.. todo:: Fix ``UnknownArrayHandle`` chapter reference above. + +.. load-example:: ListForEach + :file: GuideExampleLists.cxx + :caption: Converting dynamic types to static types with :type:`vtkm::ListForEach`. + + +------------------------------ +Pair +------------------------------ + +|VTKm| defines a :class:`vtkm::Pair` templated object that behaves just like ``std::pair`` from the standard template library. +The difference is that :class:`vtkm::Pair` will work in both the execution and control environments, whereas the STL ``std::pair`` does not always work in the execution environment. + +.. doxygenstruct:: vtkm::Pair + :members: + :undoc-members: + +The |VTKm| version of :class:`vtkm::Pair` supports the same types, fields, and operations as the STL version. +|VTKm| also provides a :func:`vtkm::make_Pair` function for convenience. + +.. doxygenfunction:: vtkm::make_Pair + + +------------------------------ +Tuple +------------------------------ + +|VTKm| defines a :class:`vtkm::Tuple` templated object that behaves like ``std::tuple`` from the standard template library. +The main difference is that :class:`vtkm::Tuple` will work in both the execution and control environments, whereas the STL ``std::tuple`` does not always work in the execution environment. + +.. doxygenclass:: vtkm::Tuple + +Defining and Constructing +============================== + +:class:`vtkm::Tuple` takes any number of template parameters that define the objects stored the tuple. + +.. load-example:: DefineTuple + :file: GuideExampleTuple.cxx + :caption: Defining a :class:`vtkm::Tuple`. + +You can construct a :class:`vtkm::Tuple` with arguments that will be used to initialize the respective objects. +As a convenience, you can use :func:`vtkm::MakeTuple` to construct a :class:`vtkm::Tuple` of types based on the arguments. + +.. doxygenfunction:: vtkm::MakeTuple +.. doxygenfunction:: vtkm::make_tuple + +.. load-example:: InitTuple + :file: GuideExampleTuple.cxx + :caption: Initializing values in a :class:`vtkm::Tuple`. + +Querying +============================== + +The size of a :class:`vtkm::Tuple` can be determined by using the :type:`vtkm::TupleSize` template, which resolves to an ``std::integral_constant``. +The types at particular indices can be determined with :type:`vtkm::TupleElement`. + +.. doxygentypedef:: vtkm::TupleSize +.. doxygentypedef:: vtkm::TupleElement + +.. load-example:: TupleQuery + :file: GuideExampleTuple.cxx + :caption: Querying :class:`vtkm::Tuple` types. + +The function :func:`vtkm::Get` can be used to retrieve an element from the :class:`vtkm::Tuple`. +:func:`vtkm::Get` returns a reference to the element, so you can set a :class:`vtkm::Tuple` element by setting the return value of :func:`vtkm::Get`. + +.. doxygenfunction:: vtkm::Get(const vtkm::Tuple &tuple) +.. doxygenfunction:: vtkm::Get(vtkm::Tuple &tuple) +.. doxygenfunction:: vtkm::get(const vtkm::Tuple &tuple) +.. doxygenfunction:: vtkm::get(vtkm::Tuple &tuple) + +.. load-example:: TupleGet + :file: GuideExampleTuple.cxx + :caption: Retrieving values from a :class:`vtkm::Tuple`. + +For Each Tuple Value +============================== + +The :func:`vtkm::ForEach` function takes a tuple and a function or functor and calls the function for each of the items in the tuple. +Nothing is returned from :func:`vtkm::ForEach`, and any return value from the function is ignored. + +.. doxygenfunction:: vtkm::ForEach(const vtkm::Tuple &tuple, Function &&f) +.. doxygenfunction:: vtkm::ForEach(vtkm::Tuple &tuple, Function &&f) + +:func:`vtkm::ForEach` can be used to check the validity of each item in a :class:`vtkm::Tuple`. + +.. load-example:: TupleCheck + :file: GuideExampleTuple.cxx + :caption: Using :func:`vtkm::Tuple::ForEach` to check the contents. + +:func:`vtkm::ForEach` can also be used to aggregate values in a :class:`vtkm::Tuple`. + +.. load-example:: TupleAggregate + :file: GuideExampleTuple.cxx + :caption: Using :func:`vtkm::Tuple::ForEach` to aggregate. + +The previous examples used an explicit ``struct`` as the functor for clarity. +However, it is often less verbose to use a C++ lambda function. + +.. load-example:: TupleAggregateLambda + :file: GuideExampleTuple.cxx + :caption: Using :func:`vtkm::Tuple::ForEach` to aggregate. + +Transform Each Tuple Value +============================== + +The :func:`vtkm::Transform` function builds a new :class:`vtkm::Tuple` by calling a function or functor on each of the items in an existing :class:`vtkm::Tuple`. +The return value is placed in the corresponding part of the resulting :class:`vtkm::Tuple`, and the type is automatically created from the return type of the function. + +.. doxygenfunction:: vtkm::Transform(const TupleType &&tuple, Function &&f) -> decltype(Apply(tuple, detail::TupleTransformFunctor{}, std::forward(f))) +.. doxygenfunction:: vtkm::Transform(TupleType &&tuple, Function &&f) -> decltype(Apply(tuple, detail::TupleTransformFunctor{}, std::forward(f))) + +.. load-example:: TupleTransform + :file: GuideExampleTuple.cxx + :caption: Transforming a :class:`vtkm::Tuple`. + +Apply +============================== + +The :func:`vtkm::Apply` function calls a function or functor using the objects in a :class:`vtkm::Tuple` as the arguments. +If the function returns a value, that value is returned from :func:`vtkm::Apply`. + +.. doxygenfunction:: vtkm::Apply(const vtkm::Tuple &tuple, Function &&f, Args&&... args) -> decltype(tuple.Apply(std::forward(f), std::forward(args)...)) +.. doxygenfunction:: vtkm::Apply(vtkm::Tuple &tuple, Function &&f, Args&&... args) -> decltype(tuple.Apply(std::forward(f), std::forward(args)...)) + +.. load-example:: TupleApply + :file: GuideExampleTuple.cxx + :caption: Applying a :class:`vtkm::Tuple` as arguments to a function. + +If additional arguments are given to :func:`vtkm::Apply`, they are also passed to the function (before the objects in the :class:`vtkm::Tuple`). +This is helpful for passing state to the function. + +.. load-example:: TupleApplyExtraArgs + :file: GuideExampleTuple.cxx + :caption: Using extra arguments with :func:`vtkm::Tuple::Apply`. + + +.. todo:: Document ``Variant``. + + +------------------------------ +Error Codes +------------------------------ + +.. index:: error codes + +For operations that occur in the control environment, |VTKm| uses exceptions to report errors as described in :chapref:`error-handling:Error Handling`. +However, when operating in the execution environment, it is not feasible to throw exceptions. Thus, for operations designed for the execution environment, the status of an operation that can fail is returned as an :enum:`vtkm::ErrorCode`, which is an ``enum``. + +.. doxygenenum:: vtkm::ErrorCode + +If a function or method returns an :enum:`vtkm::ErrorCode`, it is a good practice to check to make sure that the returned value is :enumerator:`vtkm::ErrorCode::Success`. +If it is not, you can use the :func:`vtkm::ErrorString` function to convert the :enum:`vtkm::ErrorCode` to a descriptive C string. +The easiest thing to do from within a worklet is to call the worklet's ``RaiseError`` method. + +.. doxygenfunction:: vtkm::ErrorString + +.. load-example:: HandleErrorCode + :file: GuideExampleCellLocator.cxx + :caption: Checking an :enum:`vtkm::ErrorCode` and reporting errors in a worklet. diff --git a/docs/users-guide/base-types.rst b/docs/users-guide/base-types.rst index 2baccc2d5..563947331 100644 --- a/docs/users-guide/base-types.rst +++ b/docs/users-guide/base-types.rst @@ -222,6 +222,4 @@ For example, :type:`vtkm::Vec4ui_8` is a \textidentifier{Vec} of 4 unsigned byte .. doxygentypedef:: vtkm::Vec4ui_64 These types really just scratch the surface of the ``Vec`` types available in |VTKm| and the things that can be done with them. -See ``:chapref:`advanced-types:Advanced Types` `` for more information on ``Vec`` types and what can be done with them. - -.. todo:: Update chapter reference. +See :chapref:`advanced-types:Advanced Types` for more information on ``Vec`` types and what can be done with them. diff --git a/docs/users-guide/basic-filter-impl.rst b/docs/users-guide/basic-filter-impl.rst index 350961f97..5faee0691 100644 --- a/docs/users-guide/basic-filter-impl.rst +++ b/docs/users-guide/basic-filter-impl.rst @@ -15,7 +15,7 @@ There are multiple base filter classes that we can choose from. These different classes are documented later in Chapter \ref{chap:FilterTypeReference}. For this example we will use the :class:`vtkm::filter::FilterField` base class, which is used to derive one field from another field. -.. todo:: Fix above reference. +.. todo:: Fix above reference to filter types chapter. The following example shows the declaration of our pressure unit conversion filter. By convention, this declaration would be placed in a header file with a ``.h`` extension. @@ -69,7 +69,7 @@ One of the challenges with writing filters is determining the actual types the a The :class:`vtkm::cont::Field` object pulled from the input :class:`vtkm::cont::DataSet` contains a :class:`vtkm::cont::ArrayHandle` (see :chapref:`basic-array-handles:Basic Array Handles`), but you do not know what the template parameters of the :class:`vtkm::cont::ArrayHandle` are. There are numerous ways to extract an array of an unknown type out of a :class:`vtkm::cont::ArrayHandle` (many of which will be explored later in Chapter \ref{chap:UnknownArrayHandle}), but the :class:`vtkm::filter::FilterField` contains some convenience functions to simplify this. -.. todo:: Fix above reference. +.. todo:: Fix above reference to unknown array handle chapter. In particular, this filter operates specifically on scalar fields. For this purpose, :class:`vtkm::filter::FilterField` provides the :func:`vtkm::filter::FilterField::CastAndCallScalarField` helper method. @@ -115,4 +115,4 @@ This chapter has just provided a brief introduction to creating filters. There are several more filter superclasses to help express algorithms of different types. After some more worklet concepts to implement more complex algorithms are introduced in :partref:`part-advanced:Advanced Development`, we will see a more complete documentation of the types of filters in Chapter \ref{chap:FilterTypeReference}. -.. todo:: Fix above reference. +.. todo:: Fix above reference to filter type reference. diff --git a/docs/users-guide/conf.py b/docs/users-guide/conf.py index 7e1b629ab..43a0fcbff 100644 --- a/docs/users-guide/conf.py +++ b/docs/users-guide/conf.py @@ -75,6 +75,7 @@ today_fmt = '%B %d, %Y' rst_prolog = ''' .. |VTKm| replace:: VTK‑m +.. |Veclike| replace:: ``Vec``-like .. |report-year| replace:: 2023 .. |report-number| replace:: ORNL/TM-2023/3182 ''' diff --git a/docs/users-guide/examples/CMakeLists.txt b/docs/users-guide/examples/CMakeLists.txt index 322668d50..6cd1cc18e 100644 --- a/docs/users-guide/examples/CMakeLists.txt +++ b/docs/users-guide/examples/CMakeLists.txt @@ -15,13 +15,17 @@ set(examples GuideExampleEnvironmentModifierMacros.cxx GuideExampleInitialization.cxx GuideExampleIO.cxx + GuideExampleLists.cxx GuideExampleProvidedFilters.cxx GuideExampleRendering.cxx GuideExampleRuntimeDeviceTracker.cxx GuideExampleTimer.cxx + GuideExampleTraits.cxx + GuideExampleTuple.cxx ) set(examples_device GuideExampleCellEdgesFaces.cxx + GuideExampleCellLocator.cxx GuideExampleDataSetCreation.cxx GuideExampleErrorHandling.cxx GuideExampleSimpleAlgorithm.cxx diff --git a/docs/users-guide/examples/GuideExampleCellLocator.cxx b/docs/users-guide/examples/GuideExampleCellLocator.cxx new file mode 100644 index 000000000..aa40a2cd9 --- /dev/null +++ b/docs/users-guide/examples/GuideExampleCellLocator.cxx @@ -0,0 +1,175 @@ +//============================================================================= +// +// Copyright (c) Kitware, Inc. +// All rights reserved. +// See LICENSE.txt for details. +// +// This software is distributed WITHOUT ANY WARRANTY; without even +// the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR +// PURPOSE. See the above copyright notice for more information. +// +//============================================================================= + +#include + +#include +#include +#include +#include +#include + +#include + +#include + +#include + +namespace +{ + +constexpr vtkm::Id DimensionSize = 50; +const vtkm::Id3 DimensionSizes = vtkm::Id3(DimensionSize); + +//// +//// BEGIN-EXAMPLE UseCellLocator +//// +struct QueryCellsWorklet : public vtkm::worklet::WorkletMapField +{ + using ControlSignature = + void(FieldIn, ExecObject, WholeCellSetIn, WholeArrayIn, FieldOut); + using ExecutionSignature = void(_1, _2, _3, _4, _5); + + template + VTKM_EXEC void operator()(const Point& point, + const CellLocatorExecObject& cellLocator, + const CellSet& cellSet, + const FieldPortal& field, + OutType& out) const + { + // Use the cell locator to find the cell containing the point and the parametric + // coordinates within that cell. + vtkm::Id cellId; + vtkm::Vec3f parametric; + //// + //// BEGIN-EXAMPLE HandleErrorCode + //// + vtkm::ErrorCode status = cellLocator.FindCell(point, cellId, parametric); + if (status != vtkm::ErrorCode::Success) + { + this->RaiseError(vtkm::ErrorString(status)); + } + //// + //// END-EXAMPLE HandleErrorCode + //// + + // Use this information to interpolate the point field to the given location. + if (cellId >= 0) + { + // Get shape information about the cell containing the point coordinate + auto cellShape = cellSet.GetCellShape(cellId); + auto indices = cellSet.GetIndices(cellId); + + // Make a Vec-like containing the field data at the cell's points + auto fieldValues = vtkm::make_VecFromPortalPermute(&indices, &field); + + // Do the interpolation + vtkm::exec::CellInterpolate(fieldValues, parametric, cellShape, out); + } + else + { + this->RaiseError("Given point outside of the cell set."); + } + } +}; + +// +// Later in the associated Filter class... +// + +//// PAUSE-EXAMPLE +struct DemoQueryCells +{ + vtkm::cont::Invoker Invoke; + + vtkm::cont::ArrayHandle QueryPoints; + + template + VTKM_CONT vtkm::cont::ArrayHandle Run( + const vtkm::cont::DataSet& inDataSet, + const vtkm::cont::ArrayHandle& inputField) + { + //// RESUME-EXAMPLE + //// + //// BEGIN-EXAMPLE ConstructCellLocator + //// + vtkm::cont::CellLocatorGeneral cellLocator; + cellLocator.SetCellSet(inDataSet.GetCellSet()); + cellLocator.SetCoordinates(inDataSet.GetCoordinateSystem()); + cellLocator.Update(); + //// + //// END-EXAMPLE ConstructCellLocator + //// + + vtkm::cont::ArrayHandle interpolatedField; + + this->Invoke(QueryCellsWorklet{}, + this->QueryPoints, + &cellLocator, + inDataSet.GetCellSet(), + inputField, + interpolatedField); + //// + //// END-EXAMPLE UseCellLocator + //// + + return interpolatedField; + } +}; + +void TestCellLocator() +{ + using ValueType = vtkm::Vec3f; + using ArrayType = vtkm::cont::ArrayHandle; + + vtkm::cont::DataSet data = vtkm::cont::DataSetBuilderUniform::Create(DimensionSizes); + + ArrayType inField; + vtkm::cont::ArrayCopy(vtkm::cont::ArrayHandleUniformPointCoordinates( + DimensionSizes, ValueType(0.0f), ValueType(2.0f)), + inField); + + DemoQueryCells demo; + + vtkm::cont::ArrayCopy(vtkm::cont::ArrayHandleUniformPointCoordinates( + DimensionSizes - vtkm::Id3(1), ValueType(0.5f)), + demo.QueryPoints); + + ArrayType interpolated = demo.Run(data, inField); + + vtkm::cont::ArrayHandleUniformPointCoordinates expected( + DimensionSizes - vtkm::Id3(1), ValueType(1.0f), ValueType(2.0f)); + + std::cout << "Expected: "; + vtkm::cont::printSummary_ArrayHandle(expected, std::cout); + + std::cout << "Interpolated: "; + vtkm::cont::printSummary_ArrayHandle(interpolated, std::cout); + + VTKM_TEST_ASSERT(test_equal_portals(expected.ReadPortal(), interpolated.ReadPortal())); +} + +void Run() +{ + TestCellLocator(); +} + +} // anonymous namespace + +int GuideExampleCellLocator(int argc, char* argv[]) +{ + return vtkm::cont::testing::Testing::Run(Run, argc, argv); +} diff --git a/docs/users-guide/examples/GuideExampleLists.cxx b/docs/users-guide/examples/GuideExampleLists.cxx new file mode 100644 index 000000000..b95abc610 --- /dev/null +++ b/docs/users-guide/examples/GuideExampleLists.cxx @@ -0,0 +1,476 @@ +//============================================================================= +// +// Copyright (c) Kitware, Inc. +// All rights reserved. +// See LICENSE.txt for details. +// +// This software is distributed WITHOUT ANY WARRANTY; without even +// the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR +// PURPOSE. See the above copyright notice for more information. +// +//============================================================================= + +#include +#include + +namespace +{ + +//// +//// BEGIN-EXAMPLE CustomTypeLists +//// +// A list of 2D vector types. +using Vec2List = vtkm::List; + +// An application that uses 2D geometry might commonly encounter this list of +// types. +using MyCommonTypes = vtkm::ListAppend; +//// +//// END-EXAMPLE CustomTypeLists +//// + +VTKM_STATIC_ASSERT((std::is_same, vtkm::Vec2f_32>::value)); +VTKM_STATIC_ASSERT((std::is_same, vtkm::Vec2f_64>::value)); + +VTKM_STATIC_ASSERT((std::is_same>::value)); + +} // anonymous namespace + +#include + +#include + +#include +#include +#include + +//// +//// BEGIN-EXAMPLE BaseLists +//// +#include +//// PAUSE-EXAMPLE +namespace +{ +//// RESUME-EXAMPLE + +// Placeholder classes representing things that might be in a template +// metaprogram list. +class Foo; +class Bar; +class Baz; +class Qux; +class Xyzzy; + +// The names of the following tags are indicative of the lists they contain. + +using FooList = vtkm::List; + +using FooBarList = vtkm::List; + +using BazQuxXyzzyList = vtkm::List; + +using QuxBazBarFooList = vtkm::List; +//// +//// END-EXAMPLE BaseLists +//// + +class Foo +{ +}; +class Bar +{ +}; +class Baz +{ +}; +class Qux +{ +}; +class Xyzzy +{ +}; + +struct ListFunctor +{ + std::string FoundTags; + + template + void operator()(T) + { + this->FoundTags.append(vtkm::testing::TypeName::Name()); + } + + void operator()(Foo) { this->FoundTags.append("Foo"); } + void operator()(Bar) { this->FoundTags.append("Bar"); } + void operator()(Baz) { this->FoundTags.append("Baz"); } + void operator()(Qux) { this->FoundTags.append("Qux"); } + void operator()(Xyzzy) { this->FoundTags.append("Xyzzy"); } +}; + +template +void TryList(List, const char* expectedString) +{ + ListFunctor checkFunctor; + vtkm::ListForEach(checkFunctor, List()); + std::cout << std::endl + << "Expected " << expectedString << std::endl + << "Found " << checkFunctor.FoundTags << std::endl; + VTKM_TEST_ASSERT(checkFunctor.FoundTags == expectedString, "List wrong"); +} + +void TestBaseLists() +{ + TryList(FooList(), "Foo"); + TryList(FooBarList(), "FooBar"); + TryList(BazQuxXyzzyList(), "BazQuxXyzzy"); + TryList(QuxBazBarFooList(), "QuxBazBarFoo"); +} + +//// +//// BEGIN-EXAMPLE VTKM_IS_LIST +//// +template +class MyImportantClass +{ + VTKM_IS_LIST(List); + // Implementation... +}; + +void DoImportantStuff() +{ + MyImportantClass> important1; // This compiles fine + //// PAUSE-EXAMPLE +#if 0 + //// RESUME-EXAMPLE + MyImportantClass important2; // COMPILE ERROR: vtkm::Id is not a list + //// + //// END-EXAMPLE VTKM_IS_LIST + //// + //// PAUSE-EXAMPLE +#endif + + (void)important1; // Quiet compiler + //// RESUME-EXAMPLE +} + +void TestCheckListType() +{ + DoImportantStuff(); +} + +void TestListSize() +{ + //// + //// BEGIN-EXAMPLE ListSize + //// + using MyList = vtkm::List; + + constexpr vtkm::IdComponent myListSize = vtkm::ListSize::value; + // myListSize is 3 + //// + //// END-EXAMPLE ListSize + //// + VTKM_STATIC_ASSERT(myListSize == 3); +} + +void TestListHas() +{ + //// + //// BEGIN-EXAMPLE ListHas + //// + using MyList = vtkm::List; + + constexpr bool hasInt = vtkm::ListHas::value; + // hasInt is true + + constexpr bool hasFloat = vtkm::ListHas::value; + // hasFloat is false + //// + //// END-EXAMPLE ListHas + //// + VTKM_STATIC_ASSERT(hasInt); + VTKM_STATIC_ASSERT(!hasFloat); +} + +void TestListIndices() +{ + //// + //// BEGIN-EXAMPLE ListIndices + //// + using MyList = vtkm::List; + + constexpr vtkm::IdComponent indexOfInt8 = vtkm::ListIndexOf::value; + // indexOfInt8 is 0 + constexpr vtkm::IdComponent indexOfInt32 = + vtkm::ListIndexOf::value; + // indexOfInt32 is 1 + constexpr vtkm::IdComponent indexOfInt64 = + vtkm::ListIndexOf::value; + // indexOfInt64 is 2 + constexpr vtkm::IdComponent indexOfFloat32 = + vtkm::ListIndexOf::value; + // indexOfFloat32 is -1 (not in list) + + using T0 = vtkm::ListAt; // T0 is vtkm::Int8 + using T1 = vtkm::ListAt; // T1 is vtkm::Int32 + using T2 = vtkm::ListAt; // T2 is vtkm::Int64 + //// + //// END-EXAMPLE ListIndices + //// + VTKM_TEST_ASSERT(indexOfInt8 == 0); + VTKM_TEST_ASSERT(indexOfInt32 == 1); + VTKM_TEST_ASSERT(indexOfInt64 == 2); + VTKM_TEST_ASSERT(indexOfFloat32 == -1); + + VTKM_STATIC_ASSERT((std::is_same::value)); + VTKM_STATIC_ASSERT((std::is_same::value)); + VTKM_STATIC_ASSERT((std::is_same::value)); +} + +namespace TestListAppend +{ +//// +//// BEGIN-EXAMPLE ListAppend +//// +using BigTypes = vtkm::List; +using MediumTypes = vtkm::List; +using SmallTypes = vtkm::List; + +using SmallAndBigTypes = vtkm::ListAppend; +// SmallAndBigTypes is vtkm::List + +using AllMyTypes = vtkm::ListAppend; +// AllMyTypes is +// vtkm::List +//// +//// END-EXAMPLE ListAppend +//// +VTKM_STATIC_ASSERT( + (std::is_same>::value)); +VTKM_STATIC_ASSERT( + (std::is_same< + AllMyTypes, + vtkm::List>:: + value)); +} + +namespace TestListIntersect +{ +//// +//// BEGIN-EXAMPLE ListIntersect +//// +using SignedInts = vtkm::List; +using WordTypes = vtkm::List; + +using SignedWords = vtkm::ListIntersect; +// SignedWords is vtkm::List +//// +//// END-EXAMPLE ListIntersect +//// +VTKM_STATIC_ASSERT( + (std::is_same>::value)); +} + +namespace TestListApply +{ +//// +//// BEGIN-EXAMPLE ListApply +//// +using MyList = vtkm::List; + +using MyTuple = vtkm::ListApply; +// MyTuple is std::tuple +//// +//// END-EXAMPLE ListApply +//// +VTKM_STATIC_ASSERT( + (std::is_same>::value)); +} + +namespace TestListTransform +{ +//// +//// BEGIN-EXAMPLE ListTransform +//// +using MyList = vtkm::List; + +template +using MakeVec = vtkm::Vec; + +using MyVecList = vtkm::ListTransform; +// MyVecList is vtkm::List, vtkm::Vec> +//// +//// END-EXAMPLE ListTransform +//// +VTKM_STATIC_ASSERT((std::is_same, + vtkm::Vec>>::value)); +} + +namespace TestListRemoveIf +{ +//// +//// BEGIN-EXAMPLE ListRemoveIf +//// +using MyList = + vtkm::List; + +using FilteredList = vtkm::ListRemoveIf; +// FilteredList is vtkm::List +//// +//// END-EXAMPLE ListRemoveIf +//// +VTKM_STATIC_ASSERT( + (std::is_same>::value)); +} + +namespace TestListCross +{ +//// +//// BEGIN-EXAMPLE ListCross +//// +using BaseTypes = vtkm::List; +using BoolCases = vtkm::List; + +using CrossTypes = vtkm::ListCross; +// CrossTypes is +// vtkm::List, +// vtkm::List, +// vtkm::List, +// vtkm::List, +// vtkm::List, +// vtkm::List> + +template +using ListPairToType = + typename std::conditional::value, + vtkm::Vec, 3>, + vtkm::ListAt>::type; + +using AllTypes = vtkm::ListTransform; +// AllTypes is +// vtkm::List, +// vtkm::Int32, +// vtkm::Vec, +// vtkm::Int64, +// vtkm::Vec> +//// +//// END-EXAMPLE ListCross +//// +VTKM_STATIC_ASSERT( + (std::is_same, + vtkm::List, + vtkm::List, + vtkm::List, + vtkm::List, + vtkm::List>>::value)); + +VTKM_STATIC_ASSERT((std::is_same, + vtkm::Int32, + vtkm::Vec, + vtkm::Int64, + vtkm::Vec>>::value)); +} + +//// +//// BEGIN-EXAMPLE ListForEach +//// +struct MyArrayBase +{ + // A virtual destructor makes sure C++ RTTI will be generated. It also helps + // ensure subclass destructors are called. + virtual ~MyArrayBase() {} +}; + +template +struct MyArrayImpl : public MyArrayBase +{ + std::vector Array; +}; + +template +void PrefixSum(std::vector& array) +{ + T sum(typename vtkm::VecTraits::ComponentType(0)); + for (typename std::vector::iterator iter = array.begin(); iter != array.end(); + iter++) + { + sum = sum + *iter; + *iter = sum; + } +} + +struct PrefixSumFunctor +{ + MyArrayBase* ArrayPointer; + + PrefixSumFunctor(MyArrayBase* arrayPointer) + : ArrayPointer(arrayPointer) + { + } + + template + void operator()(T) + { + using ConcreteArrayType = MyArrayImpl; + ConcreteArrayType* concreteArray = + dynamic_cast(this->ArrayPointer); + if (concreteArray != NULL) + { + PrefixSum(concreteArray->Array); + } + } +}; + +void DoPrefixSum(MyArrayBase* array) +{ + PrefixSumFunctor functor = PrefixSumFunctor(array); + vtkm::ListForEach(functor, vtkm::TypeListCommon()); +} +//// +//// END-EXAMPLE ListForEach +//// + +void TestPrefixSum() +{ + MyArrayImpl array; + array.Array.resize(10); + std::fill(array.Array.begin(), array.Array.end(), 1); + DoPrefixSum(&array); + for (vtkm::Id index = 0; index < 10; index++) + { + VTKM_TEST_ASSERT(array.Array[(std::size_t)index] == index + 1, + "Got bad prefix sum."); + } +} + +void Test() +{ + TestBaseLists(); + TestCheckListType(); + TestListSize(); + TestListHas(); + TestListIndices(); + TestPrefixSum(); +} + +} // anonymous namespace + +int GuideExampleLists(int argc, char* argv[]) +{ + return vtkm::testing::Testing::Run(Test, argc, argv); +} diff --git a/docs/users-guide/examples/GuideExampleTraits.cxx b/docs/users-guide/examples/GuideExampleTraits.cxx new file mode 100644 index 000000000..c32d25e25 --- /dev/null +++ b/docs/users-guide/examples/GuideExampleTraits.cxx @@ -0,0 +1,359 @@ +//============================================================================= +// +// Copyright (c) Kitware, Inc. +// All rights reserved. +// See LICENSE.txt for details. +// +// This software is distributed WITHOUT ANY WARRANTY; without even +// the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR +// PURPOSE. See the above copyright notice for more information. +// +//============================================================================= + +#include +#include + +#include + +//// +//// BEGIN-EXAMPLE TypeTraits +//// +#include + +#include +//// PAUSE-EXAMPLE +namespace TraitsExamples +{ +//// RESUME-EXAMPLE + +template +T AnyRemainder(const T& numerator, const T& denominator); + +namespace detail +{ + +template +T AnyRemainderImpl(const T& numerator, + const T& denominator, + vtkm::TypeTraitsIntegerTag, + vtkm::TypeTraitsScalarTag) +{ + return numerator % denominator; +} + +template +T AnyRemainderImpl(const T& numerator, + const T& denominator, + vtkm::TypeTraitsRealTag, + vtkm::TypeTraitsScalarTag) +{ + // The VTK-m math library contains a Remainder function that operates on + // floating point numbers. + return vtkm::Remainder(numerator, denominator); +} + +template +T AnyRemainderImpl(const T& numerator, + const T& denominator, + NumericTag, + vtkm::TypeTraitsVectorTag) +{ + T result; + for (int componentIndex = 0; componentIndex < T::NUM_COMPONENTS; componentIndex++) + { + result[componentIndex] = + AnyRemainder(numerator[componentIndex], denominator[componentIndex]); + } + return result; +} + +} // namespace detail + +template +T AnyRemainder(const T& numerator, const T& denominator) +{ + return detail::AnyRemainderImpl(numerator, + denominator, + typename vtkm::TypeTraits::NumericTag(), + typename vtkm::TypeTraits::DimensionalityTag()); +} +//// +//// END-EXAMPLE TypeTraits +//// + +void TryRemainder() +{ + vtkm::Id m1 = AnyRemainder(7, 3); + VTKM_TEST_ASSERT(m1 == 1, "Got bad remainder"); + + vtkm::Float32 m2 = AnyRemainder(7.0f, 3.0f); + VTKM_TEST_ASSERT(test_equal(m2, 1), "Got bad remainder"); + + vtkm::Id3 m3 = AnyRemainder(vtkm::Id3(10, 9, 8), vtkm::Id3(7, 6, 5)); + VTKM_TEST_ASSERT(test_equal(m3, vtkm::Id3(3, 3, 3)), "Got bad remainder"); + + vtkm::Vec3f_32 m4 = AnyRemainder(vtkm::make_Vec(10, 9, 8), vtkm::make_Vec(7, 6, 5)); + VTKM_TEST_ASSERT(test_equal(m4, vtkm::make_Vec(3, 3, 3)), "Got bad remainder"); +} + +template +struct TypeTraits; + +//// +//// BEGIN-EXAMPLE TypeTraitsImpl +//// +//// PAUSE-EXAMPLE +#if 0 +//// RESUME-EXAMPLE +namespace vtkm { +//// PAUSE-EXAMPLE +#endif +//// RESUME-EXAMPLE + +template<> +struct TypeTraits +{ + using NumericTag = vtkm::TypeTraitsRealTag; + using DimensionalityTag = vtkm::TypeTraitsScalarTag; + + VTKM_EXEC_CONT + static vtkm::Float32 ZeroInitialization() { return vtkm::Float32(0); } +}; + +//// PAUSE-EXAMPLE +#if 0 +//// RESUME-EXAMPLE +} +//// PAUSE-EXAMPLE +#endif +//// RESUME-EXAMPLE +//// +//// END-EXAMPLE TypeTraitsImpl +//// + +void TryCustomTypeTraits() +{ + using CustomTraits = TraitsExamples::TypeTraits; + using OriginalTraits = vtkm::TypeTraits; + + VTKM_STATIC_ASSERT( + (std::is_same::value)); + VTKM_STATIC_ASSERT((std::is_same::value)); + + VTKM_TEST_ASSERT(CustomTraits::ZeroInitialization() == + OriginalTraits::ZeroInitialization(), + "Bad zero initialization."); +} + +} // namespace TraitsExamples + +//// +//// BEGIN-EXAMPLE VecTraits +//// +#include +//// PAUSE-EXAMPLE +namespace TraitsExamples +{ +//// RESUME-EXAMPLE + +// This functor provides a total ordering of vectors. Every compared vector +// will be either less, greater, or equal (assuming all the vector components +// also have a total ordering). +template +struct LessTotalOrder +{ + VTKM_EXEC_CONT + bool operator()(const T& left, const T& right) + { + for (int index = 0; index < vtkm::VecTraits::NUM_COMPONENTS; index++) + { + using ComponentType = typename vtkm::VecTraits::ComponentType; + const ComponentType& leftValue = vtkm::VecTraits::GetComponent(left, index); + const ComponentType& rightValue = vtkm::VecTraits::GetComponent(right, index); + if (leftValue < rightValue) + { + return true; + } + if (rightValue < leftValue) + { + return false; + } + } + // If we are here, the vectors are equal (or at least equivalent). + return false; + } +}; + +// This functor provides a partial ordering of vectors. It returns true if and +// only if all components satisfy the less operation. It is possible for +// vectors to be neither less, greater, nor equal, but the transitive closure +// is still valid. +template +struct LessPartialOrder +{ + VTKM_EXEC_CONT + bool operator()(const T& left, const T& right) + { + for (int index = 0; index < vtkm::VecTraits::NUM_COMPONENTS; index++) + { + using ComponentType = typename vtkm::VecTraits::ComponentType; + const ComponentType& leftValue = vtkm::VecTraits::GetComponent(left, index); + const ComponentType& rightValue = vtkm::VecTraits::GetComponent(right, index); + if (!(leftValue < rightValue)) + { + return false; + } + } + // If we are here, all components satisfy less than relation. + return true; + } +}; +//// +//// END-EXAMPLE VecTraits +//// + +void TryLess() +{ + LessTotalOrder totalLess1; + VTKM_TEST_ASSERT(totalLess1(1, 2), "Bad less."); + VTKM_TEST_ASSERT(!totalLess1(2, 1), "Bad less."); + VTKM_TEST_ASSERT(!totalLess1(1, 1), "Bad less."); + + LessPartialOrder partialLess1; + VTKM_TEST_ASSERT(partialLess1(1, 2), "Bad less."); + VTKM_TEST_ASSERT(!partialLess1(2, 1), "Bad less."); + VTKM_TEST_ASSERT(!partialLess1(1, 1), "Bad less."); + + LessTotalOrder totalLess3; + VTKM_TEST_ASSERT(totalLess3(vtkm::Id3(1, 2, 3), vtkm::Id3(3, 2, 1)), "Bad less."); + VTKM_TEST_ASSERT(!totalLess3(vtkm::Id3(3, 2, 1), vtkm::Id3(1, 2, 3)), "Bad less."); + VTKM_TEST_ASSERT(!totalLess3(vtkm::Id3(1, 2, 3), vtkm::Id3(1, 2, 3)), "Bad less."); + VTKM_TEST_ASSERT(totalLess3(vtkm::Id3(1, 2, 3), vtkm::Id3(2, 3, 4)), "Bad less."); + + LessPartialOrder partialLess3; + VTKM_TEST_ASSERT(!partialLess3(vtkm::Id3(1, 2, 3), vtkm::Id3(3, 2, 1)), "Bad less."); + VTKM_TEST_ASSERT(!partialLess3(vtkm::Id3(3, 2, 1), vtkm::Id3(1, 2, 3)), "Bad less."); + VTKM_TEST_ASSERT(!partialLess3(vtkm::Id3(1, 2, 3), vtkm::Id3(1, 2, 3)), "Bad less."); + VTKM_TEST_ASSERT(partialLess3(vtkm::Id3(1, 2, 3), vtkm::Id3(2, 3, 4)), "Bad less."); +} + +template +struct VecTraits; + +//// +//// BEGIN-EXAMPLE VecTraitsImpl +//// +//// PAUSE-EXAMPLE +#if 0 +//// RESUME-EXAMPLE +namespace vtkm { +//// PAUSE-EXAMPLE +#endif +//// RESUME-EXAMPLE + +template<> +struct VecTraits +{ + using ComponentType = vtkm::Id; + using BaseComponentType = vtkm::Id; + static const int NUM_COMPONENTS = 3; + using IsSizeStatic = vtkm::VecTraitsTagSizeStatic; + using HasMultipleComponents = vtkm::VecTraitsTagMultipleComponents; + + VTKM_EXEC_CONT + static vtkm::IdComponent GetNumberOfComponents(const vtkm::Id3&) + { + return NUM_COMPONENTS; + } + + VTKM_EXEC_CONT + static const vtkm::Id& GetComponent(const vtkm::Id3& vector, int component) + { + return vector[component]; + } + VTKM_EXEC_CONT + static vtkm::Id& GetComponent(vtkm::Id3& vector, int component) + { + return vector[component]; + } + + VTKM_EXEC_CONT + static void SetComponent(vtkm::Id3& vector, int component, vtkm::Id value) + { + vector[component] = value; + } + + template + using ReplaceComponentType = vtkm::Vec; + + template + using ReplaceBaseComponentType = vtkm::Vec; + + template + VTKM_EXEC_CONT static void CopyInto(const vtkm::Id3& src, + vtkm::Vec& dest) + { + for (vtkm::IdComponent index = 0; (index < NUM_COMPONENTS) && (index < DestSize); + index++) + { + dest[index] = src[index]; + } + } +}; + +//// PAUSE-EXAMPLE +#if 0 +//// RESUME-EXAMPLE +} // namespace vtkm +//// PAUSE-EXAMPLE +#endif +//// RESUME-EXAMPLE +//// +//// END-EXAMPLE VecTraitsImpl +//// + +void TryCustomVecTriats() +{ + using CustomTraits = TraitsExamples::VecTraits; + using OriginalTraits = vtkm::VecTraits; + + VTKM_STATIC_ASSERT( + (std::is_same::value)); + VTKM_STATIC_ASSERT(CustomTraits::NUM_COMPONENTS == OriginalTraits::NUM_COMPONENTS); + VTKM_STATIC_ASSERT((std::is_same::value)); + VTKM_STATIC_ASSERT( + (std::is_same::value)); + + vtkm::Id3 value = TestValue(10, vtkm::Id3()); + VTKM_TEST_ASSERT(CustomTraits::GetNumberOfComponents(value) == + OriginalTraits::GetNumberOfComponents(value), + "Wrong size."); + VTKM_TEST_ASSERT(CustomTraits::GetComponent(value, 1) == + OriginalTraits::GetComponent(value, 1), + "Wrong component."); + + CustomTraits::SetComponent(value, 2, 0); + VTKM_TEST_ASSERT(value[2] == 0, "Did not set component."); + + vtkm::Id2 shortValue; + CustomTraits::CopyInto(value, shortValue); + VTKM_TEST_ASSERT(test_equal(shortValue[0], value[0])); + VTKM_TEST_ASSERT(test_equal(shortValue[1], value[1])); +} + +void Test() +{ + TryRemainder(); + TryCustomTypeTraits(); + TryLess(); + TryCustomVecTriats(); +} + +} // namespace TraitsExamples + +int GuideExampleTraits(int argc, char* argv[]) +{ + return vtkm::testing::Testing::Run(TraitsExamples::Test, argc, argv); +} diff --git a/docs/users-guide/examples/GuideExampleTuple.cxx b/docs/users-guide/examples/GuideExampleTuple.cxx new file mode 100644 index 000000000..39dde77e5 --- /dev/null +++ b/docs/users-guide/examples/GuideExampleTuple.cxx @@ -0,0 +1,364 @@ +//============================================================================= +// +// Copyright (c) Kitware, Inc. +// All rights reserved. +// See LICENSE.txt for details. +// +// This software is distributed WITHOUT ANY WARRANTY; without even +// the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR +// PURPOSE. See the above copyright notice for more information. +// +//============================================================================= + +#include + +#include +#include + +#include + +namespace +{ + +constexpr vtkm::Id ARRAY_SIZE = 10; + +void Define() +{ + //// + //// BEGIN-EXAMPLE DefineTuple + //// + vtkm::Tuple> myTuple; + //// + //// END-EXAMPLE DefineTuple + //// + (void)myTuple; +} + +void Init() +{ + vtkm::cont::ArrayHandle array; + + //// + //// BEGIN-EXAMPLE InitTuple + //// + // Initialize a tuple with 0, [0, 1, 2], and an existing ArrayHandle. + vtkm::Tuple> myTuple1( + 0, vtkm::Vec3f(0, 1, 2), array); + + // Another way to create the same tuple. + auto myTuple2 = vtkm::MakeTuple(vtkm::Id(0), vtkm::Vec3f(0, 1, 2), array); + //// + //// END-EXAMPLE InitTuple + //// + + VTKM_TEST_ASSERT(std::is_same::value); + VTKM_TEST_ASSERT(vtkm::Get<0>(myTuple1) == 0); + VTKM_TEST_ASSERT(vtkm::Get<0>(myTuple2) == 0); + VTKM_TEST_ASSERT(test_equal(vtkm::Get<1>(myTuple1), vtkm::Vec3f(0, 1, 2))); + VTKM_TEST_ASSERT(test_equal(vtkm::Get<1>(myTuple2), vtkm::Vec3f(0, 1, 2))); +} + +void Query() +{ + //// + //// BEGIN-EXAMPLE TupleQuery + //// + using TupleType = vtkm::Tuple; + + // Becomes 3 + constexpr vtkm::IdComponent size = vtkm::TupleSize::value; + + using FirstType = vtkm::TupleElement<0, TupleType>; // vtkm::Id + using SecondType = vtkm::TupleElement<1, TupleType>; // vtkm::Float32 + using ThirdType = vtkm::TupleElement<2, TupleType>; // vtkm::Float64 + //// + //// END-EXAMPLE TupleQuery + //// + + VTKM_TEST_ASSERT(size == 3); + VTKM_TEST_ASSERT(std::is_same::value); + VTKM_TEST_ASSERT(std::is_same::value); + VTKM_TEST_ASSERT(std::is_same::value); +} + +void Get() +{ + //// + //// BEGIN-EXAMPLE TupleGet + //// + auto myTuple = vtkm::MakeTuple(vtkm::Id3(0, 1, 2), vtkm::Vec3f(3, 4, 5)); + + // Gets the value [0, 1, 2] + vtkm::Id3 x = vtkm::Get<0>(myTuple); + + // Changes the second object in myTuple to [6, 7, 8] + vtkm::Get<1>(myTuple) = vtkm::Vec3f(6, 7, 8); + //// + //// END-EXAMPLE TupleGet + //// + + VTKM_TEST_ASSERT(x == vtkm::Id3(0, 1, 2)); + VTKM_TEST_ASSERT(test_equal(vtkm::Get<1>(myTuple), vtkm::Vec3f(6, 7, 8))); +} + +vtkm::Int16 CreateValue(vtkm::Id index) +{ + return TestValue(index, vtkm::Int16{}); +} + +//// +//// BEGIN-EXAMPLE TupleCheck +//// +void CheckPositive(vtkm::Float64 x) +{ + if (x < 0) + { + throw vtkm::cont::ErrorBadValue("Values need to be positive."); + } +} + +// ... + +//// PAUSE-EXAMPLE +void ForEachCheck() +{ + //// RESUME-EXAMPLE + vtkm::Tuple tuple( + CreateValue(0), CreateValue(1), CreateValue(2)); + + // Will throw an error if any of the values are negative. + vtkm::ForEach(tuple, CheckPositive); + //// + //// END-EXAMPLE TupleCheck + //// +} + +//// +//// BEGIN-EXAMPLE TupleAggregate +//// +struct SumFunctor +{ + vtkm::Float64 Sum = 0; + + template + void operator()(const T& x) + { + this->Sum = this->Sum + static_cast(x); + } +}; + +// ... + +//// PAUSE-EXAMPLE +void ForEachAggregate() +{ + //// RESUME-EXAMPLE + vtkm::Tuple tuple( + CreateValue(0), CreateValue(1), CreateValue(2)); + + SumFunctor sum; + vtkm::ForEach(tuple, sum); + vtkm::Float64 average = sum.Sum / 3; + //// + //// END-EXAMPLE TupleAggregate + //// + + VTKM_TEST_ASSERT(test_equal(average, 101)); +} + +void ForEachAggregateLambda() +{ + //// + //// BEGIN-EXAMPLE TupleAggregateLambda + //// + vtkm::Tuple tuple( + CreateValue(0), CreateValue(1), CreateValue(2)); + + vtkm::Float64 sum = 0; + auto sumFunctor = [&sum](auto x) { sum += static_cast(x); }; + + vtkm::ForEach(tuple, sumFunctor); + vtkm::Float64 average = sum / 3; + //// + //// END-EXAMPLE TupleAggregateLambda + //// + + VTKM_TEST_ASSERT(test_equal(average, 101)); +} + +//// +//// BEGIN-EXAMPLE TupleTransform +//// +struct GetReadPortalFunctor +{ + template + typename Array::ReadPortalType operator()(const Array& array) const + { + VTKM_IS_ARRAY_HANDLE(Array); + return array.ReadPortal(); + } +}; + +// ... + +//// PAUSE-EXAMPLE +void Transform() +{ + vtkm::cont::ArrayHandle array1; + array1.Allocate(ARRAY_SIZE); + SetPortal(array1.WritePortal()); + + vtkm::cont::ArrayHandle array2; + array2.Allocate(ARRAY_SIZE); + SetPortal(array2.WritePortal()); + + vtkm::cont::ArrayHandle array3; + array3.Allocate(ARRAY_SIZE); + SetPortal(array3.WritePortal()); + + //// RESUME-EXAMPLE + auto arrayTuple = vtkm::MakeTuple(array1, array2, array3); + + auto portalTuple = vtkm::Transform(arrayTuple, GetReadPortalFunctor{}); + //// + //// END-EXAMPLE TupleTransform + //// + + CheckPortal(vtkm::Get<0>(portalTuple)); + CheckPortal(vtkm::Get<1>(portalTuple)); + CheckPortal(vtkm::Get<2>(portalTuple)); +} + +//// +//// BEGIN-EXAMPLE TupleApply +//// +struct AddArraysFunctor +{ + template + vtkm::Id operator()(Array1 inArray1, Array2 inArray2, Array3 outArray) const + { + VTKM_IS_ARRAY_HANDLE(Array1); + VTKM_IS_ARRAY_HANDLE(Array2); + VTKM_IS_ARRAY_HANDLE(Array3); + + vtkm::Id length = inArray1.GetNumberOfValues(); + VTKM_ASSERT(inArray2.GetNumberOfValues() == length); + outArray.Allocate(length); + + auto inPortal1 = inArray1.ReadPortal(); + auto inPortal2 = inArray2.ReadPortal(); + auto outPortal = outArray.WritePortal(); + for (vtkm::Id index = 0; index < length; ++index) + { + outPortal.Set(index, inPortal1.Get(index) + inPortal2.Get(index)); + } + + return length; + } +}; + +// ... + +//// PAUSE-EXAMPLE +void Apply() +{ + vtkm::cont::ArrayHandle array1; + array1.Allocate(ARRAY_SIZE); + SetPortal(array1.WritePortal()); + + vtkm::cont::ArrayHandle array2; + vtkm::cont::ArrayCopy(array1, array2); + + vtkm::cont::ArrayHandle array3; + + //// RESUME-EXAMPLE + auto arrayTuple = vtkm::MakeTuple(array1, array2, array3); + + vtkm::Id arrayLength = vtkm::Apply(arrayTuple, AddArraysFunctor{}); + //// + //// END-EXAMPLE TupleApply + //// + + VTKM_TEST_ASSERT(arrayLength == ARRAY_SIZE); + + auto portal = array3.ReadPortal(); + VTKM_TEST_ASSERT(portal.GetNumberOfValues() == ARRAY_SIZE); + for (vtkm::Id i = 0; i < ARRAY_SIZE; ++i) + { + VTKM_TEST_ASSERT(test_equal(portal.Get(i), 2 * TestValue(i, vtkm::Float32{}))); + } +} + +//// +//// BEGIN-EXAMPLE TupleApplyExtraArgs +//// +struct ScanArrayLengthFunctor +{ + template + vtkm::Vec operator()( + const vtkm::Vec& partialResult, + const Array& nextArray, + const Remaining&... remainingArrays) const + { + vtkm::Vec nextResult; + std::copy(&partialResult[0], &partialResult[0] + N, &nextResult[0]); + nextResult[N] = nextResult[N - 1] + nextArray.GetNumberOfValues(); + return (*this)(nextResult, remainingArrays...); + } + + template + vtkm::Vec operator()(const vtkm::Vec& result) const + { + return result; + } +}; + +// ... + +//// PAUSE-EXAMPLE +void ApplyExtraArgs() +{ + vtkm::cont::ArrayHandle array1; + array1.Allocate(ARRAY_SIZE); + + vtkm::cont::ArrayHandle array2; + array2.Allocate(ARRAY_SIZE); + + vtkm::cont::ArrayHandle array3; + array3.Allocate(ARRAY_SIZE); + + //// RESUME-EXAMPLE + auto arrayTuple = vtkm::MakeTuple(array1, array2, array3); + + vtkm::Vec sizeScan = + vtkm::Apply(arrayTuple, ScanArrayLengthFunctor{}, vtkm::Vec{ 0 }); + //// + //// END-EXAMPLE TupleApplyExtraArgs + //// + + VTKM_TEST_ASSERT(sizeScan[0] == 0 * ARRAY_SIZE); + VTKM_TEST_ASSERT(sizeScan[1] == 1 * ARRAY_SIZE); + VTKM_TEST_ASSERT(sizeScan[2] == 2 * ARRAY_SIZE); + VTKM_TEST_ASSERT(sizeScan[3] == 3 * ARRAY_SIZE); +} + +void Run() +{ + Define(); + Init(); + Query(); + Get(); + ForEachCheck(); + ForEachAggregate(); + ForEachAggregateLambda(); + Transform(); + Apply(); + ApplyExtraArgs(); +} + +} // anonymous namespace + +int GuideExampleTuple(int argc, char* argv[]) +{ + return vtkm::cont::testing::Testing::Run(Run, argc, argv); +} diff --git a/docs/users-guide/io.rst b/docs/users-guide/io.rst index 0af979f7b..d3a7f8662 100644 --- a/docs/users-guide/io.rst +++ b/docs/users-guide/io.rst @@ -18,7 +18,7 @@ All the file I/O classes are declared under the ``vtkm::io`` namespace. increasing power and complexity. In particular, :secref:`dataset:Building Data Sets` describes how to build |VTKm| data set objects and Section \ref{sec:ArrayHandle:Adapting} documents how to adapt data structures defined in other libraries to be used directly in |VTKm|. -.. todo:: Add ArrayHandle section reference above. +.. todo:: Add custom ArrayHandle section reference above. ------------------------------ Readers diff --git a/docs/users-guide/part-advanced.rst b/docs/users-guide/part-advanced.rst index 9017faab1..5bcd983f0 100644 --- a/docs/users-guide/part-advanced.rst +++ b/docs/users-guide/part-advanced.rst @@ -1,3 +1,8 @@ ============================== Advanced Development ============================== + +.. toctree:: + :maxdepth: 2 + + advanced-types.rst diff --git a/docs/users-guide/provided-filters.rst b/docs/users-guide/provided-filters.rst index c8b677e8c..75715f658 100644 --- a/docs/users-guide/provided-filters.rst +++ b/docs/users-guide/provided-filters.rst @@ -412,8 +412,6 @@ The input and output of this filter are a structured data sets. .. doxygenclass:: vtkm::filter::entity_extraction::ExtractStructured :members: -.. todo:: Document vtkm::RangeId and vtkm::RangeId3 (in advanced types chapter). - Ghost Cell Removal ------------------------------ diff --git a/docs/users-guide/rendering.rst b/docs/users-guide/rendering.rst index 2c6406354..968e2a3da 100644 --- a/docs/users-guide/rendering.rst +++ b/docs/users-guide/rendering.rst @@ -511,7 +511,7 @@ First call :func:`vtkm::rendering::View::Paint` on the :class:`vtkm::rendering:: Second, get the image color data out of the :class:`vtkm::rendering::View`'s :class:`vtkm::rendering::Canvas` object. This is done by calling :func:`vtkm::rendering::Canvas::GetColorBuffer`. This will return a :class:`vtkm::cont::ArrayHandle` object containing the image's pixel color data. -(:class:`vtkm::cont::ArrayHandle` is discussed in detail in Chapter \ref{chap:BasicArrayHandles} and subsequent chapters.) +(:class:`vtkm::cont::ArrayHandle` is discussed in detail in :chapref:`basic-array-handles:Basic Array Handles` and subsequent chapters.) A raw pointer can be pulled out of this :class:`vtkm::cont::ArrayHandle` by casting it to the :class:`vtkm::cont::ArrayHandleBase` subclass and calling the :func:`vtkm::cont::ArrayHandleBase::GetReadPointer` method on that. Third, the pixel color data are pasted into the OpenGL render context. There are multiple ways to do so, but the most straightforward way is to use the ``glDrawPixels`` function provided by OpenGL. @@ -519,8 +519,6 @@ Fourth, swap the OpenGL buffers. The method to swap OpenGL buffers varies by OS platform. The aforementioned graphics libraries GLUT and GLFW each provide a function for doing so. -.. todo:: Fix chapter reference above. - .. load-example:: RenderToOpenGL :file: GuideExampleRenderingInteractive.cxx :caption: Rendering a :class:`vtkm::rendering::View` and pasting the result to an active OpenGL context. diff --git a/docs/users-guide/simple-worklets.rst b/docs/users-guide/simple-worklets.rst index b0aa80a7e..908c62bf6 100644 --- a/docs/users-guide/simple-worklets.rst +++ b/docs/users-guide/simple-worklets.rst @@ -63,7 +63,7 @@ The parameters of the function prototype are *tags* that identify the type of da ``ControlSignature`` tags are defined by the worklet type and the various tags are documented more fully in Chapter \ref{chap:WorkletTypeReference}. In the case of :numref:`ex:ControlSignature`, the two tags ``FieldIn`` and ``FieldOut`` represent input and output data, respectively. -.. todo:: Fix reference above. +.. todo:: Fix worklet type reference above. .. index:: single: control signature diff --git a/vtkm/Bounds.h b/vtkm/Bounds.h index 6cd30034b..601bc2e03 100644 --- a/vtkm/Bounds.h +++ b/vtkm/Bounds.h @@ -28,15 +28,24 @@ namespace vtkm /// struct Bounds { + /// The range of values in the X direction. The `vtkm::Range` struct provides + /// the minimum and maximum along that axis. vtkm::Range X; + /// The range of values in the Y direction. The `vtkm::Range` struct provides + /// the minimum and maximum along that axis. vtkm::Range Y; + /// The range of values in the Z direction. The `vtkm::Range` struct provides + /// the minimum and maximum along that axis. vtkm::Range Z; + /// Construct an empty bounds. The bounds will represent no space until + /// otherwise modified. VTKM_EXEC_CONT Bounds() {} Bounds(const Bounds&) = default; + /// Construct a bounds with a given range in the x, y, and z dimensions. VTKM_EXEC_CONT Bounds(const vtkm::Range& xRange, const vtkm::Range& yRange, const vtkm::Range& zRange) : X(xRange) @@ -45,6 +54,8 @@ struct Bounds { } + /// Construct a bounds with the minimum and maximum coordinates in the x, y, and z + /// directions. template VTKM_EXEC_CONT Bounds(const T1& minX, const T2& maxX, diff --git a/vtkm/ErrorCode.h b/vtkm/ErrorCode.h index d04e120ea..7ef94a0fc 100644 --- a/vtkm/ErrorCode.h +++ b/vtkm/ErrorCode.h @@ -16,8 +16,18 @@ namespace vtkm { +/// @brief Identifies whether an operation was successful or what type of error it had. +/// +/// Most errors in VTK-m are reported by throwing an exception. However, there are +/// some places, most notably the execution environment, where it is not possible +/// to throw an exception. For those cases, it is typical for a function to return +/// an `ErrorCode` identifier. The calling code can check to see if the operation was +/// a success or what kind of error was encountered otherwise. +/// +/// Use the `vtkm::ErrorString()` function to get a descriptive string of the error type. enum class ErrorCode { + // Documentation is below (for better layout in generated documents). Success, InvalidShapeId, InvalidNumberOfPoints, @@ -36,6 +46,87 @@ enum class ErrorCode UnknownError }; +/// @var ErrorCode Success +/// @brief A successful operation. +/// +/// This code is returned when the operation was successful. Calling code +/// should check the error code against this identifier when checking the +/// status. + +/// @var ErrorCode InvalidShapeId +/// @brief A unknown shape identifier was encountered. +/// +/// All cell shapes must be listed in `vtkm::CellShapeIdEnum`. + +/// @var ErrorCode InvalidNumberOfPoints +/// @brief The wrong number of points was provided for a given cell type. +/// +/// For example, if a triangle has 4 points associated with it, you are +/// likely to get this error. + +/// @var ErrorCode InvalidCellMetric +/// @brief A cell metric was requested for a cell that does not support that metric. + +/// @var ErrorCode WrongShapeIdForTagType +/// This is an internal error from the lightweight cell library. + +/// @var ErrorCode InvalidPointId +/// @brief A bad point identifier was detected while operating on a cell. + +/// @var ErrorCode InvalidEdgeId +/// @brief A bad edge identifier was detected while operating on a cell. + +/// @var ErrorCode InvalidFaceId +/// @brief A bad face identifier was detected while operating on a cell. + +/// @var ErrorCode SolutionDidNotConverge +/// @brief An iterative operation did not find an appropriate solution. +/// +/// This error code might be returned with some results of an iterative +/// solution. However, solution did not appear to resolve, so the results +/// might not be accurate. + +/// @var ErrorCode MatrixFactorizationFailed +/// @brief A solution was not found for a linear system. +/// +/// Some VTK-m computations use linear algebra to solve a system of equations. +/// If the equations does not give a valid result, this error can be returned. + +/// @var ErrorCode DegenerateCellDetected +/// @brief An operation detected a degenerate cell. +/// +/// A degenerate cell has two or more vertices combined into one, which +/// changes the structure of the cell. For example, if 2 vertices of +/// a tetrahedron are at the same point, the cell degenerates to a +/// triangle. Degenerate cells have the potential to interfere with some +/// computations on cells. + +/// @var ErrorCode MalformedCellDetected +/// @brief An operation detected on a malformed cell. +/// +/// Most cell shapes have some assumptions about their geometry (e.g. not +/// self intersecting). If an operation detects an expected behavior is +/// violated, this error is returned. (Note that `vtkm::DegenerateCellDetected` +/// has its own error coe.) + +/// @var ErrorCode OperationOnEmptyCell +/// @brief An operation was attempted on a cell with an empty shape. +/// +/// There is a special "empty" cell shape type (`vtkm::CellShapeTagEmpty`) that +/// can be used as a placeholder for a cell with no information. Math operations +/// such as interpolation cannot be performed on empty cells, and attempting to +/// do so will result in this error. + +/// @var ErrorCode CellNotFound +/// @brief A cell matching some given criteria could not be found. +/// +/// This error code is most often used in a cell locator where no cell in the +/// given region could be found. + +/// @brief Convert a `vtkm::ErrorCode` into a human-readable string. +/// +/// This method is useful when reporting the results of a function that +/// failed. VTKM_EXEC_CONT inline const char* ErrorString(vtkm::ErrorCode code) noexcept { diff --git a/vtkm/List.h b/vtkm/List.h index 52c17845d..f03d45553 100644 --- a/vtkm/List.h +++ b/vtkm/List.h @@ -30,6 +30,11 @@ namespace vtkm " Compilers often have a recursive template instantiation limit of around 1024," \ " so operations on lists this large can lead to confusing and misleading errors.") +/// @brief A template used to hold a list of types. +/// +/// `List` is an empty `struct` that is used to hold a list of types as its template +/// arguments. VTK-m provides templated types that allows a `List` to be +/// manipulated and used in numerous ways. template struct List { @@ -78,13 +83,14 @@ struct UniversalTypeTag } // namespace detail -/// A special tag for an empty list. +/// @brief A convenience type for an empty list. /// using ListEmpty = vtkm::List<>; -/// A special tag for a list that represents holding all potential values +/// @brief A special type for a list that represents holding all potential values /// -/// Note: Can not be used with ForEach and some list transforms for obvious reasons. +/// Note: This list cannot be used with `ForEach` and some list transforms +/// for obvious reasons. using ListUniversal = vtkm::List; namespace detail @@ -711,7 +717,6 @@ struct ListIntersectImpl template using ListIntersect = typename detail::ListIntersectImpl::type; -///@{ /// For each typename represented by the list, call the functor with a /// default instance of that type. /// @@ -729,7 +734,6 @@ VTKM_EXEC_CONT void ListForEach(Functor&&, vtkm::ListEmpty, Args&&...) { // No types to run functor on. } -///@} namespace detail { diff --git a/vtkm/Range.h b/vtkm/Range.h index bcf14e478..c190a6f31 100644 --- a/vtkm/Range.h +++ b/vtkm/Range.h @@ -30,9 +30,13 @@ namespace vtkm /// struct Range { + /// The minumum value of the range (inclusive). vtkm::Float64 Min; + /// Tha maximum value of the range (inclusive). vtkm::Float64 Max; + /// Construct a range with a given minimum and maximum. If no minimum or maximum is + /// given, the range will be empty. VTKM_EXEC_CONT Range() : Min(vtkm::Infinity64()) diff --git a/vtkm/RangeId.h b/vtkm/RangeId.h index b952c9414..c9d98a423 100644 --- a/vtkm/RangeId.h +++ b/vtkm/RangeId.h @@ -27,9 +27,12 @@ namespace vtkm /// struct RangeId { + /// The minimum index of the range (inclusive). vtkm::Id Min; + /// The maximum index of the range (exclusive). vtkm::Id Max; + /// Construct a range with no indices. VTKM_EXEC_CONT RangeId() : Min(0) @@ -37,6 +40,8 @@ struct RangeId { } + /// Construct a range with the given minimum (inclusive) and maximum (exclusive) + /// indices. VTKM_EXEC_CONT RangeId(vtkm::Id min, vtkm::Id max) : Min(min) diff --git a/vtkm/RangeId2.h b/vtkm/RangeId2.h index 814742705..84171c91a 100644 --- a/vtkm/RangeId2.h +++ b/vtkm/RangeId2.h @@ -15,22 +15,28 @@ namespace vtkm { -/// \brief Represent 2D integer range. +/// @brief Represent 2D integer range. /// -/// \c vtkm::RangeId2 is a helper class for representing a 2D range of integer +/// `vtkm::RangeId2` is a helper class for representing a 2D range of integer /// values. The typical use of this class is to express a box of indices -/// in the x, y, and z directions. +/// in the x and y directions. /// -/// \c RangeId2 also contains several helper functions for computing and +/// `RangeId2` also contains several helper functions for computing and /// maintaining the range. /// struct RangeId2 { + /// The range of values in the X direction. The `vtkm::RangeId` struct provides + /// the minimum and maximum along that axis. vtkm::RangeId X; + /// The range of values in the Y direction. The `vtkm::RangeId` struct provides + /// the minimum and maximum along that axis. vtkm::RangeId Y; + /// Construct an empty 2D range. RangeId2() = default; + /// Construct a range with the given x and y directions. VTKM_EXEC_CONT RangeId2(const vtkm::RangeId& xrange, const vtkm::RangeId& yrange) : X(xrange) @@ -38,6 +44,7 @@ struct RangeId2 { } + /// Construct a range with the given minimum (inclusive) and maximum (exclusive) points. VTKM_EXEC_CONT RangeId2(vtkm::Id minX, vtkm::Id maxX, vtkm::Id minY, vtkm::Id maxY) : X(vtkm::RangeId(minX, maxX)) @@ -45,8 +52,8 @@ struct RangeId2 { } - /// Initialize range with an array of 6 values in the order xmin, xmax, - /// ymin, ymax, zmin, zmax. + /// Initialize range with an array of 4 values in the order xmin, xmax, + /// ymin, ymax. /// VTKM_EXEC_CONT explicit RangeId2(const vtkm::Id range[4]) diff --git a/vtkm/RangeId3.h b/vtkm/RangeId3.h index 9a6f0b3d8..b7d328d32 100644 --- a/vtkm/RangeId3.h +++ b/vtkm/RangeId3.h @@ -26,12 +26,20 @@ namespace vtkm /// struct RangeId3 { + /// The range of values in the X direction. The `vtkm::RangeId` struct provides + /// the minimum and maximum along that axis. vtkm::RangeId X; + /// The range of values in the Y direction. The `vtkm::RangeId` struct provides + /// the minimum and maximum along that axis. vtkm::RangeId Y; + /// The range of values in the Z direction. The `vtkm::RangeId` struct provides + /// the minimum and maximum along that axis. vtkm::RangeId Z; + /// Construct an empty 3D range. RangeId3() = default; + /// Construct a range with the given x, y, and z directions. VTKM_EXEC_CONT RangeId3(const vtkm::RangeId& xrange, const vtkm::RangeId& yrange, const vtkm::RangeId& zrange) : X(xrange) @@ -40,6 +48,7 @@ struct RangeId3 { } + /// Construct a range with the given minimum (inclusive) and maximum (exclusive) points. VTKM_EXEC_CONT RangeId3(vtkm::Id minX, vtkm::Id maxX, vtkm::Id minY, vtkm::Id maxY, vtkm::Id minZ, vtkm::Id maxZ) : X(vtkm::RangeId(minX, maxX)) diff --git a/vtkm/Tuple.h b/vtkm/Tuple.h index 7544be2c9..bd2a7733d 100644 --- a/vtkm/Tuple.h +++ b/vtkm/Tuple.h @@ -75,27 +75,31 @@ struct tuple_element template using tuple_element_t = typename tuple_element::type; -///@{ -/// \brief Retrieve the object from a `vtkm::Tuple` at the given index. -/// +/// @brief Retrieve the object from a `vtkm::Tuple` at the given index. VTKM_SUPPRESS_EXEC_WARNINGS template -VTKM_EXEC_CONT auto Get(const vtkm::Tuple& tuple) -> decltype(tuple.template Get()) +VTKM_EXEC_CONT auto Get(const vtkm::Tuple& tuple) +#ifndef VTKM_DOXYGEN_ONLY + // Breathe (for Sphinx) has problems parsing this declarator id. + -> decltype(tuple.template Get()) +#endif { return tuple.template Get(); } +/// @brief Retrieve the object from a `vtkm::Tuple` at the given index. VTKM_SUPPRESS_EXEC_WARNINGS template -VTKM_EXEC_CONT auto Get(vtkm::Tuple& tuple) -> decltype(tuple.template Get()) +VTKM_EXEC_CONT auto Get(vtkm::Tuple& tuple) +#ifndef VTKM_DOXYGEN_ONLY + // Breathe (for Sphinx) has problems parsing this declarator id. + -> decltype(tuple.template Get()) +#endif { return tuple.template Get(); } -///@} -///@{ -/// \brief Compatible with `std::get` for `vtkm::Tuple`. -/// +/// @brief Compatible with `std::get` for `vtkm::Tuple`. VTKM_SUPPRESS_EXEC_WARNINGS template VTKM_EXEC_CONT auto get(const vtkm::Tuple& tuple) @@ -104,6 +108,7 @@ VTKM_EXEC_CONT auto get(const vtkm::Tuple& tuple) return vtkm::Get(Index)>(tuple); } +/// @brief Compatible with `std::get` for `vtkm::Tuple`. VTKM_SUPPRESS_EXEC_WARNINGS template VTKM_EXEC_CONT auto get(vtkm::Tuple& tuple) @@ -111,7 +116,6 @@ VTKM_EXEC_CONT auto get(vtkm::Tuple& tuple) { return vtkm::Get(Index)>(tuple); } -///@} /// \brief Creates a new `vtkm::Tuple` with the given types. /// @@ -145,14 +149,6 @@ struct TupleTransformFunctor } }; -VTKM_SUPPRESS_EXEC_WARNINGS -template -VTKM_EXEC_CONT auto TupleTransform(TupleType&& tuple, Function&& f) - -> decltype(tuple.Apply(TupleTransformFunctor{}, std::forward(f))) -{ - return tuple.Apply(TupleTransformFunctor{}, std::forward(f)); -} - struct TupleForEachFunctor { VTKM_SUPPRESS_EXEC_WARNINGS @@ -163,17 +159,69 @@ struct TupleForEachFunctor } }; -VTKM_SUPPRESS_EXEC_WARNINGS -template -VTKM_EXEC_CONT auto TupleForEach(TupleType&& tuple, Function&& f) - -> decltype(tuple.Apply(TupleForEachFunctor{}, std::forward(f))) -{ - return tuple.Apply(TupleForEachFunctor{}, std::forward(f)); -} - } // namespace detail /// @endcond +/// @brief Call a function with the values of a `vtkm::Tuple` as arguments. +/// +/// If a `vtkm::Tuple` is given with values `a`, `b`, and `c`, then +/// `f` will be called as `f(a, b, c)`. +/// +/// Additional arguments can optionally be given to `vtkm::Apply()`. These +/// arguments will be added to the _beginning_ of the arguments to the function. +/// +/// The returned value of the function (if any) will be returned from `vtkm::Apply()`. +template +VTKM_EXEC_CONT auto Apply(const vtkm::Tuple& tuple, Function&& f, Args&&... args) + -> decltype(tuple.Apply(std::forward(f), std::forward(args)...)) +{ + return tuple.Apply(std::forward(f), std::forward(args)...); +} + +/// @copydoc Apply +template +VTKM_EXEC_CONT auto Apply(vtkm::Tuple& tuple, Function&& f, Args&&... args) + -> decltype(tuple.Apply(std::forward(f), std::forward(args)...)) +{ + return tuple.Apply(std::forward(f), std::forward(args)...); +} + +/// @brief Call a function with each value of the given tuple. +/// +/// The function calls will be done in the order of the values in the `vtkm::Tuple`. +template +VTKM_EXEC_CONT void ForEach(const vtkm::Tuple& tuple, Function&& f) +{ + return vtkm::Apply(tuple, detail::TupleForEachFunctor{}, std::forward(f)); +} + +/// @copydoc ForEach +template +VTKM_EXEC_CONT void ForEach(vtkm::Tuple& tuple, Function&& f) +{ + return vtkm::Apply(tuple, detail::TupleForEachFunctor{}, std::forward(f)); +} + +/// @brief Construct a new `vtkm::Tuple` by applying a function to each value. +/// +/// The `vtkm::Transform` function builds a new `vtkm::Tuple` by calling a function +/// or functor on each of the items in the given `tuple`. The return value is placed +/// in the corresponding part of the resulting Tuple, and the type is automatically +/// created from the return type of the function. +template +VTKM_EXEC_CONT auto Transform(const TupleType&& tuple, Function&& f) + -> decltype(Apply(tuple, detail::TupleTransformFunctor{}, std::forward(f))) +{ + return Apply(tuple, detail::TupleTransformFunctor{}, std::forward(f)); +} + +template +VTKM_EXEC_CONT auto Transform(TupleType&& tuple, Function&& f) + -> decltype(Apply(tuple, detail::TupleTransformFunctor{}, std::forward(f))) +{ + return Apply(tuple, detail::TupleTransformFunctor{}, std::forward(f)); +} + template <> class Tuple<> { @@ -285,28 +333,28 @@ public: template VTKM_EXEC_CONT void ForEach(Function&& f) { - detail::TupleForEach(*this, std::forward(f)); + vtkm::ForEach(*this, std::forward(f)); } VTKM_SUPPRESS_EXEC_WARNINGS template VTKM_EXEC_CONT void ForEach(Function&& f) const { - detail::TupleForEach(*this, std::forward(f)); + vtkm::ForEach(*this, std::forward(f)); } VTKM_SUPPRESS_EXEC_WARNINGS template VTKM_EXEC_CONT auto Transform(Function&& f) - -> decltype(detail::TupleTransform(*this, std::forward(f))) + -> decltype(vtkm::Transform(*this, std::forward(f))) { - return detail::TupleTransform(*this, std::forward(f)); + return vtkm::Transform(*this, std::forward(f)); } VTKM_SUPPRESS_EXEC_WARNINGS template VTKM_EXEC_CONT auto Transform(Function&& f) const - -> decltype(detail::TupleTransform(*this, std::forward(f))) + -> decltype(vtkm::Transform(*this, std::forward(f))) { - return detail::TupleTransform(*this, std::forward(f)); + return vtkm::Transform(*this, std::forward(f)); } }; @@ -396,28 +444,28 @@ public: template VTKM_EXEC_CONT void ForEach(Function&& f) { - detail::TupleForEach(*this, std::forward(f)); + vtkm::ForEach(*this, std::forward(f)); } VTKM_SUPPRESS_EXEC_WARNINGS template VTKM_EXEC_CONT void ForEach(Function&& f) const { - detail::TupleForEach(*this, std::forward(f)); + vtkm::ForEach(*this, std::forward(f)); } VTKM_SUPPRESS_EXEC_WARNINGS template VTKM_EXEC_CONT auto Transform(Function&& f) - -> decltype(detail::TupleTransform(*this, std::forward(f))) + -> decltype(vtkm::Transform(*this, std::forward(f))) { - return detail::TupleTransform(*this, std::forward(f)); + return vtkm::Transform(*this, std::forward(f)); } VTKM_SUPPRESS_EXEC_WARNINGS template VTKM_EXEC_CONT auto Transform(Function&& f) const - -> decltype(detail::TupleTransform(*this, std::forward(f))) + -> decltype(vtkm::Transform(*this, std::forward(f))) { - return detail::TupleTransform(*this, std::forward(f)); + return vtkm::Transform(*this, std::forward(f)); } }; @@ -519,28 +567,28 @@ public: template VTKM_EXEC_CONT void ForEach(Function&& f) { - detail::TupleForEach(*this, std::forward(f)); + vtkm::ForEach(*this, std::forward(f)); } VTKM_SUPPRESS_EXEC_WARNINGS template VTKM_EXEC_CONT void ForEach(Function&& f) const { - detail::TupleForEach(*this, std::forward(f)); + vtkm::ForEach(*this, std::forward(f)); } VTKM_SUPPRESS_EXEC_WARNINGS template VTKM_EXEC_CONT auto Transform(Function&& f) - -> decltype(detail::TupleTransform(*this, std::forward(f))) + -> decltype(vtkm::Transform(*this, std::forward(f))) { - return detail::TupleTransform(*this, std::forward(f)); + return vtkm::Transform(*this, std::forward(f)); } VTKM_SUPPRESS_EXEC_WARNINGS template VTKM_EXEC_CONT auto Transform(Function&& f) const - -> decltype(detail::TupleTransform(*this, std::forward(f))) + -> decltype(vtkm::Transform(*this, std::forward(f))) { - return detail::TupleTransform(*this, std::forward(f)); + return vtkm::Transform(*this, std::forward(f)); } }; @@ -654,28 +702,28 @@ public: template VTKM_EXEC_CONT void ForEach(Function&& f) { - detail::TupleForEach(*this, std::forward(f)); + vtkm::ForEach(*this, std::forward(f)); } VTKM_SUPPRESS_EXEC_WARNINGS template VTKM_EXEC_CONT void ForEach(Function&& f) const { - detail::TupleForEach(*this, std::forward(f)); + vtkm::ForEach(*this, std::forward(f)); } VTKM_SUPPRESS_EXEC_WARNINGS template VTKM_EXEC_CONT auto Transform(Function&& f) - -> decltype(detail::TupleTransform(*this, std::forward(f))) + -> decltype(vtkm::Transform(*this, std::forward(f))) { - return detail::TupleTransform(*this, std::forward(f)); + return vtkm::Transform(*this, std::forward(f)); } VTKM_SUPPRESS_EXEC_WARNINGS template VTKM_EXEC_CONT auto Transform(Function&& f) const - -> decltype(detail::TupleTransform(*this, std::forward(f))) + -> decltype(vtkm::Transform(*this, std::forward(f))) { - return detail::TupleTransform(*this, std::forward(f)); + return vtkm::Transform(*this, std::forward(f)); } }; @@ -801,28 +849,28 @@ public: template VTKM_EXEC_CONT void ForEach(Function&& f) { - detail::TupleForEach(*this, std::forward(f)); + vtkm::ForEach(*this, std::forward(f)); } VTKM_SUPPRESS_EXEC_WARNINGS template VTKM_EXEC_CONT void ForEach(Function&& f) const { - detail::TupleForEach(*this, std::forward(f)); + vtkm::ForEach(*this, std::forward(f)); } VTKM_SUPPRESS_EXEC_WARNINGS template VTKM_EXEC_CONT auto Transform(Function&& f) - -> decltype(detail::TupleTransform(*this, std::forward(f))) + -> decltype(vtkm::Transform(*this, std::forward(f))) { - return detail::TupleTransform(*this, std::forward(f)); + return vtkm::Transform(*this, std::forward(f)); } VTKM_SUPPRESS_EXEC_WARNINGS template VTKM_EXEC_CONT auto Transform(Function&& f) const - -> decltype(detail::TupleTransform(*this, std::forward(f))) + -> decltype(vtkm::Transform(*this, std::forward(f))) { - return detail::TupleTransform(*this, std::forward(f)); + return vtkm::Transform(*this, std::forward(f)); } }; @@ -960,28 +1008,28 @@ public: template VTKM_EXEC_CONT void ForEach(Function&& f) { - detail::TupleForEach(*this, std::forward(f)); + vtkm::ForEach(*this, std::forward(f)); } VTKM_SUPPRESS_EXEC_WARNINGS template VTKM_EXEC_CONT void ForEach(Function&& f) const { - detail::TupleForEach(*this, std::forward(f)); + vtkm::ForEach(*this, std::forward(f)); } VTKM_SUPPRESS_EXEC_WARNINGS template VTKM_EXEC_CONT auto Transform(Function&& f) - -> decltype(detail::TupleTransform(*this, std::forward(f))) + -> decltype(vtkm::Transform(*this, std::forward(f))) { - return detail::TupleTransform(*this, std::forward(f)); + return vtkm::Transform(*this, std::forward(f)); } VTKM_SUPPRESS_EXEC_WARNINGS template VTKM_EXEC_CONT auto Transform(Function&& f) const - -> decltype(detail::TupleTransform(*this, std::forward(f))) + -> decltype(vtkm::Transform(*this, std::forward(f))) { - return detail::TupleTransform(*this, std::forward(f)); + return vtkm::Transform(*this, std::forward(f)); } }; @@ -1131,28 +1179,28 @@ public: template VTKM_EXEC_CONT void ForEach(Function&& f) { - detail::TupleForEach(*this, std::forward(f)); + vtkm::ForEach(*this, std::forward(f)); } VTKM_SUPPRESS_EXEC_WARNINGS template VTKM_EXEC_CONT void ForEach(Function&& f) const { - detail::TupleForEach(*this, std::forward(f)); + vtkm::ForEach(*this, std::forward(f)); } VTKM_SUPPRESS_EXEC_WARNINGS template VTKM_EXEC_CONT auto Transform(Function&& f) - -> decltype(detail::TupleTransform(*this, std::forward(f))) + -> decltype(vtkm::Transform(*this, std::forward(f))) { - return detail::TupleTransform(*this, std::forward(f)); + return vtkm::Transform(*this, std::forward(f)); } VTKM_SUPPRESS_EXEC_WARNINGS template VTKM_EXEC_CONT auto Transform(Function&& f) const - -> decltype(detail::TupleTransform(*this, std::forward(f))) + -> decltype(vtkm::Transform(*this, std::forward(f))) { - return detail::TupleTransform(*this, std::forward(f)); + return vtkm::Transform(*this, std::forward(f)); } }; @@ -1314,28 +1362,28 @@ public: template VTKM_EXEC_CONT void ForEach(Function&& f) { - detail::TupleForEach(*this, std::forward(f)); + vtkm::ForEach(*this, std::forward(f)); } VTKM_SUPPRESS_EXEC_WARNINGS template VTKM_EXEC_CONT void ForEach(Function&& f) const { - detail::TupleForEach(*this, std::forward(f)); + vtkm::ForEach(*this, std::forward(f)); } VTKM_SUPPRESS_EXEC_WARNINGS template VTKM_EXEC_CONT auto Transform(Function&& f) - -> decltype(detail::TupleTransform(*this, std::forward(f))) + -> decltype(vtkm::Transform(*this, std::forward(f))) { - return detail::TupleTransform(*this, std::forward(f)); + return vtkm::Transform(*this, std::forward(f)); } VTKM_SUPPRESS_EXEC_WARNINGS template VTKM_EXEC_CONT auto Transform(Function&& f) const - -> decltype(detail::TupleTransform(*this, std::forward(f))) + -> decltype(vtkm::Transform(*this, std::forward(f))) { - return detail::TupleTransform(*this, std::forward(f)); + return vtkm::Transform(*this, std::forward(f)); } }; @@ -1509,28 +1557,28 @@ public: template VTKM_EXEC_CONT void ForEach(Function&& f) { - detail::TupleForEach(*this, std::forward(f)); + vtkm::ForEach(*this, std::forward(f)); } VTKM_SUPPRESS_EXEC_WARNINGS template VTKM_EXEC_CONT void ForEach(Function&& f) const { - detail::TupleForEach(*this, std::forward(f)); + vtkm::ForEach(*this, std::forward(f)); } VTKM_SUPPRESS_EXEC_WARNINGS template VTKM_EXEC_CONT auto Transform(Function&& f) - -> decltype(detail::TupleTransform(*this, std::forward(f))) + -> decltype(vtkm::Transform(*this, std::forward(f))) { - return detail::TupleTransform(*this, std::forward(f)); + return vtkm::Transform(*this, std::forward(f)); } VTKM_SUPPRESS_EXEC_WARNINGS template VTKM_EXEC_CONT auto Transform(Function&& f) const - -> decltype(detail::TupleTransform(*this, std::forward(f))) + -> decltype(vtkm::Transform(*this, std::forward(f))) { - return detail::TupleTransform(*this, std::forward(f)); + return vtkm::Transform(*this, std::forward(f)); } }; @@ -1716,28 +1764,28 @@ public: template VTKM_EXEC_CONT void ForEach(Function&& f) { - detail::TupleForEach(*this, std::forward(f)); + vtkm::ForEach(*this, std::forward(f)); } VTKM_SUPPRESS_EXEC_WARNINGS template VTKM_EXEC_CONT void ForEach(Function&& f) const { - detail::TupleForEach(*this, std::forward(f)); + vtkm::ForEach(*this, std::forward(f)); } VTKM_SUPPRESS_EXEC_WARNINGS template VTKM_EXEC_CONT auto Transform(Function&& f) - -> decltype(detail::TupleTransform(*this, std::forward(f))) + -> decltype(vtkm::Transform(*this, std::forward(f))) { - return detail::TupleTransform(*this, std::forward(f)); + return vtkm::Transform(*this, std::forward(f)); } VTKM_SUPPRESS_EXEC_WARNINGS template VTKM_EXEC_CONT auto Transform(Function&& f) const - -> decltype(detail::TupleTransform(*this, std::forward(f))) + -> decltype(vtkm::Transform(*this, std::forward(f))) { - return detail::TupleTransform(*this, std::forward(f)); + return vtkm::Transform(*this, std::forward(f)); } }; @@ -1935,28 +1983,28 @@ public: template VTKM_EXEC_CONT void ForEach(Function&& f) { - detail::TupleForEach(*this, std::forward(f)); + vtkm::ForEach(*this, std::forward(f)); } VTKM_SUPPRESS_EXEC_WARNINGS template VTKM_EXEC_CONT void ForEach(Function&& f) const { - detail::TupleForEach(*this, std::forward(f)); + vtkm::ForEach(*this, std::forward(f)); } VTKM_SUPPRESS_EXEC_WARNINGS template VTKM_EXEC_CONT auto Transform(Function&& f) - -> decltype(detail::TupleTransform(*this, std::forward(f))) + -> decltype(vtkm::Transform(*this, std::forward(f))) { - return detail::TupleTransform(*this, std::forward(f)); + return vtkm::Transform(*this, std::forward(f)); } VTKM_SUPPRESS_EXEC_WARNINGS template VTKM_EXEC_CONT auto Transform(Function&& f) const - -> decltype(detail::TupleTransform(*this, std::forward(f))) + -> decltype(vtkm::Transform(*this, std::forward(f))) { - return detail::TupleTransform(*this, std::forward(f)); + return vtkm::Transform(*this, std::forward(f)); } }; @@ -2166,28 +2214,28 @@ public: template VTKM_EXEC_CONT void ForEach(Function&& f) { - detail::TupleForEach(*this, std::forward(f)); + vtkm::ForEach(*this, std::forward(f)); } VTKM_SUPPRESS_EXEC_WARNINGS template VTKM_EXEC_CONT void ForEach(Function&& f) const { - detail::TupleForEach(*this, std::forward(f)); + vtkm::ForEach(*this, std::forward(f)); } VTKM_SUPPRESS_EXEC_WARNINGS template VTKM_EXEC_CONT auto Transform(Function&& f) - -> decltype(detail::TupleTransform(*this, std::forward(f))) + -> decltype(vtkm::Transform(*this, std::forward(f))) { - return detail::TupleTransform(*this, std::forward(f)); + return vtkm::Transform(*this, std::forward(f)); } VTKM_SUPPRESS_EXEC_WARNINGS template VTKM_EXEC_CONT auto Transform(Function&& f) const - -> decltype(detail::TupleTransform(*this, std::forward(f))) + -> decltype(vtkm::Transform(*this, std::forward(f))) { - return detail::TupleTransform(*this, std::forward(f)); + return vtkm::Transform(*this, std::forward(f)); } }; @@ -2409,28 +2457,28 @@ public: template VTKM_EXEC_CONT void ForEach(Function&& f) { - detail::TupleForEach(*this, std::forward(f)); + vtkm::ForEach(*this, std::forward(f)); } VTKM_SUPPRESS_EXEC_WARNINGS template VTKM_EXEC_CONT void ForEach(Function&& f) const { - detail::TupleForEach(*this, std::forward(f)); + vtkm::ForEach(*this, std::forward(f)); } VTKM_SUPPRESS_EXEC_WARNINGS template VTKM_EXEC_CONT auto Transform(Function&& f) - -> decltype(detail::TupleTransform(*this, std::forward(f))) + -> decltype(vtkm::Transform(*this, std::forward(f))) { - return detail::TupleTransform(*this, std::forward(f)); + return vtkm::Transform(*this, std::forward(f)); } VTKM_SUPPRESS_EXEC_WARNINGS template VTKM_EXEC_CONT auto Transform(Function&& f) const - -> decltype(detail::TupleTransform(*this, std::forward(f))) + -> decltype(vtkm::Transform(*this, std::forward(f))) { - return detail::TupleTransform(*this, std::forward(f)); + return vtkm::Transform(*this, std::forward(f)); } }; @@ -2664,28 +2712,28 @@ public: template VTKM_EXEC_CONT void ForEach(Function&& f) { - detail::TupleForEach(*this, std::forward(f)); + vtkm::ForEach(*this, std::forward(f)); } VTKM_SUPPRESS_EXEC_WARNINGS template VTKM_EXEC_CONT void ForEach(Function&& f) const { - detail::TupleForEach(*this, std::forward(f)); + vtkm::ForEach(*this, std::forward(f)); } VTKM_SUPPRESS_EXEC_WARNINGS template VTKM_EXEC_CONT auto Transform(Function&& f) - -> decltype(detail::TupleTransform(*this, std::forward(f))) + -> decltype(vtkm::Transform(*this, std::forward(f))) { - return detail::TupleTransform(*this, std::forward(f)); + return vtkm::Transform(*this, std::forward(f)); } VTKM_SUPPRESS_EXEC_WARNINGS template VTKM_EXEC_CONT auto Transform(Function&& f) const - -> decltype(detail::TupleTransform(*this, std::forward(f))) + -> decltype(vtkm::Transform(*this, std::forward(f))) { - return detail::TupleTransform(*this, std::forward(f)); + return vtkm::Transform(*this, std::forward(f)); } }; @@ -2931,28 +2979,28 @@ public: template VTKM_EXEC_CONT void ForEach(Function&& f) { - detail::TupleForEach(*this, std::forward(f)); + vtkm::ForEach(*this, std::forward(f)); } VTKM_SUPPRESS_EXEC_WARNINGS template VTKM_EXEC_CONT void ForEach(Function&& f) const { - detail::TupleForEach(*this, std::forward(f)); + vtkm::ForEach(*this, std::forward(f)); } VTKM_SUPPRESS_EXEC_WARNINGS template VTKM_EXEC_CONT auto Transform(Function&& f) - -> decltype(detail::TupleTransform(*this, std::forward(f))) + -> decltype(vtkm::Transform(*this, std::forward(f))) { - return detail::TupleTransform(*this, std::forward(f)); + return vtkm::Transform(*this, std::forward(f)); } VTKM_SUPPRESS_EXEC_WARNINGS template VTKM_EXEC_CONT auto Transform(Function&& f) const - -> decltype(detail::TupleTransform(*this, std::forward(f))) + -> decltype(vtkm::Transform(*this, std::forward(f))) { - return detail::TupleTransform(*this, std::forward(f)); + return vtkm::Transform(*this, std::forward(f)); } }; @@ -3210,28 +3258,28 @@ public: template VTKM_EXEC_CONT void ForEach(Function&& f) { - detail::TupleForEach(*this, std::forward(f)); + vtkm::ForEach(*this, std::forward(f)); } VTKM_SUPPRESS_EXEC_WARNINGS template VTKM_EXEC_CONT void ForEach(Function&& f) const { - detail::TupleForEach(*this, std::forward(f)); + vtkm::ForEach(*this, std::forward(f)); } VTKM_SUPPRESS_EXEC_WARNINGS template VTKM_EXEC_CONT auto Transform(Function&& f) - -> decltype(detail::TupleTransform(*this, std::forward(f))) + -> decltype(vtkm::Transform(*this, std::forward(f))) { - return detail::TupleTransform(*this, std::forward(f)); + return vtkm::Transform(*this, std::forward(f)); } VTKM_SUPPRESS_EXEC_WARNINGS template VTKM_EXEC_CONT auto Transform(Function&& f) const - -> decltype(detail::TupleTransform(*this, std::forward(f))) + -> decltype(vtkm::Transform(*this, std::forward(f))) { - return detail::TupleTransform(*this, std::forward(f)); + return vtkm::Transform(*this, std::forward(f)); } }; @@ -3501,28 +3549,28 @@ public: template VTKM_EXEC_CONT void ForEach(Function&& f) { - detail::TupleForEach(*this, std::forward(f)); + vtkm::ForEach(*this, std::forward(f)); } VTKM_SUPPRESS_EXEC_WARNINGS template VTKM_EXEC_CONT void ForEach(Function&& f) const { - detail::TupleForEach(*this, std::forward(f)); + vtkm::ForEach(*this, std::forward(f)); } VTKM_SUPPRESS_EXEC_WARNINGS template VTKM_EXEC_CONT auto Transform(Function&& f) - -> decltype(detail::TupleTransform(*this, std::forward(f))) + -> decltype(vtkm::Transform(*this, std::forward(f))) { - return detail::TupleTransform(*this, std::forward(f)); + return vtkm::Transform(*this, std::forward(f)); } VTKM_SUPPRESS_EXEC_WARNINGS template VTKM_EXEC_CONT auto Transform(Function&& f) const - -> decltype(detail::TupleTransform(*this, std::forward(f))) + -> decltype(vtkm::Transform(*this, std::forward(f))) { - return detail::TupleTransform(*this, std::forward(f)); + return vtkm::Transform(*this, std::forward(f)); } }; @@ -3804,28 +3852,28 @@ public: template VTKM_EXEC_CONT void ForEach(Function&& f) { - detail::TupleForEach(*this, std::forward(f)); + vtkm::ForEach(*this, std::forward(f)); } VTKM_SUPPRESS_EXEC_WARNINGS template VTKM_EXEC_CONT void ForEach(Function&& f) const { - detail::TupleForEach(*this, std::forward(f)); + vtkm::ForEach(*this, std::forward(f)); } VTKM_SUPPRESS_EXEC_WARNINGS template VTKM_EXEC_CONT auto Transform(Function&& f) - -> decltype(detail::TupleTransform(*this, std::forward(f))) + -> decltype(vtkm::Transform(*this, std::forward(f))) { - return detail::TupleTransform(*this, std::forward(f)); + return vtkm::Transform(*this, std::forward(f)); } VTKM_SUPPRESS_EXEC_WARNINGS template VTKM_EXEC_CONT auto Transform(Function&& f) const - -> decltype(detail::TupleTransform(*this, std::forward(f))) + -> decltype(vtkm::Transform(*this, std::forward(f))) { - return detail::TupleTransform(*this, std::forward(f)); + return vtkm::Transform(*this, std::forward(f)); } }; @@ -4119,28 +4167,28 @@ public: template VTKM_EXEC_CONT void ForEach(Function&& f) { - detail::TupleForEach(*this, std::forward(f)); + vtkm::ForEach(*this, std::forward(f)); } VTKM_SUPPRESS_EXEC_WARNINGS template VTKM_EXEC_CONT void ForEach(Function&& f) const { - detail::TupleForEach(*this, std::forward(f)); + vtkm::ForEach(*this, std::forward(f)); } VTKM_SUPPRESS_EXEC_WARNINGS template VTKM_EXEC_CONT auto Transform(Function&& f) - -> decltype(detail::TupleTransform(*this, std::forward(f))) + -> decltype(vtkm::Transform(*this, std::forward(f))) { - return detail::TupleTransform(*this, std::forward(f)); + return vtkm::Transform(*this, std::forward(f)); } VTKM_SUPPRESS_EXEC_WARNINGS template VTKM_EXEC_CONT auto Transform(Function&& f) const - -> decltype(detail::TupleTransform(*this, std::forward(f))) + -> decltype(vtkm::Transform(*this, std::forward(f))) { - return detail::TupleTransform(*this, std::forward(f)); + return vtkm::Transform(*this, std::forward(f)); } }; @@ -4446,28 +4494,28 @@ public: template VTKM_EXEC_CONT void ForEach(Function&& f) { - detail::TupleForEach(*this, std::forward(f)); + vtkm::ForEach(*this, std::forward(f)); } VTKM_SUPPRESS_EXEC_WARNINGS template VTKM_EXEC_CONT void ForEach(Function&& f) const { - detail::TupleForEach(*this, std::forward(f)); + vtkm::ForEach(*this, std::forward(f)); } VTKM_SUPPRESS_EXEC_WARNINGS template VTKM_EXEC_CONT auto Transform(Function&& f) - -> decltype(detail::TupleTransform(*this, std::forward(f))) + -> decltype(vtkm::Transform(*this, std::forward(f))) { - return detail::TupleTransform(*this, std::forward(f)); + return vtkm::Transform(*this, std::forward(f)); } VTKM_SUPPRESS_EXEC_WARNINGS template VTKM_EXEC_CONT auto Transform(Function&& f) const - -> decltype(detail::TupleTransform(*this, std::forward(f))) + -> decltype(vtkm::Transform(*this, std::forward(f))) { - return detail::TupleTransform(*this, std::forward(f)); + return vtkm::Transform(*this, std::forward(f)); } }; @@ -4872,28 +4920,28 @@ public: template VTKM_EXEC_CONT void ForEach(Function&& f) { - detail::TupleForEach(*this, std::forward(f)); + vtkm::ForEach(*this, std::forward(f)); } VTKM_SUPPRESS_EXEC_WARNINGS template VTKM_EXEC_CONT void ForEach(Function&& f) const { - detail::TupleForEach(*this, std::forward(f)); + vtkm::ForEach(*this, std::forward(f)); } VTKM_SUPPRESS_EXEC_WARNINGS template VTKM_EXEC_CONT auto Transform(Function&& f) - -> decltype(detail::TupleTransform(*this, std::forward(f))) + -> decltype(vtkm::Transform(*this, std::forward(f))) { - return detail::TupleTransform(*this, std::forward(f)); + return vtkm::Transform(*this, std::forward(f)); } VTKM_SUPPRESS_EXEC_WARNINGS template VTKM_EXEC_CONT auto Transform(Function&& f) const - -> decltype(detail::TupleTransform(*this, std::forward(f))) + -> decltype(vtkm::Transform(*this, std::forward(f))) { - return detail::TupleTransform(*this, std::forward(f)); + return vtkm::Transform(*this, std::forward(f)); } }; diff --git a/vtkm/Tuple.h.in b/vtkm/Tuple.h.in index 84898d91e..513e06065 100644 --- a/vtkm/Tuple.h.in +++ b/vtkm/Tuple.h.in @@ -116,27 +116,31 @@ struct tuple_element template using tuple_element_t = typename tuple_element::type; -///@{ -/// \brief Retrieve the object from a `vtkm::Tuple` at the given index. -/// +/// @brief Retrieve the object from a `vtkm::Tuple` at the given index. VTKM_SUPPRESS_EXEC_WARNINGS template -VTKM_EXEC_CONT auto Get(const vtkm::Tuple& tuple) -> decltype(tuple.template Get()) +VTKM_EXEC_CONT auto Get(const vtkm::Tuple& tuple) +#ifndef VTKM_DOXYGEN_ONLY + // Breathe (for Sphinx) has problems parsing this declarator id. + -> decltype(tuple.template Get()) +#endif { return tuple.template Get(); } +/// @brief Retrieve the object from a `vtkm::Tuple` at the given index. VTKM_SUPPRESS_EXEC_WARNINGS template -VTKM_EXEC_CONT auto Get(vtkm::Tuple& tuple) -> decltype(tuple.template Get()) +VTKM_EXEC_CONT auto Get(vtkm::Tuple& tuple) +#ifndef VTKM_DOXYGEN_ONLY + // Breathe (for Sphinx) has problems parsing this declarator id. + -> decltype(tuple.template Get()) +#endif { return tuple.template Get(); } -///@} -///@{ -/// \brief Compatible with `std::get` for `vtkm::Tuple`. -/// +/// @brief Compatible with `std::get` for `vtkm::Tuple`. VTKM_SUPPRESS_EXEC_WARNINGS template VTKM_EXEC_CONT auto get(const vtkm::Tuple& tuple) @@ -145,6 +149,7 @@ VTKM_EXEC_CONT auto get(const vtkm::Tuple& tuple) return vtkm::Get(Index)>(tuple); } +/// @brief Compatible with `std::get` for `vtkm::Tuple`. VTKM_SUPPRESS_EXEC_WARNINGS template VTKM_EXEC_CONT auto get(vtkm::Tuple& tuple) @@ -152,7 +157,6 @@ VTKM_EXEC_CONT auto get(vtkm::Tuple& tuple) { return vtkm::Get(Index)>(tuple); } -///@} /// \brief Creates a new `vtkm::Tuple` with the given types. /// @@ -186,14 +190,6 @@ struct TupleTransformFunctor } }; -VTKM_SUPPRESS_EXEC_WARNINGS -template -VTKM_EXEC_CONT auto TupleTransform(TupleType&& tuple, Function&& f) - -> decltype(tuple.Apply(TupleTransformFunctor{}, std::forward(f))) -{ - return tuple.Apply(TupleTransformFunctor{}, std::forward(f)); -} - struct TupleForEachFunctor { VTKM_SUPPRESS_EXEC_WARNINGS @@ -204,17 +200,69 @@ struct TupleForEachFunctor } }; -VTKM_SUPPRESS_EXEC_WARNINGS -template -VTKM_EXEC_CONT auto TupleForEach(TupleType&& tuple, Function&& f) - -> decltype(tuple.Apply(TupleForEachFunctor{}, std::forward(f))) -{ - return tuple.Apply(TupleForEachFunctor{}, std::forward(f)); -} - } // namespace detail /// @endcond +/// @brief Call a function with the values of a `vtkm::Tuple` as arguments. +/// +/// If a `vtkm::Tuple` is given with values `a`, `b`, and `c`, then +/// `f` will be called as `f(a, b, c)`. +/// +/// Additional arguments can optionally be given to `vtkm::Apply()`. These +/// arguments will be added to the _beginning_ of the arguments to the function. +/// +/// The returned value of the function (if any) will be returned from `vtkm::Apply()`. +template +VTKM_EXEC_CONT auto Apply(const vtkm::Tuple& tuple, Function&& f, Args&&... args) + -> decltype(tuple.Apply(std::forward(f), std::forward(args)...)) +{ + return tuple.Apply(std::forward(f), std::forward(args)...); +} + +/// @copydoc Apply +template +VTKM_EXEC_CONT auto Apply(vtkm::Tuple& tuple, Function&& f, Args&&... args) + -> decltype(tuple.Apply(std::forward(f), std::forward(args)...)) +{ + return tuple.Apply(std::forward(f), std::forward(args)...); +} + +/// @brief Call a function with each value of the given tuple. +/// +/// The function calls will be done in the order of the values in the `vtkm::Tuple`. +template +VTKM_EXEC_CONT void ForEach(const vtkm::Tuple& tuple, Function&& f) +{ + return vtkm::Apply(tuple, detail::TupleForEachFunctor{}, std::forward(f)); +} + +/// @copydoc ForEach +template +VTKM_EXEC_CONT void ForEach(vtkm::Tuple& tuple, Function&& f) +{ + return vtkm::Apply(tuple, detail::TupleForEachFunctor{}, std::forward(f)); +} + +/// @brief Construct a new `vtkm::Tuple` by applying a function to each value. +/// +/// The `vtkm::Transform` function builds a new `vtkm::Tuple` by calling a function +/// or functor on each of the items in the given `tuple`. The return value is placed +/// in the corresponding part of the resulting Tuple, and the type is automatically +/// created from the return type of the function. +template +VTKM_EXEC_CONT auto Transform(const TupleType&& tuple, Function&& f) + -> decltype(Apply(tuple, detail::TupleTransformFunctor{}, std::forward(f))) +{ + return Apply(tuple, detail::TupleTransformFunctor{}, std::forward(f)); +} + +template +VTKM_EXEC_CONT auto Transform(TupleType&& tuple, Function&& f) + -> decltype(Apply(tuple, detail::TupleTransformFunctor{}, std::forward(f))) +{ + return Apply(tuple, detail::TupleTransformFunctor{}, std::forward(f)); +} + template <> class Tuple<> { @@ -332,28 +380,28 @@ $endfor\ template VTKM_EXEC_CONT void ForEach(Function&& f) { - detail::TupleForEach(*this, std::forward(f)); + vtkm::ForEach(*this, std::forward(f)); } VTKM_SUPPRESS_EXEC_WARNINGS template VTKM_EXEC_CONT void ForEach(Function&& f) const { - detail::TupleForEach(*this, std::forward(f)); + vtkm::ForEach(*this, std::forward(f)); } VTKM_SUPPRESS_EXEC_WARNINGS template VTKM_EXEC_CONT auto Transform(Function&& f) - -> decltype(detail::TupleTransform(*this, std::forward(f))) + -> decltype(vtkm::Transform(*this, std::forward(f))) { - return detail::TupleTransform(*this, std::forward(f)); + return vtkm::Transform(*this, std::forward(f)); } VTKM_SUPPRESS_EXEC_WARNINGS template VTKM_EXEC_CONT auto Transform(Function&& f) const - -> decltype(detail::TupleTransform(*this, std::forward(f))) + -> decltype(vtkm::Transform(*this, std::forward(f))) { - return detail::TupleTransform(*this, std::forward(f)); + return vtkm::Transform(*this, std::forward(f)); } }; @@ -472,28 +520,28 @@ $endfor\ template VTKM_EXEC_CONT void ForEach(Function&& f) { - detail::TupleForEach(*this, std::forward(f)); + vtkm::ForEach(*this, std::forward(f)); } VTKM_SUPPRESS_EXEC_WARNINGS template VTKM_EXEC_CONT void ForEach(Function&& f) const { - detail::TupleForEach(*this, std::forward(f)); + vtkm::ForEach(*this, std::forward(f)); } VTKM_SUPPRESS_EXEC_WARNINGS template VTKM_EXEC_CONT auto Transform(Function&& f) - -> decltype(detail::TupleTransform(*this, std::forward(f))) + -> decltype(vtkm::Transform(*this, std::forward(f))) { - return detail::TupleTransform(*this, std::forward(f)); + return vtkm::Transform(*this, std::forward(f)); } VTKM_SUPPRESS_EXEC_WARNINGS template VTKM_EXEC_CONT auto Transform(Function&& f) const - -> decltype(detail::TupleTransform(*this, std::forward(f))) + -> decltype(vtkm::Transform(*this, std::forward(f))) { - return detail::TupleTransform(*this, std::forward(f)); + return vtkm::Transform(*this, std::forward(f)); } }; diff --git a/vtkm/TypeTraits.h b/vtkm/TypeTraits.h index ae1a5e7ca..6968c6c52 100644 --- a/vtkm/TypeTraits.h +++ b/vtkm/TypeTraits.h @@ -72,6 +72,8 @@ public: /// also be treated as vectors with VecTraits. using DimensionalityTag = vtkm::TypeTraitsUnknownTag; + /// @brief A static function that returns 0 (or the closest equivalent to it) + /// for the given type. VTKM_EXEC_CONT static T ZeroInitialization() { return T(); } }; diff --git a/vtkm/VecTraits.h b/vtkm/VecTraits.h index a66ad5136..2c507175b 100644 --- a/vtkm/VecTraits.h +++ b/vtkm/VecTraits.h @@ -79,18 +79,28 @@ struct VTKM_NEVER_EXPORT VecTraits /// \brief Number of components in the vector. /// - /// This is only defined for vectors of a static size. + /// This is only defined for vectors of a static size. That is, `NUM_COMPONENTS` + /// is not available when `IsSizeStatic` is set to `vtkm::VecTraitsTagSizeVariable`. /// static constexpr vtkm::IdComponent NUM_COMPONENTS = 1; - /// Number of components in the given vector. + /// @brief Returns the number of components in the given vector. + /// + /// The result of `GetNumberOfComponents()` is the same value of `NUM_COMPONENTS` + /// for vector types that have a static size (that is, `IsSizeStatic` is + /// `vtkm::VecTraitsTagSizeStatic`). But unlike `NUM_COMPONENTS`, `GetNumberOfComponents()` + /// works for vectors of any type. /// static constexpr vtkm::IdComponent GetNumberOfComponents(const T&) { return NUM_COMPONENTS; } /// \brief A tag specifying whether this vector has multiple components (i.e. is a "real" vector). /// - /// This tag can be useful for creating specialized functions when a vector - /// is really just a scalar. + /// This type is set to either `vtkm::VecTraitsTagSingleComponent` if the vector length + /// is size 1 or `vtkm::VecTraitsTagMultipleComponents` otherwise. + /// This tag can be useful for creating specialized functions when a vector is really + /// just a scalar. If the vector type is of variable size (that is, `IsSizeStatic` is + /// `vtkm::VecTraitsTagSizeVariable`), then `HasMultipleComponents` might be + /// `vtkm::VecTraitsTagMultipleComponents` even when at run time there is only one component. /// using HasMultipleComponents = vtkm::VecTraitsTagSingleComponent; @@ -109,6 +119,7 @@ struct VTKM_NEVER_EXPORT VecTraits { return vector; } + /// @copydoc GetComponent VTKM_EXEC_CONT static ComponentType& GetComponent(T& vector, vtkm::IdComponent vtkmNotUsed(component)) { diff --git a/vtkm/filter/mesh_info/MeshQualityArea.cxx b/vtkm/filter/mesh_info/MeshQualityArea.cxx index 083a7aee1..43a1b5492 100644 --- a/vtkm/filter/mesh_info/MeshQualityArea.cxx +++ b/vtkm/filter/mesh_info/MeshQualityArea.cxx @@ -61,7 +61,7 @@ struct AreaWorklet : vtkm::worklet::WorkletVisitCellsWithPoints vtkmGenericCellShapeMacro(metricValue = this->ComputeMetric(numPoints, pts, CellShapeTag())); default: - this->RaiseError(vtkm::ErrorString(vtkm::ErrorCode::CellNotFound)); + this->RaiseError(vtkm::ErrorString(vtkm::ErrorCode::InvalidShapeId)); metricValue = OutType(0.0); } } diff --git a/vtkm/filter/mesh_info/MeshQualityVolume.cxx b/vtkm/filter/mesh_info/MeshQualityVolume.cxx index 223774312..f2a9eba9e 100644 --- a/vtkm/filter/mesh_info/MeshQualityVolume.cxx +++ b/vtkm/filter/mesh_info/MeshQualityVolume.cxx @@ -50,7 +50,7 @@ struct VolumeWorklet : vtkm::worklet::WorkletVisitCellsWithPoints vtkmGenericCellShapeMacro(metricValue = this->ComputeMetric(numPoints, pts, CellShapeTag())); default: - this->RaiseError(vtkm::ErrorString(vtkm::ErrorCode::CellNotFound)); + this->RaiseError(vtkm::ErrorString(vtkm::ErrorCode::InvalidShapeId)); metricValue = OutType(0.0); } } diff --git a/vtkm/filter/mesh_info/worklet/MeshQualityWorklet.h b/vtkm/filter/mesh_info/worklet/MeshQualityWorklet.h index 610f25eb9..a3e024350 100644 --- a/vtkm/filter/mesh_info/worklet/MeshQualityWorklet.h +++ b/vtkm/filter/mesh_info/worklet/MeshQualityWorklet.h @@ -69,7 +69,7 @@ struct MeshQualityWorklet : vtkm::worklet::WorkletVisitCellsWithPoints vtkmGenericCellShapeMacro(metricValue = self->template ComputeMetric( numPoints, pts, CellShapeTag{}, errorCode)); default: - errorCode = vtkm::ErrorCode::CellNotFound; + errorCode = vtkm::ErrorCode::InvalidShapeId; metricValue = OutType(0.0); }