From 97324e75cdbdc704d3fe5bab2ea4b54c299af9d4 Mon Sep 17 00:00:00 2001 From: Kenneth Moreland Date: Mon, 4 Jan 2021 16:36:03 -0700 Subject: [PATCH] Enable reinterpreting `UnknownArrayHandle` to compatible C types The base C types have several "duplicate" types that the compiler considers different even though the byte representation is the same. For example, `char` and `signed char` have the same meaning but are treated as different types. Likewise, 'long', 'int', and 'long long' are all different types even though 'long' is the same as either 'int' or 'long long'. When pulling extracted components from `UnknownArrayHandle`, there is little value for creating multiple code paths for types like `char` and `signed char`. Instead, allow implicit conversion among these types. --- vtkm/TypeList.h | 23 +++++++++----- vtkm/cont/UnknownArrayHandle.cxx | 17 +++++++++- vtkm/cont/UnknownArrayHandle.h | 46 +++++++++++++++++++++++++--- vtkm/testing/Testing.h | 1 + vtkm/testing/UnitTestTypeList.cxx | 39 +++++++++++++---------- vtkm/testing/UnitTestTypeListTag.cxx | 39 +++++++++++++---------- 6 files changed, 121 insertions(+), 44 deletions(-) diff --git a/vtkm/TypeList.h b/vtkm/TypeList.h index 47ddca749..34f1f4eb9 100644 --- a/vtkm/TypeList.h +++ b/vtkm/TypeList.h @@ -86,7 +86,12 @@ using TypeListField = vtkm::List; /// A list of all scalars defined in vtkm/Types.h. A scalar is a type that -/// holds a single number. +/// holds a single number. This should containing all true variations of +/// scalars, but there might be some arithmetic C types not included. For +/// example, this list contains `signed char`, and `unsigned char`, but not +/// `char` as one of those types will behave the same as it. Two of the three +/// types behave the same, but be aware that template resolution will treat +/// them differently. /// using TypeListScalarAll = vtkm::List; + vtkm::Float64>; + +// A list that containes all the base arithmetric C types (i.e. char, int, float, etc.). +// The list contains C types that are functionally equivalent but considered different +// types (e.g. it contains both `char` and `signed char`). +using TypeListBaseC = vtkm::ListAppend< + vtkm::TypeListScalarAll, + // Other base C types that are the same as above but + // recognized as different by the compiler + vtkm::List>; /// A list of the most commonly use Vec classes. Specifically, these are /// vectors of size 2, 3, or 4 containing either unsigned bytes, signed diff --git a/vtkm/cont/UnknownArrayHandle.cxx b/vtkm/cont/UnknownArrayHandle.cxx index f3771af55..ec07fdb97 100644 --- a/vtkm/cont/UnknownArrayHandle.cxx +++ b/vtkm/cont/UnknownArrayHandle.cxx @@ -59,6 +59,20 @@ std::shared_ptr UnknownAHContainer::MakeNewInstance() const return newContainer; } +bool UnknownAHComponentInfo::operator==(const UnknownAHComponentInfo& rhs) +{ + if (this->IsIntegral || this->IsFloat) + { + return ((this->IsIntegral == rhs.IsIntegral) && (this->IsFloat == rhs.IsFloat) && + (this->IsSigned == rhs.IsSigned) && (this->Size == rhs.Size)); + } + else + { + // Needs optimization based on platform. OSX cannot compare typeid across translation units? + return this->Type == rhs.Type; + } +} + } // namespace detail VTKM_CONT bool UnknownArrayHandle::IsValueTypeImpl(std::type_index type) const @@ -83,7 +97,8 @@ VTKM_CONT bool UnknownArrayHandle::IsStorageTypeImpl(std::type_index type) const return this->Container->StorageType == type; } -VTKM_CONT bool UnknownArrayHandle::IsBaseComponentTypeImpl(std::type_index type) const +VTKM_CONT bool UnknownArrayHandle::IsBaseComponentTypeImpl( + const detail::UnknownAHComponentInfo& type) const { if (!this->Container) { diff --git a/vtkm/cont/UnknownArrayHandle.h b/vtkm/cont/UnknownArrayHandle.h index 23f049ec2..2531cad91 100644 --- a/vtkm/cont/UnknownArrayHandle.h +++ b/vtkm/cont/UnknownArrayHandle.h @@ -142,13 +142,50 @@ struct MakeUnknownAHContainerFunctor std::shared_ptr operator()(const vtkm::cont::ArrayHandle& array) const; }; +struct VTKM_CONT_EXPORT UnknownAHComponentInfo +{ + std::type_index Type; + bool IsIntegral; + bool IsFloat; + bool IsSigned; + std::size_t Size; + + UnknownAHComponentInfo() = delete; + + bool operator==(const UnknownAHComponentInfo& rhs); + + template + static UnknownAHComponentInfo Make() + { + return UnknownAHComponentInfo{ typeid(T), + std::is_integral::value, + std::is_floating_point::value, + std::is_signed::value, + sizeof(T) }; + } + +private: + UnknownAHComponentInfo(std::type_index&& type, + bool isIntegral, + bool isFloat, + bool isSigned, + std::size_t size) + : Type(std::move(type)) + , IsIntegral(isIntegral) + , IsFloat(isFloat) + , IsSigned(isSigned) + , Size(size) + { + } +}; + struct VTKM_CONT_EXPORT UnknownAHContainer { void* ArrayHandlePointer; std::type_index ValueType; std::type_index StorageType; - std::type_index BaseComponentType; + UnknownAHComponentInfo BaseComponentType; using DeleteType = void(void*); DeleteType* DeleteFunction; @@ -247,7 +284,8 @@ inline UnknownAHContainer::UnknownAHContainer(const vtkm::cont::ArrayHandle(array)) , ValueType(typeid(T)) , StorageType(typeid(S)) - , BaseComponentType(typeid(typename vtkm::VecTraits::BaseComponentType)) + , BaseComponentType( + UnknownAHComponentInfo::Make::BaseComponentType>()) , DeleteFunction(detail::UnknownAHDelete) , NewInstance(detail::UnknownADNewInstance) , NewInstanceBasic(detail::UnknownADNewInstanceBasic) @@ -311,7 +349,7 @@ class VTKM_CONT_EXPORT UnknownArrayHandle VTKM_CONT bool IsValueTypeImpl(std::type_index type) const; VTKM_CONT bool IsStorageTypeImpl(std::type_index type) const; - VTKM_CONT bool IsBaseComponentTypeImpl(std::type_index type) const; + VTKM_CONT bool IsBaseComponentTypeImpl(const detail::UnknownAHComponentInfo& type) const; public: VTKM_CONT UnknownArrayHandle() = default; @@ -387,7 +425,7 @@ public: template VTKM_CONT bool IsBaseComponentType() const { - return this->IsBaseComponentTypeImpl(typeid(BaseComponentType)); + return this->IsBaseComponentTypeImpl(detail::UnknownAHComponentInfo::Make()); } /// Returns true if this array matches the ArrayHandleType template argument. diff --git a/vtkm/testing/Testing.h b/vtkm/testing/Testing.h index 09ca5d442..3beaa69ae 100644 --- a/vtkm/testing/Testing.h +++ b/vtkm/testing/Testing.h @@ -129,6 +129,7 @@ VTK_M_BASIC_TYPE(vtkm::Int64, I64); VTK_M_BASIC_TYPE(vtkm::UInt64, UI64); // types without vtkm::typedefs: +VTK_M_BASIC_TYPE(bool, bool); VTK_M_BASIC_TYPE(char, char); VTK_M_BASIC_TYPE(long, long); VTK_M_BASIC_TYPE(unsigned long, unsigned long); diff --git a/vtkm/testing/UnitTestTypeList.cxx b/vtkm/testing/UnitTestTypeList.cxx index 85afed553..ade19267b 100644 --- a/vtkm/testing/UnitTestTypeList.cxx +++ b/vtkm/testing/UnitTestTypeList.cxx @@ -172,16 +172,31 @@ void TestLists() scalarsAll.AddExpected(vtkm::UInt32()); scalarsAll.AddExpected(vtkm::Int64()); scalarsAll.AddExpected(vtkm::UInt64()); - // Extra types with same layout as above but considered different by C - scalarsAll.AddExpected(char()); - scalarsAll.AddExpected((signed int)0); - scalarsAll.AddExpected((unsigned int)0); - scalarsAll.AddExpected((signed long)0); - scalarsAll.AddExpected((unsigned long)0); - scalarsAll.AddExpected((signed long long)0); - scalarsAll.AddExpected((unsigned long long)0); TryList(scalarsAll, vtkm::TypeListScalarAll()); + std::cout << "TypeListBaseC" << std::endl; + TypeSet baseC; + baseC.AddExpected(vtkm::Float32()); + baseC.AddExpected(vtkm::Float64()); + baseC.AddExpected(vtkm::Int8()); + baseC.AddExpected(vtkm::UInt8()); + baseC.AddExpected(vtkm::Int16()); + baseC.AddExpected(vtkm::UInt16()); + baseC.AddExpected(vtkm::Int32()); + baseC.AddExpected(vtkm::UInt32()); + baseC.AddExpected(vtkm::Int64()); + baseC.AddExpected(vtkm::UInt64()); + // Extra types with same layout as above but considered different by C + baseC.AddExpected(bool()); + baseC.AddExpected(char()); + baseC.AddExpected((signed int)0); + baseC.AddExpected((unsigned int)0); + baseC.AddExpected((signed long)0); + baseC.AddExpected((unsigned long)0); + baseC.AddExpected((signed long long)0); + baseC.AddExpected((unsigned long long)0); + TryList(baseC, vtkm::TypeListBaseC()); + std::cout << "TypeListVecCommon" << std::endl; TypeSet vecCommon; vecCommon.AddExpected(vtkm::Vec2f_32()); @@ -277,14 +292,6 @@ void TestLists() all.AddExpected(vtkm::Vec4ui_16()); all.AddExpected(vtkm::Vec4ui_32()); all.AddExpected(vtkm::Vec4ui_64()); - // Extra types with same layout as above but considered different by C - all.AddExpected(char()); - all.AddExpected((signed int)0); - all.AddExpected((unsigned int)0); - all.AddExpected((signed long)0); - all.AddExpected((unsigned long)0); - all.AddExpected((signed long long)0); - all.AddExpected((unsigned long long)0); TryList(all, vtkm::TypeListAll()); } diff --git a/vtkm/testing/UnitTestTypeListTag.cxx b/vtkm/testing/UnitTestTypeListTag.cxx index cda93d4f9..b442ac593 100644 --- a/vtkm/testing/UnitTestTypeListTag.cxx +++ b/vtkm/testing/UnitTestTypeListTag.cxx @@ -171,16 +171,31 @@ void TestLists() scalarsAll.AddExpected(vtkm::UInt32()); scalarsAll.AddExpected(vtkm::Int64()); scalarsAll.AddExpected(vtkm::UInt64()); - // Extra types with same layout as above but considered different by C - scalarsAll.AddExpected(char()); - scalarsAll.AddExpected((signed int)0); - scalarsAll.AddExpected((unsigned int)0); - scalarsAll.AddExpected((signed long)0); - scalarsAll.AddExpected((unsigned long)0); - scalarsAll.AddExpected((signed long long)0); - scalarsAll.AddExpected((unsigned long long)0); TryList(scalarsAll, vtkm::TypeListTagScalarAll()); + std::cout << "TypeListBaseC" << std::endl; + TypeSet baseC; + baseC.AddExpected(vtkm::Float32()); + baseC.AddExpected(vtkm::Float64()); + baseC.AddExpected(vtkm::Int8()); + baseC.AddExpected(vtkm::UInt8()); + baseC.AddExpected(vtkm::Int16()); + baseC.AddExpected(vtkm::UInt16()); + baseC.AddExpected(vtkm::Int32()); + baseC.AddExpected(vtkm::UInt32()); + baseC.AddExpected(vtkm::Int64()); + baseC.AddExpected(vtkm::UInt64()); + // Extra types with same layout as above but considered different by C + baseC.AddExpected(bool()); + baseC.AddExpected(char()); + baseC.AddExpected((signed int)0); + baseC.AddExpected((unsigned int)0); + baseC.AddExpected((signed long)0); + baseC.AddExpected((unsigned long)0); + baseC.AddExpected((signed long long)0); + baseC.AddExpected((unsigned long long)0); + TryList(baseC, vtkm::TypeListBaseC()); + std::cout << "TypeListTagVecCommon" << std::endl; TypeSet vecCommon; vecCommon.AddExpected(vtkm::Vec2f_32()); @@ -276,14 +291,6 @@ void TestLists() all.AddExpected(vtkm::Vec4ui_16()); all.AddExpected(vtkm::Vec4ui_32()); all.AddExpected(vtkm::Vec4ui_64()); - // Extra types with same layout as above but considered different by C - all.AddExpected(char()); - all.AddExpected((signed int)0); - all.AddExpected((unsigned int)0); - all.AddExpected((signed long)0); - all.AddExpected((unsigned long)0); - all.AddExpected((signed long long)0); - all.AddExpected((unsigned long long)0); TryList(all, vtkm::TypeListTagAll()); }