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.
This commit is contained in:
Kenneth Moreland 2021-01-04 16:36:03 -07:00
parent de55494c81
commit 97324e75cd
6 changed files with 121 additions and 44 deletions

@ -86,7 +86,12 @@ using TypeListField = vtkm::List<vtkm::Float32,
vtkm::Vec4f_64>;
/// 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::Int8,
vtkm::UInt8,
@ -97,12 +102,16 @@ using TypeListScalarAll = vtkm::List<vtkm::Int8,
vtkm::Int64,
vtkm::UInt64,
vtkm::Float32,
vtkm::Float64,
// Other base C types that are the same as above but
// recognized as different by the compiler
char,
signed VTKM_UNUSED_INT_TYPE,
unsigned VTKM_UNUSED_INT_TYPE>;
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<bool, char, signed VTKM_UNUSED_INT_TYPE, unsigned VTKM_UNUSED_INT_TYPE>>;
/// A list of the most commonly use Vec classes. Specifically, these are
/// vectors of size 2, 3, or 4 containing either unsigned bytes, signed

@ -59,6 +59,20 @@ std::shared_ptr<UnknownAHContainer> 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)
{

@ -142,13 +142,50 @@ struct MakeUnknownAHContainerFunctor
std::shared_ptr<UnknownAHContainer> operator()(const vtkm::cont::ArrayHandle<T, S>& 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 <typename T>
static UnknownAHComponentInfo Make()
{
return UnknownAHComponentInfo{ typeid(T),
std::is_integral<T>::value,
std::is_floating_point<T>::value,
std::is_signed<T>::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<T, S
: ArrayHandlePointer(new vtkm::cont::ArrayHandle<T, S>(array))
, ValueType(typeid(T))
, StorageType(typeid(S))
, BaseComponentType(typeid(typename vtkm::VecTraits<T>::BaseComponentType))
, BaseComponentType(
UnknownAHComponentInfo::Make<typename vtkm::VecTraits<T>::BaseComponentType>())
, DeleteFunction(detail::UnknownAHDelete<T, S>)
, NewInstance(detail::UnknownADNewInstance<T, S>)
, NewInstanceBasic(detail::UnknownADNewInstanceBasic<T>)
@ -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 <typename BaseComponentType>
VTKM_CONT bool IsBaseComponentType() const
{
return this->IsBaseComponentTypeImpl(typeid(BaseComponentType));
return this->IsBaseComponentTypeImpl(detail::UnknownAHComponentInfo::Make<BaseComponentType>());
}
/// Returns true if this array matches the ArrayHandleType template argument.

@ -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);

@ -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());
}

@ -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());
}