diff --git a/docs/changelog/vectraits-for-all.md b/docs/changelog/vectraits-for-all.md new file mode 100644 index 000000000..9de668741 --- /dev/null +++ b/docs/changelog/vectraits-for-all.md @@ -0,0 +1,19 @@ +# Implemented `VecTraits` class for all types + +The `VecTraits` class allows templated functions, methods, and classes to +treat type arguments uniformly as `Vec` types or to otherwise differentiate +between scalar and vector types. This only works for types that `VecTraits` +is defined for. + +The `VecTraits` templated class now has a default implementation that will +be used for any type that does not have a `VecTraits` specialization. This +removes many surprise compiler errors when using a template that, unknown +to you, has `VecTraits` in its implementation. + +One potential issue is that if `VecTraits` gets defined for a new type, the +behavior of `VecTraits` could change for that type in backward-incompatible +ways. If `VecTraits` is used in a purely generic way, this should not be an +issue. However, if assumptions were made about the components and length, +this could cause problems. + +Fixes #589. diff --git a/vtkm/TypeTraits.h b/vtkm/TypeTraits.h index f321d3bf9..ae1a5e7ca 100644 --- a/vtkm/TypeTraits.h +++ b/vtkm/TypeTraits.h @@ -69,7 +69,7 @@ public: /// \brief A tag to determine whether the type has multiple components. /// /// This tag is either TypeTraitsScalarTag or TypeTraitsVectorTag. Scalars can - /// also be treated as vectors. + /// also be treated as vectors with VecTraits. using DimensionalityTag = vtkm::TypeTraitsUnknownTag; VTKM_EXEC_CONT static T ZeroInitialization() { return T(); } diff --git a/vtkm/VecFlat.h b/vtkm/VecFlat.h index 476241881..01d2b5028 100644 --- a/vtkm/VecFlat.h +++ b/vtkm/VecFlat.h @@ -22,20 +22,18 @@ namespace internal { template ::HasMultipleComponents> + typename MultipleComponents = typename vtkm::VecTraits::HasMultipleComponents> struct TotalNumComponents; template struct TotalNumComponents { VTKM_STATIC_ASSERT_MSG( - (std::is_same::IsSizeStatic, - vtkm::VecTraitsTagSizeStatic>::value), + (std::is_same::IsSizeStatic, vtkm::VecTraitsTagSizeStatic>::value), "vtkm::VecFlat can only be used with Vec types with a static number of components."); - using ComponentType = typename vtkm::internal::SafeVecTraits::ComponentType; + using ComponentType = typename vtkm::VecTraits::ComponentType; static constexpr vtkm::IdComponent value = - vtkm::internal::SafeVecTraits::NUM_COMPONENTS * TotalNumComponents::value; + vtkm::VecTraits::NUM_COMPONENTS * TotalNumComponents::value; }; template @@ -45,7 +43,7 @@ struct TotalNumComponents }; template -using FlattenVec = vtkm::Vec::BaseComponentType, +using FlattenVec = vtkm::Vec::BaseComponentType, vtkm::internal::TotalNumComponents::value>; template @@ -64,10 +62,10 @@ VTKM_EXEC_CONT T GetFlatVecComponentImpl(const T& component, } template -VTKM_EXEC_CONT typename vtkm::internal::SafeVecTraits::BaseComponentType +VTKM_EXEC_CONT typename vtkm::VecTraits::BaseComponentType GetFlatVecComponentImpl(const T& vec, vtkm::IdComponent index, std::false_type vtkmNotUsed(isBase)) { - using Traits = vtkm::internal::SafeVecTraits; + using Traits = vtkm::VecTraits; using ComponentType = typename Traits::ComponentType; using BaseComponentType = typename Traits::BaseComponentType; @@ -80,7 +78,7 @@ GetFlatVecComponentImpl(const T& vec, vtkm::IdComponent index, std::false_type v } // namespace detail template -VTKM_EXEC_CONT typename vtkm::internal::SafeVecTraits::BaseComponentType GetFlatVecComponent( +VTKM_EXEC_CONT typename vtkm::VecTraits::BaseComponentType GetFlatVecComponent( const T& vec, vtkm::IdComponent index) { @@ -114,7 +112,7 @@ VTKM_EXEC_CONT void CopyVecNestedToFlatImpl(const NestedVecType& nestedVec, vtkm::Vec& flatVec, vtkm::IdComponent flatOffset) { - using Traits = vtkm::internal::SafeVecTraits; + using Traits = vtkm::VecTraits; using ComponentType = typename Traits::ComponentType; constexpr vtkm::IdComponent subSize = TotalNumComponents::value; @@ -176,7 +174,7 @@ VTKM_EXEC_CONT void CopyVecFlatToNestedImpl(const vtkm::Vec& flatVec, vtkm::IdComponent flatOffset, NestedVecType& nestedVec) { - using Traits = vtkm::internal::SafeVecTraits; + using Traits = vtkm::VecTraits; using ComponentType = typename Traits::ComponentType; constexpr vtkm::IdComponent subSize = TotalNumComponents::value; diff --git a/vtkm/VecFromPortal.h b/vtkm/VecFromPortal.h index a5b5caca2..4f2330981 100644 --- a/vtkm/VecFromPortal.h +++ b/vtkm/VecFromPortal.h @@ -117,8 +117,7 @@ struct VecTraits> using VecType = vtkm::VecFromPortal; using ComponentType = typename VecType::ComponentType; - using BaseComponentType = - typename vtkm::internal::SafeVecTraits::BaseComponentType; + using BaseComponentType = typename vtkm::VecTraits::BaseComponentType; using HasMultipleComponents = vtkm::VecTraitsTagMultipleComponents; using IsSizeStatic = vtkm::VecTraitsTagSizeVariable; diff --git a/vtkm/VecTraits.h b/vtkm/VecTraits.h index 440a4ced2..a66ad5136 100644 --- a/vtkm/VecTraits.h +++ b/vtkm/VecTraits.h @@ -10,6 +10,8 @@ #ifndef vtk_m_VecTraits_h #define vtk_m_VecTraits_h +#include +#include #include namespace vtkm @@ -42,64 +44,55 @@ struct VecTraitsTagSizeVariable { }; -namespace internal -{ - -// Forward declaration -template -struct SafeVecTraits; - -template -struct VecTraitsMultipleComponentChooser -{ - using Type = vtkm::VecTraitsTagMultipleComponents; -}; - -template -struct VecTraitsMultipleComponentChooser<1, ComponentType> -{ - using Type = typename vtkm::internal::SafeVecTraits::HasMultipleComponents; -}; - -} // namespace internal - -/// The VecTraits class gives several static members that define how -/// to use a given type as a vector. +/// \brief Traits that can be queried to treat any type as a `Vec`. /// -template +/// The VecTraits class gives several static members that define how +/// to use a given type as a vector. This is useful for templated +/// functions and methods that have a parameter that could be either +/// a standard scalar type or a `Vec` or some other `Vec`-like +/// object. When using this class, scalar objects are treated like +/// a `Vec` of size 1. +/// +/// The default implementation of this template treats the type as +/// a scalar. Types that actually behave like vectors should +/// specialize this template to provide the proper information. +/// +template struct VTKM_NEVER_EXPORT VecTraits { -#ifdef VTKM_DOXYGEN_ONLY + // The base VecTraits should not be used with qualifiers. + VTKM_STATIC_ASSERT_MSG((std::is_same>, T>::value), + "The base VecTraits should not be used with qualifiers."); + /// \brief Type of the components in the vector. /// /// If the type is really a scalar, then the component type is the same as the scalar type. /// - using ComponentType = typename VecType::ComponentType; + using ComponentType = T; /// \brief Base component type in the vector. /// /// Similar to ComponentType except that for nested vectors (e.g. Vec, N>), it /// returns the base scalar type at the end of the composition (T in this example). /// - using BaseComponentType = typename vtkm::VecTraits::BaseComponentType; + using BaseComponentType = T; /// \brief Number of components in the vector. /// /// This is only defined for vectors of a static size. /// - static constexpr vtkm::IdComponent NUM_COMPONENTS = VecType::NUM_COMPONENTS; + static constexpr vtkm::IdComponent NUM_COMPONENTS = 1; /// Number of components in the given vector. /// - static vtkm::IdComponent GetNumberOfComponents(const VecType& vec); + 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. /// - using HasMultipleComponents = - typename internal::VecTraitsMultipleComponentChooser::Type; + using HasMultipleComponents = vtkm::VecTraitsTagSingleComponent; /// \brief A tag specifying whether the size of this vector is known at compile time. /// @@ -111,81 +104,113 @@ struct VTKM_NEVER_EXPORT VecTraits /// Returns the value in a given component of the vector. /// - VTKM_EXEC_CONT static const ComponentType& GetComponent( - const typename std::remove_const::type& vector, - vtkm::IdComponent component); - VTKM_EXEC_CONT static ComponentType& GetComponent( - typename std::remove_const::type& vector, - vtkm::IdComponent component); + VTKM_EXEC_CONT static const ComponentType& GetComponent(const T& vector, + vtkm::IdComponent vtkmNotUsed(component)) + { + return vector; + } + VTKM_EXEC_CONT static ComponentType& GetComponent(T& vector, + vtkm::IdComponent vtkmNotUsed(component)) + { + return vector; + } /// Changes the value in a given component of the vector. /// - VTKM_EXEC_CONT static void SetComponent(VecType& vector, - vtkm::IdComponent component, - ComponentType value); + VTKM_EXEC_CONT static void SetComponent(T& vector, + vtkm::IdComponent vtkmNotUsed(component), + ComponentType value) + { + vector = value; + } /// \brief Get a vector of the same type but with a different component. /// /// This type resolves to another vector with a different component type. For example, - /// @code vtkm::VecTraits>::ReplaceComponentType @endcode is vtkm::Vec. - /// This replacement is not recursive. So @code VecTraits, N>::ReplaceComponentType @endcode - /// is vtkm::Vec. + /// `vtkm::VecTraits>::ReplaceComponentType` is `vtkm::Vec`. + /// This replacement is not recursive. So `VecTraits, N>::ReplaceComponentType` + /// is `vtkm::Vec`. /// template - using ReplaceComponentType = VecTemplate; + using ReplaceComponentType = NewComponentType; /// \brief Get a vector of the same type but with a different base component. /// /// This type resolves to another vector with a different base component type. The replacement /// is recursive for nested types. For example, - /// @code VecTraits, N>::ReplaceBaseComponentType @endcode is Vec, N>. + /// `VecTraits, N>::ReplaceBaseComponentType` is `Vec, N>`. /// template - using ReplaceBaseComponentType = VecTemplate< - typename VecTraits::template ReplaceBaseComponentType, - N>; + using ReplaceBaseComponentType = NewComponentType; /// Copies the components in the given vector into a given Vec object. /// - template - VTKM_EXEC_CONT static void CopyInto(const VecType& src, vtkm::Vec& dest); -#endif // VTKM_DOXYGEN_ONLY + template + VTKM_EXEC_CONT static void CopyInto(const T& src, vtkm::Vec& dest) + { + dest[0] = src; + } }; -namespace detail -{ - template -struct HasVecTraitsImpl -{ - template ::ComponentType> - static std::true_type Test(A*); +using HasVecTraits VTKM_DEPRECATED(2.1, "All types now have VecTraits defined.") = std::true_type; - static std::false_type Test(...); - - using Type = decltype(Test(std::declval())); -}; - -} // namespace detail - -/// \brief Determines whether the given type has VecTraits defined. -/// -/// If the given type T has a valid VecTraits class, then HasVecTraits will be set to -/// std::true_type. Otherwise it will be set to std::false_type. For example, -/// HasVecTraits is the same as std::true_type whereas HasVecTraits is the same -/// as std::false_type. This is useful to block the definition of methods using VecTraits when -/// VecTraits are not defined. -/// -template -using HasVecTraits = typename detail::HasVecTraitsImpl::Type; - -// This partial specialization allows you to define a non-const version of -// VecTraits and have it still work for const version. -// +// These partial specializations allow VecTraits to work with const and reference qualifiers. template struct VTKM_NEVER_EXPORT VecTraits : VecTraits { }; +template +struct VTKM_NEVER_EXPORT VecTraits : VecTraits +{ +}; +template +struct VTKM_NEVER_EXPORT VecTraits : VecTraits +{ +}; + +// This partial specialization allows VecTraits to work with pointers. +template +struct VTKM_NEVER_EXPORT VecTraits : VecTraits +{ + VTKM_EXEC_CONT static vtkm::IdComponent GetNumberOfComponents(const T* vector) + { + return VecTraits::GetNumberOfComponents(*vector); + } + VTKM_EXEC_CONT static auto GetComponent(const T* vector, vtkm::IdComponent component) + -> decltype(VecTraits::GetComponent(*vector, component)) + { + return VecTraits::GetComponent(*vector, component); + } + VTKM_EXEC_CONT static auto GetComponent(T* vector, vtkm::IdComponent component) + -> decltype(VecTraits::GetComponent(*vector, component)) + { + return VecTraits::GetComponent(*vector, component); + } + VTKM_EXEC_CONT static void SetComponent(T* vector, + vtkm::IdComponent component, + typename VecTraits::ComponentType value) + { + VecTraits::SetComponent(*vector, component, value); + } + template + using ReplaceComponentType = + typename VecTraits::template ReplaceComponentType*; + template + using ReplaceBaseComponentType = + typename VecTraits::template ReplaceBaseComponentType*; + template + VTKM_EXEC_CONT static void CopyInto( + const T* src, + vtkm::Vec::ComponentType, destSize>& dest) + { + VecTraits::CopyInto(*src, dest); + } +}; +template +struct VTKM_NEVER_EXPORT VecTraits : VecTraits +{ +}; #if defined(VTKM_GCC) && (__GNUC__ <= 5) namespace detail @@ -201,13 +226,29 @@ template struct VecReplaceBaseComponentTypeGCC4or5 { using type = - vtkm::Vec::template ReplaceBaseComponentType, - Size>; + vtkm::Vec::template ReplaceBaseComponentType, Size>; }; } // namespace detail #endif // GCC Version 4.8 +namespace internal +{ + +template +struct VecTraitsMultipleComponentChooser +{ + using Type = vtkm::VecTraitsTagMultipleComponents; +}; + +template +struct VecTraitsMultipleComponentChooser<1, ComponentType> +{ + using Type = typename vtkm::VecTraits::HasMultipleComponents; +}; + +} // namespace internal + template struct VTKM_NEVER_EXPORT VecTraits> { @@ -224,8 +265,7 @@ struct VTKM_NEVER_EXPORT VecTraits> /// Similar to ComponentType except that for nested vectors (e.g. Vec, N>), it /// returns the base scalar type at the end of the composition (T in this example). /// - using BaseComponentType = - typename vtkm::internal::SafeVecTraits::BaseComponentType; + using BaseComponentType = typename vtkm::VecTraits::BaseComponentType; /// Number of components in the vector. /// @@ -304,10 +344,9 @@ struct VTKM_NEVER_EXPORT VecTraits> typename detail::VecReplaceBaseComponentTypeGCC4or5::type; #else // !GCC <= 5 template - using ReplaceBaseComponentType = - vtkm::Vec::template ReplaceBaseComponentType, - Size>; + using ReplaceBaseComponentType = vtkm::Vec< + typename vtkm::VecTraits::template ReplaceBaseComponentType, + Size>; #endif ///@} @@ -509,7 +548,8 @@ namespace internal /// Used for overriding VecTraits for basic scalar types. /// template -struct VTKM_NEVER_EXPORT VecTraitsBasic +struct VTKM_DEPRECATED(2.1, "VecTraitsBasic is now the default implementation for VecTraits.") + VTKM_NEVER_EXPORT VecTraitsBasic { using ComponentType = ScalarType; using BaseComponentType = ScalarType; @@ -548,87 +588,41 @@ struct VTKM_NEVER_EXPORT VecTraitsBasic } }; -namespace detail -{ - -template > -struct VTKM_NEVER_EXPORT SafeVecTraitsImpl; - template -struct VTKM_NEVER_EXPORT SafeVecTraitsImpl : vtkm::VecTraits -{ -}; - -template -struct VTKM_NEVER_EXPORT SafeVecTraitsImpl : vtkm::internal::VecTraitsBasic -{ -}; - -} // namespace detail - -/// \brief A version of VecTraits that will be available for any type. -/// -/// The `VecTraits` template is only defined for types that have a specific specialization -/// for it. That means if you use `VecTraits` in a template, that template will likely -/// fail to build for types that are not defined for `VecTraits`. -/// -/// To use `VecTraits` in a class that should support all types, not just those with -/// defined `VecTraits`, you can use this "safe" version. `SafeVecTraits` is the same as -/// `VecTraits` if the latter is defined. If the `VecTraits` are not defined, then -/// `SafeVecTraits` treats the type as a simple scalar value. -/// -/// This template ensures that it will work reasonably well for all types. But be careful -/// as if `VecTraits` is later defined, the template is likely to change. -/// -template -struct VTKM_NEVER_EXPORT SafeVecTraits : detail::SafeVecTraitsImpl +struct VTKM_DEPRECATED(2.1 "VecTraits now safe to use on any type.") VTKM_NEVER_EXPORT SafeVecTraits + : vtkm::VecTraits { }; } // namespace internal -/// \brief VecTraits for Pair types -/// -/// Although a pair would seem better as a size-2 vector, we treat it as a -/// scalar. This is because a \c Vec is assumed to have the same type for -/// every component, and a pair in general has a different type for each -/// component. Thus we treat a pair as a "scalar" unit. -/// -template -struct VTKM_NEVER_EXPORT VecTraits> - : public vtkm::internal::VecTraitsBasic> +namespace detail +{ + +struct VTKM_DEPRECATED(2.1, + "VTKM_BASIC_TYPE_VECTOR is no longer necessary because VecTraits implements " + "basic type by default.") VTKM_BASIC_TYPE_VECTOR_is_deprecated { }; +template +struct issue_VTKM_BASIC_TYPE_VECTOR_deprecation_warning; + +} + } // namespace vtkm -#define VTKM_BASIC_TYPE_VECTOR(type) \ - namespace vtkm \ - { \ - template <> \ - struct VTKM_NEVER_EXPORT VecTraits : public vtkm::internal::VecTraitsBasic \ - { \ - }; \ +#define VTKM_BASIC_TYPE_VECTOR(type) \ + namespace vtkm \ + { \ + namespace detail \ + { \ + template <> \ + struct issue_VTKM_BASIC_TYPE_VECTOR_deprecation_warning \ + : public vtkm::detail::VTKM_BASIC_TYPE_VECTOR_is_deprecated \ + { \ + }; \ + } \ } -/// Allows you to treat basic types as if they were vectors. - -VTKM_BASIC_TYPE_VECTOR(float) -VTKM_BASIC_TYPE_VECTOR(double) - -VTKM_BASIC_TYPE_VECTOR(bool) -VTKM_BASIC_TYPE_VECTOR(char) -VTKM_BASIC_TYPE_VECTOR(signed char) -VTKM_BASIC_TYPE_VECTOR(unsigned char) -VTKM_BASIC_TYPE_VECTOR(short) -VTKM_BASIC_TYPE_VECTOR(unsigned short) -VTKM_BASIC_TYPE_VECTOR(int) -VTKM_BASIC_TYPE_VECTOR(unsigned int) -VTKM_BASIC_TYPE_VECTOR(long) -VTKM_BASIC_TYPE_VECTOR(unsigned long) -VTKM_BASIC_TYPE_VECTOR(long long) -VTKM_BASIC_TYPE_VECTOR(unsigned long long) - -//#undef VTKM_BASIC_TYPE_VECTOR - #endif //vtk_m_VecTraits_h diff --git a/vtkm/cont/ArrayCopy.h b/vtkm/cont/ArrayCopy.h index 612a7e4f4..8e70f1c1e 100644 --- a/vtkm/cont/ArrayCopy.h +++ b/vtkm/cont/ArrayCopy.h @@ -33,21 +33,6 @@ namespace cont namespace detail { -// Compile-time check to make sure that an `ArrayHandle` passed to `ArrayCopy` -// can be passed to a `UnknownArrayHandle`. This function does nothing -// except provide a compile error that is easier to understand than if you -// let it go and error in `UnknownArrayHandle`. (Huh? I'm not using that.) -template -inline void ArrayCopyValueTypeCheck() -{ - VTKM_STATIC_ASSERT_MSG(vtkm::HasVecTraits::value, - "An `ArrayHandle` that has a special value type that is not supported " - "by the precompiled version of `ArrayCopy` has been used. If this array " - "must be deep copied, consider using `ArrayCopyDevice`. Look at the " - "compile error for the type assigned to template parameter `T` to " - "see the offending type."); -} - template struct ArrayCopyConcreteSrc; @@ -74,8 +59,6 @@ void ArrayCopyImpl(const vtkm::cont::UnknownArrayHandle& source, std::false_type, std::true_type) { - detail::ArrayCopyValueTypeCheck(); - using DestType = vtkm::cont::ArrayHandle; if (source.CanConvert()) { @@ -96,9 +79,6 @@ void ArrayCopyImpl(const vtkm::cont::ArrayHandle& source, std::true_type, std::true_type) { - ArrayCopyValueTypeCheck(); - ArrayCopyValueTypeCheck(); - detail::ArrayCopyConcreteSrc{}(source, destination); } diff --git a/vtkm/cont/ArrayExtractComponent.h b/vtkm/cont/ArrayExtractComponent.h index 4d412a51d..12dc1eeaa 100644 --- a/vtkm/cont/ArrayExtractComponent.h +++ b/vtkm/cont/ArrayExtractComponent.h @@ -37,7 +37,7 @@ namespace internal // is defined rather than where it is resolved. This causes problems when extracting // components of, say, an ArrayHandleMultiplexer holding an ArrayHandleSOA. template -vtkm::cont::ArrayHandleStride::BaseComponentType> +vtkm::cont::ArrayHandleStride::BaseComponentType> ArrayExtractComponentFallback(const vtkm::cont::ArrayHandle& src, vtkm::IdComponent componentIndex, vtkm::CopyFlag allowCopy) @@ -53,7 +53,7 @@ ArrayExtractComponentFallback(const vtkm::cont::ArrayHandle& src, << vtkm::cont::TypeToString>() << " requires an inefficient memory copy."); - using BaseComponentType = typename vtkm::internal::SafeVecTraits::BaseComponentType; + using BaseComponentType = typename vtkm::VecTraits::BaseComponentType; vtkm::Id numValues = src.GetNumberOfValues(); vtkm::cont::ArrayHandleBasic dest; dest.Allocate(numValues); @@ -78,10 +78,10 @@ template struct ArrayExtractComponentImpl : ArrayExtractComponentImplInefficient { template - vtkm::cont::ArrayHandleStride::BaseComponentType> - operator()(const vtkm::cont::ArrayHandle& src, - vtkm::IdComponent componentIndex, - vtkm::CopyFlag allowCopy) const + vtkm::cont::ArrayHandleStride::BaseComponentType> operator()( + const vtkm::cont::ArrayHandle& src, + vtkm::IdComponent componentIndex, + vtkm::CopyFlag allowCopy) const { // This is the slow "default" implementation. ArrayHandle implementations should provide // more efficient overloads where applicable. @@ -93,15 +93,13 @@ template <> struct ArrayExtractComponentImpl { template - vtkm::cont::ArrayHandleStride::BaseComponentType> - operator()(const vtkm::cont::ArrayHandle& src, - vtkm::IdComponent componentIndex, - vtkm::CopyFlag allowCopy) const + vtkm::cont::ArrayHandleStride::BaseComponentType> operator()( + const vtkm::cont::ArrayHandle& src, + vtkm::IdComponent componentIndex, + vtkm::CopyFlag allowCopy) const { - return this->DoExtract(src, - componentIndex, - allowCopy, - typename vtkm::internal::SafeVecTraits::HasMultipleComponents{}); + return this->DoExtract( + src, componentIndex, allowCopy, typename vtkm::VecTraits::HasMultipleComponents{}); } private: @@ -112,7 +110,7 @@ private: vtkm::VecTraitsTagSingleComponent) const { VTKM_ASSERT(componentIndex == 0); - using VTraits = vtkm::internal::SafeVecTraits; + using VTraits = vtkm::VecTraits; using TBase = typename VTraits::BaseComponentType; VTKM_STATIC_ASSERT(VTraits::NUM_COMPONENTS == 1); @@ -135,7 +133,7 @@ private: vtkm::CopyFlag allowCopy, vtkm::VecTraitsTagMultipleComponents) const { - using VTraits = vtkm::internal::SafeVecTraits; + using VTraits = vtkm::VecTraits; using T = typename VTraits::ComponentType; constexpr vtkm::IdComponent N = VTraits::NUM_COMPONENTS; @@ -254,10 +252,10 @@ using ArrayExtractComponentIsInefficient = typename std::is_base_of< /// `vtkm::cont::internal::ArrayExtractComponentImpl`. /// template -vtkm::cont::ArrayHandleStride::BaseComponentType> -ArrayExtractComponent(const vtkm::cont::ArrayHandle& src, - vtkm::IdComponent componentIndex, - vtkm::CopyFlag allowCopy = vtkm::CopyFlag::On) +vtkm::cont::ArrayHandleStride::BaseComponentType> ArrayExtractComponent( + const vtkm::cont::ArrayHandle& src, + vtkm::IdComponent componentIndex, + vtkm::CopyFlag allowCopy = vtkm::CopyFlag::On) { return internal::ArrayExtractComponentImpl{}(src, componentIndex, allowCopy); } diff --git a/vtkm/cont/ArrayGetValues.h b/vtkm/cont/ArrayGetValues.h index e4a19fb14..51e23e444 100644 --- a/vtkm/cont/ArrayGetValues.h +++ b/vtkm/cont/ArrayGetValues.h @@ -120,9 +120,6 @@ VTKM_CONT void ArrayGetValues(const vtkm::cont::ArrayHandle& ids const vtkm::cont::ArrayHandle& data, vtkm::cont::ArrayHandle& output) { - VTKM_STATIC_ASSERT_MSG( - vtkm::HasVecTraits::value, - "ArrayGetValues can only be used with arrays containing value types with VecTraits defined."); using DataArrayHandle = vtkm::cont::ArrayHandle; using InefficientExtract = vtkm::cont::internal::ArrayExtractComponentIsInefficient; diff --git a/vtkm/cont/ArrayHandle.h b/vtkm/cont/ArrayHandle.h index 09a40f346..6a4467b15 100644 --- a/vtkm/cont/ArrayHandle.h +++ b/vtkm/cont/ArrayHandle.h @@ -752,9 +752,9 @@ VTKM_NEVER_EXPORT VTKM_CONT inline void printSummary_ArrayHandle_Value( std::ostream& out, vtkm::VecTraitsTagMultipleComponents) { - using Traits = vtkm::internal::SafeVecTraits; + using Traits = vtkm::VecTraits; using ComponentType = typename Traits::ComponentType; - using IsVecOfVec = typename vtkm::internal::SafeVecTraits::HasMultipleComponents; + using IsVecOfVec = typename vtkm::VecTraits::HasMultipleComponents; vtkm::IdComponent numComponents = Traits::GetNumberOfComponents(value); out << "("; printSummary_ArrayHandle_Value(Traits::GetComponent(value, 0), out, IsVecOfVec()); @@ -774,10 +774,10 @@ VTKM_NEVER_EXPORT VTKM_CONT inline void printSummary_ArrayHandle_Value( { out << "{"; printSummary_ArrayHandle_Value( - value.first, out, typename vtkm::internal::SafeVecTraits::HasMultipleComponents()); + value.first, out, typename vtkm::VecTraits::HasMultipleComponents()); out << ","; printSummary_ArrayHandle_Value( - value.second, out, typename vtkm::internal::SafeVecTraits::HasMultipleComponents()); + value.second, out, typename vtkm::VecTraits::HasMultipleComponents()); out << "}"; } @@ -793,7 +793,7 @@ VTKM_NEVER_EXPORT VTKM_CONT inline void printSummary_ArrayHandle( { using ArrayType = vtkm::cont::ArrayHandle; using PortalType = typename ArrayType::ReadPortalType; - using IsVec = typename vtkm::internal::SafeVecTraits::HasMultipleComponents; + using IsVec = typename vtkm::VecTraits::HasMultipleComponents; vtkm::Id sz = array.GetNumberOfValues(); diff --git a/vtkm/cont/ArrayHandleCounting.h b/vtkm/cont/ArrayHandleCounting.h index 2840eeaeb..7f2eae8c1 100644 --- a/vtkm/cont/ArrayHandleCounting.h +++ b/vtkm/cont/ArrayHandleCounting.h @@ -77,27 +77,17 @@ private: namespace detail { -template > -struct CanCountImpl; - template -struct CanCountImpl -{ - using TTraits = vtkm::TypeTraits; - static constexpr bool IsNumeric = - !std::is_same::value; - - static constexpr bool value = IsNumeric; -}; - -template -struct CanCountImpl +struct CanCountImpl { using VTraits = vtkm::VecTraits; using BaseType = typename VTraits::BaseComponentType; + using TTraits = vtkm::TypeTraits; + static constexpr bool IsNumeric = + !std::is_same::value; static constexpr bool IsBool = std::is_same::value; - static constexpr bool value = CanCountImpl::value && !IsBool; + static constexpr bool value = IsNumeric && !IsBool; }; } // namespace detail diff --git a/vtkm/cont/ArrayHandleRecombineVec.h b/vtkm/cont/ArrayHandleRecombineVec.h index f99303a95..1a817e296 100644 --- a/vtkm/cont/ArrayHandleRecombineVec.h +++ b/vtkm/cont/ArrayHandleRecombineVec.h @@ -87,7 +87,7 @@ public: return *this; } - template ::value>::type> + template VTKM_EXEC_CONT RecombineVec& operator=(const T& src) { this->DoCopy(src); @@ -104,7 +104,7 @@ public: return result; } - template ::value>::type> + template VTKM_EXEC_CONT RecombineVec& operator+=(const T& src) { using VTraits = vtkm::VecTraits; @@ -115,7 +115,7 @@ public: } return *this; } - template ::value>::type> + template VTKM_EXEC_CONT RecombineVec& operator-=(const T& src) { using VTraits = vtkm::VecTraits; @@ -126,7 +126,7 @@ public: } return *this; } - template ::value>::type> + template VTKM_EXEC_CONT RecombineVec& operator*=(const T& src) { using VTraits = vtkm::VecTraits; @@ -137,7 +137,7 @@ public: } return *this; } - template ::value>::type> + template VTKM_EXEC_CONT RecombineVec& operator/=(const T& src) { using VTraits = vtkm::VecTraits; @@ -148,7 +148,7 @@ public: } return *this; } - template ::value>::type> + template VTKM_EXEC_CONT RecombineVec& operator%=(const T& src) { using VTraits = vtkm::VecTraits; @@ -159,7 +159,7 @@ public: } return *this; } - template ::value>::type> + template VTKM_EXEC_CONT RecombineVec& operator&=(const T& src) { using VTraits = vtkm::VecTraits; @@ -170,7 +170,7 @@ public: } return *this; } - template ::value>::type> + template VTKM_EXEC_CONT RecombineVec& operator|=(const T& src) { using VTraits = vtkm::VecTraits; @@ -181,7 +181,7 @@ public: } return *this; } - template ::value>::type> + template VTKM_EXEC_CONT RecombineVec& operator^=(const T& src) { using VTraits = vtkm::VecTraits; @@ -192,7 +192,7 @@ public: } return *this; } - template ::value>::type> + template VTKM_EXEC_CONT RecombineVec& operator>>=(const T& src) { using VTraits = vtkm::VecTraits; @@ -203,7 +203,7 @@ public: } return *this; } - template ::value>::type> + template VTKM_EXEC_CONT RecombineVec& operator<<=(const T& src) { using VTraits = vtkm::VecTraits; diff --git a/vtkm/cont/ArrayHandleRuntimeVec.h b/vtkm/cont/ArrayHandleRuntimeVec.h index 6006452a9..4143c8bd4 100644 --- a/vtkm/cont/ArrayHandleRuntimeVec.h +++ b/vtkm/cont/ArrayHandleRuntimeVec.h @@ -141,7 +141,7 @@ class Storage, vtkm::cont::StorageTagRunti vtkm::cont::internal::Storage; VTKM_STATIC_ASSERT_MSG( - vtkm::internal::SafeVecTraits::NUM_COMPONENTS == 1, + vtkm::VecTraits::NUM_COMPONENTS == 1, "ArrayHandleRuntimeVec only supports scalars grouped into a single Vec. Nested Vecs can " "still be used with ArrayHandleRuntimeVec. The values are treated as flattened (like " "with VecFlat)."); diff --git a/vtkm/cont/ArrayHandleSOA.h b/vtkm/cont/ArrayHandleSOA.h index 552ab5d5a..d50d64470 100644 --- a/vtkm/cont/ArrayHandleSOA.h +++ b/vtkm/cont/ArrayHandleSOA.h @@ -44,7 +44,6 @@ public: private: using ComponentType = typename ComponentPortalType::ValueType; - VTKM_STATIC_ASSERT(vtkm::HasVecTraits::value); using VTraits = vtkm::VecTraits; VTKM_STATIC_ASSERT((std::is_same::value)); static constexpr vtkm::IdComponent NUM_COMPONENTS = VTraits::NUM_COMPONENTS; diff --git a/vtkm/cont/UnknownArrayHandle.h b/vtkm/cont/UnknownArrayHandle.h index 88b40590f..27c52ffc1 100644 --- a/vtkm/cont/UnknownArrayHandle.h +++ b/vtkm/cont/UnknownArrayHandle.h @@ -82,11 +82,9 @@ inline auto UnknownAHNumberOfComponentsImpl(void* mem) // of a use case for the storage to report the number of components for a static data type. // If that happens, this implementation will need to be modified. template -inline auto UnknownAHNumberOfComponentsImpl(void*) - -> decltype(vtkm::internal::SafeVecTraits::NUM_COMPONENTS) +inline auto UnknownAHNumberOfComponentsImpl(void*) -> decltype(vtkm::VecTraits::NUM_COMPONENTS) { - static constexpr vtkm::IdComponent numComponents = - vtkm::internal::SafeVecTraits::NUM_COMPONENTS; + static constexpr vtkm::IdComponent numComponents = vtkm::VecTraits::NUM_COMPONENTS; return numComponents; } @@ -117,7 +115,7 @@ inline auto UnknownAHNumberOfComponentsFlatImpl(void* mem) // static. If a future `ArrayHandle` type violates this, this code will have to become // more complex. return (vtkm::cont::internal::Storage::GetNumberOfComponents(arrayHandle->GetBuffers()) * - vtkm::VecFlat::ComponentType>::NUM_COMPONENTS); + vtkm::VecFlat::ComponentType>::NUM_COMPONENTS); } // Uses SFINAE to use the number of compnents in VecTraits. @@ -364,14 +362,13 @@ std::shared_ptr UnknownAHNewInstanceBasic(vtkm::VecTraitsTag template std::shared_ptr UnknownAHNewInstanceBasic() { - return UnknownAHNewInstanceBasic(typename vtkm::internal::SafeVecTraits::IsSizeStatic{}); + return UnknownAHNewInstanceBasic(typename vtkm::VecTraits::IsSizeStatic{}); } template std::shared_ptr UnknownAHNewInstanceFloatBasic(vtkm::VecTraitsTagSizeStatic) { - using FloatT = typename vtkm::internal::SafeVecTraits::template ReplaceBaseComponentType< - vtkm::FloatDefault>; + using FloatT = typename vtkm::VecTraits::template ReplaceBaseComponentType; return UnknownAHContainer::Make(vtkm::cont::ArrayHandleBasic{}); } template @@ -383,8 +380,7 @@ std::shared_ptr UnknownAHNewInstanceFloatBasic(vtkm::VecTrai template std::shared_ptr UnknownAHNewInstanceFloatBasic() { - return UnknownAHNewInstanceFloatBasic( - typename vtkm::internal::SafeVecTraits::IsSizeStatic{}); + return UnknownAHNewInstanceFloatBasic(typename vtkm::VecTraits::IsSizeStatic{}); } template @@ -393,7 +389,7 @@ inline UnknownAHContainer::UnknownAHContainer(const vtkm::cont::ArrayHandle::BaseComponentType>()) + UnknownAHComponentInfo::Make::BaseComponentType>()) , DeleteFunction(detail::UnknownAHDelete) , Buffers(detail::UnknownAHBuffers) , NewInstance(detail::UnknownAHNewInstance) @@ -1031,8 +1027,8 @@ namespace detail { template ::ComponentType>::NUM_COMPONENTS> + vtkm::IdComponent = + vtkm::VecTraits::ComponentType>::NUM_COMPONENTS> struct UnknownArrayHandleRuntimeVecAsBasic { VTKM_CONT bool operator()(const vtkm::cont::UnknownArrayHandle*, diff --git a/vtkm/cont/internal/MapArrayPermutation.cxx b/vtkm/cont/internal/MapArrayPermutation.cxx index cb3512df0..82de78f0f 100644 --- a/vtkm/cont/internal/MapArrayPermutation.cxx +++ b/vtkm/cont/internal/MapArrayPermutation.cxx @@ -36,7 +36,6 @@ struct MapPermutationWorklet : vtkm::worklet::WorkletMapField InputPortalType inputPortal, OutputType& output) const { - VTKM_STATIC_ASSERT(vtkm::HasVecTraits::value); if ((permutationIndex >= 0) && (permutationIndex < inputPortal.GetNumberOfValues())) { output = inputPortal.Get(permutationIndex); diff --git a/vtkm/cont/testing/UnitTestArrayHandleRuntimeVec.cxx b/vtkm/cont/testing/UnitTestArrayHandleRuntimeVec.cxx index a2da0ad5a..fdb4e7bd6 100644 --- a/vtkm/cont/testing/UnitTestArrayHandleRuntimeVec.cxx +++ b/vtkm/cont/testing/UnitTestArrayHandleRuntimeVec.cxx @@ -76,8 +76,8 @@ struct PassThrough : vtkm::worklet::WorkletMapField OutValue& outValue, vtkm::IdComponent& outIndex) const { - using VTraitsIn = vtkm::internal::SafeVecTraits; - using VTraitsOut = vtkm::internal::SafeVecTraits; + using VTraitsIn = vtkm::VecTraits; + using VTraitsOut = vtkm::VecTraits; VTraitsOut::SetComponent(outValue, outIndex, VTraitsIn::GetComponent(inValue, inIndex)); inIndex++; outIndex++; diff --git a/vtkm/internal/ArrayPortalValueReference.h b/vtkm/internal/ArrayPortalValueReference.h index e92340a3f..e7f849d31 100644 --- a/vtkm/internal/ArrayPortalValueReference.h +++ b/vtkm/internal/ArrayPortalValueReference.h @@ -19,39 +19,6 @@ namespace vtkm namespace internal { -namespace detail -{ - -// TODO: VecTraits should just always be supported. See #589. - -template ::value>::type> -VTKM_EXEC_CONT inline vtkm::IdComponent SafeGetNumberOfComponents(const Vec& vec) -{ - return vtkm::VecTraits::GetNumberOfComponents(vec); -} - -VTKM_EXEC_CONT inline vtkm::IdComponent SafeGetNumberOfComponents(...) -{ - return 1; -} - -template ::value>::type> -VTKM_EXEC_CONT inline typename vtkm::VecTraits::ComponentType SafeGetComponent( - const Vec& vec, - vtkm::IdComponent index) -{ - return vtkm::VecTraits::GetComponent(vec, index); -} - -template ::value>::type> -VTKM_EXEC_CONT inline T SafeGetComponent(const T& value, vtkm::IdComponent index) -{ - VTKM_ASSERT(index == 0); - return value; -} - -} // namespace detail - /// \brief A value class for returning setable values of an ArrayPortal /// /// \c ArrayPortal classes have a pair of \c Get and \c Set methods that @@ -350,12 +317,12 @@ struct ArrayPortalValueReference // cannot write components one at a time. VTKM_EXEC_CONT vtkm::IdComponent GetNumberOfComponents() const { - return detail::SafeGetNumberOfComponents(static_cast(*this)); + return vtkm::VecTraits::GetNumberOfComponents(this->Get()); } - VTKM_EXEC_CONT auto operator[](vtkm::IdComponent index) const - -> decltype(detail::SafeGetComponent(std::declval(), index)) + VTKM_EXEC_CONT + typename vtkm::VecTraits::ComponentType operator[](vtkm::IdComponent index) const { - return detail::SafeGetComponent(static_cast(*this), index); + return vtkm::VecTraits::GetComponent(this->Get(), index); } private: diff --git a/vtkm/io/internal/VTKDataSetTypes.h b/vtkm/io/internal/VTKDataSetTypes.h index eaeb811ea..483573a6f 100644 --- a/vtkm/io/internal/VTKDataSetTypes.h +++ b/vtkm/io/internal/VTKDataSetTypes.h @@ -242,11 +242,9 @@ inline void SelectTypeAndCall(DataType dtype, assert(false); } } + } } } // namespace vtkm::io::internal -VTKM_BASIC_TYPE_VECTOR(vtkm::io::internal::ColorChannel8) -VTKM_BASIC_TYPE_VECTOR(vtkm::io::internal::DummyBitType) - #endif // vtk_m_io_internal_VTKDataSetTypes_h diff --git a/vtkm/testing/Testing.h b/vtkm/testing/Testing.h index ed0217f67..36cb38616 100644 --- a/vtkm/testing/Testing.h +++ b/vtkm/testing/Testing.h @@ -624,12 +624,8 @@ namespace detail template struct TestEqualImpl { - template - VTKM_EXEC_CONT bool DoIt(T1 vector1, - T2 vector2, - vtkm::Float64 tolerance, - Dimensionality1, - Dimensionality2) const + template + VTKM_EXEC_CONT bool DoIt(T1 vector1, T2 vector2, vtkm::Float64 tolerance, IsBase1, IsBase2) const { using Traits1 = vtkm::VecTraits; using Traits2 = vtkm::VecTraits; @@ -658,8 +654,8 @@ struct TestEqualImpl VTKM_EXEC_CONT bool DoIt(T1 scalar1, T2 scalar2, vtkm::Float64 tolerance, - vtkm::TypeTraitsScalarTag, - vtkm::TypeTraitsScalarTag) const + std::true_type, + std::true_type) const { // Do all comparisons using 64-bit floats. return test_equal( @@ -668,11 +664,13 @@ struct TestEqualImpl VTKM_EXEC_CONT bool operator()(T1 value1, T2 value2, vtkm::Float64 tolerance) const { + using Base1 = typename vtkm::VecTraits::BaseComponentType; + using Base2 = typename vtkm::VecTraits::BaseComponentType; return this->DoIt(value1, value2, tolerance, - typename vtkm::TypeTraits::DimensionalityTag(), - typename vtkm::TypeTraits::DimensionalityTag()); + typename std::is_same::type{}, + typename std::is_same::type{}); } }; diff --git a/vtkm/testing/UnitTestVecTraits.cxx b/vtkm/testing/UnitTestVecTraits.cxx index 9642670b8..85a08c885 100644 --- a/vtkm/testing/UnitTestVecTraits.cxx +++ b/vtkm/testing/UnitTestVecTraits.cxx @@ -17,12 +17,18 @@ namespace static constexpr vtkm::Id MAX_VECTOR_SIZE = 5; static constexpr vtkm::Id VecInit[MAX_VECTOR_SIZE] = { 42, 54, 67, 12, 78 }; -void ExpectTrueType(std::true_type) {} - -void ExpectFalseType(std::false_type) {} - struct TypeWithoutVecTraits { + vtkm::Id Value = -1; + + TypeWithoutVecTraits() = default; + + TypeWithoutVecTraits(vtkm::Id value) + : Value(value) + { + } + + operator vtkm::Id() const { return this->Value; } }; struct TestVecTypeFunctor @@ -30,9 +36,6 @@ struct TestVecTypeFunctor template void operator()(const T&) const { - // Make sure that VecTraits actually exists - ExpectTrueType(vtkm::HasVecTraits()); - using Traits = vtkm::VecTraits; using ComponentType = typename Traits::ComponentType; VTKM_TEST_ASSERT(Traits::NUM_COMPONENTS <= MAX_VECTOR_SIZE, @@ -59,8 +62,8 @@ void TestVecTraits() vtkm::testing::Testing::TryTypes(test); std::cout << "vtkm::Vec" << std::endl; test(vtkm::Vec()); - - ExpectFalseType(vtkm::HasVecTraits()); + std::cout << "TypeWithoutVecTraits" << std::endl; + test(TypeWithoutVecTraits{}); vtkm::testing::TestVecComponentsTag(); vtkm::testing::TestVecComponentsTag(); @@ -69,6 +72,7 @@ void TestVecTraits() vtkm::testing::TestVecComponentsTag>(); vtkm::testing::TestScalarComponentsTag(); vtkm::testing::TestScalarComponentsTag(); + vtkm::testing::TestScalarComponentsTag(); } } // anonymous namespace diff --git a/vtkm/testing/VecTraitsTests.h b/vtkm/testing/VecTraitsTests.h index e84db5b72..0bec632a8 100644 --- a/vtkm/testing/VecTraitsTests.h +++ b/vtkm/testing/VecTraitsTests.h @@ -47,6 +47,12 @@ inline void CompareDimensionalityTags(vtkm::TypeTraitsVectorTag, { // If we are here, everything is fine. } +inline void CompareDimensionalityTags(vtkm::TypeTraitsUnknownTag, vtkm::VecTraitsTagSingleComponent) +{ + // If we are here, type traits are probably not defined (and default to unknown). In this case, + // we expect VecTraits to have the default implementation, in which case it is treated as a + // single component. +} template inline void CheckIsStatic(const T&, vtkm::VecTraitsTagSizeStatic) @@ -73,6 +79,12 @@ struct VecIsWritable> using type = std::false_type; }; +template +struct VecIsWritable*> +{ + using type = std::false_type; +}; + // Part of TestVecTypeImpl that writes to the Vec type template static void TestVecTypeWritableImpl(const T& inVector, @@ -150,8 +162,9 @@ static void TestVecTypeImpl(const typename std::remove_const::type& inVector, } // This will fail to compile if the tags are wrong. - detail::CompareDimensionalityTags(typename vtkm::TypeTraits::DimensionalityTag(), - typename vtkm::VecTraits::HasMultipleComponents()); + detail::CompareDimensionalityTags( + typename vtkm::TypeTraits>::DimensionalityTag(), + typename vtkm::VecTraits::HasMultipleComponents()); TestVecTypeWritableImpl( inVector, vectorCopy, outVector, typename VecIsWritable::type()); @@ -159,7 +172,9 @@ static void TestVecTypeImpl(const typename std::remove_const::type& inVector, // Compiler checks for base component types using BaseComponentType = typename vtkm::VecTraits::BaseComponentType; VTKM_STATIC_ASSERT((std::is_same::DimensionalityTag, - vtkm::TypeTraitsScalarTag>::value)); + vtkm::TypeTraitsScalarTag>::value) || + (std::is_same::DimensionalityTag, + vtkm::TypeTraitsUnknownTag>::value)); VTKM_STATIC_ASSERT((std::is_same::BaseComponentType, BaseComponentType>::value)); @@ -167,12 +182,12 @@ static void TestVecTypeImpl(const typename std::remove_const::type& inVector, using ReplaceWithVecComponent = typename vtkm::VecTraits::template ReplaceComponentType>; VTKM_STATIC_ASSERT( - (std::is_same::DimensionalityTag, + (std::is_same>::DimensionalityTag, vtkm::TypeTraitsVectorTag>::value && std::is_same::ComponentType, vtkm::Vec>::value) || - (std::is_same::DimensionalityTag, - vtkm::TypeTraitsScalarTag>::value && + (!std::is_same>::DimensionalityTag, + vtkm::TypeTraitsVectorTag>::value && std::is_same::ComponentType, char>::value)); VTKM_STATIC_ASSERT( (std::is_same::BaseComponentType, @@ -180,12 +195,12 @@ static void TestVecTypeImpl(const typename std::remove_const::type& inVector, using ReplaceBaseComponent = typename vtkm::VecTraits::template ReplaceBaseComponentType; VTKM_STATIC_ASSERT( - (std::is_same::DimensionalityTag, + (std::is_same>::DimensionalityTag, vtkm::TypeTraitsVectorTag>::value && std::is_same::ComponentType, vtkm::Vec>::value) || - (std::is_same::DimensionalityTag, - vtkm::TypeTraitsScalarTag>::value && + (!std::is_same>::DimensionalityTag, + vtkm::TypeTraitsVectorTag>::value && std::is_same::ComponentType, short>::value)); VTKM_STATIC_ASSERT(( std::is_same::BaseComponentType, short>::value)); @@ -227,6 +242,13 @@ static void TestVecType(const T& inVector, T& outVector) { detail::TestVecTypeImpl(inVector, outVector); detail::TestVecTypeImpl(inVector, outVector); + // The local pointer variables are for some weirdness about `TestVecTypeImpl` taking references + // of its argument type. + T* inPointer = const_cast(&inVector); + T* outPointer = &outVector; + detail::TestVecTypeImpl(inPointer, outPointer); + VTKM_STATIC_ASSERT_MSG((std::is_base_of, vtkm::VecTraits>::value), + "Constant pointer should have same implementation as pointer."); } /// Checks to make sure that the HasMultipleComponents tag is actually for a