extract checkUInt64ToIn64Conversion and convertUInt64ToInt64IfPossible to separate functions

This commit is contained in:
chen768959 2023-09-08 15:05:04 +08:00
parent 329c9fce3c
commit 5c2fd38f73
2 changed files with 44 additions and 60 deletions

View File

@ -136,39 +136,17 @@ DataTypePtr FieldToDataType<on_error>::operator() (const Array & x) const
DataTypes element_types;
element_types.reserve(x.size());
auto checkIfConversionSigned = [&](bool& has_signed_int, bool& has_uint64, bool& uint64_could_opposite,
const DataTypePtr & type, const Field & elem)
{
if (uint64_could_opposite)
{
has_signed_int |= WhichDataType(type).isNativeInt();
if (type->getTypeId() == TypeIndex::UInt64)
{
has_uint64 = true;
uint64_could_opposite &= (elem.template get<UInt64>() <= std::numeric_limits<Int64>::max());
}
}
};
bool has_signed_int = false;
bool has_uint64 = false;
bool uint64_could_opposite = true;
bool uint64_convert_possible = true;
for (const Field & elem : x)
{
DataTypePtr type = applyVisitor(*this, elem);
element_types.emplace_back(type);
checkIfConversionSigned(has_signed_int, has_uint64, uint64_could_opposite, type, elem);
checkUInt64ToIn64Conversion(has_signed_int, uint64_convert_possible, type, elem);
}
// Convert the UInt64 type to Int64 in order to cover other signed_integer types
// and obtain the least super type of all ints.
if (has_signed_int && has_uint64 && uint64_could_opposite)
{
for (auto & type : element_types)
if (type->getTypeId() == TypeIndex::UInt64)
type = std::make_shared<DataTypeInt64>();
}
if (has_signed_int && uint64_convert_possible)
convertUInt64ToInt64IfPossible(element_types);
return std::make_shared<DataTypeArray>(getLeastSupertype<on_error>(element_types));
}
@ -196,53 +174,27 @@ DataTypePtr FieldToDataType<on_error>::operator() (const Map & map) const
key_types.reserve(map.size());
value_types.reserve(map.size());
auto checkIfConversionSigned = [&](bool& has_signed_int, bool& has_uint64, bool& uint64_could_opposite,
const DataTypePtr & type, const Field & elem)
{
if (uint64_could_opposite)
{
has_signed_int |= WhichDataType(type).isNativeInt();
if (type->getTypeId() == TypeIndex::UInt64)
{
has_uint64 = true;
uint64_could_opposite &= (elem.template get<UInt64>() <= std::numeric_limits<Int64>::max());
}
}
};
auto updateUInt64Types = [](DataTypes types)
{
for (auto& type : types)
if (type->getTypeId() == TypeIndex::UInt64)
type = std::make_shared<DataTypeInt64>();
};
bool k_has_signed_int = false;
bool k_has_uint64 = false;
bool k_uint64_could_opposite = true;
bool k_uint64_convert_possible = true;
bool v_has_signed_int = false;
bool v_has_uint64 = false;
bool v_uint64_could_opposite = true;
bool v_uint64_convert_possible = true;
for (const auto & elem : map)
{
const auto & tuple = elem.safeGet<const Tuple &>();
assert(tuple.size() == 2);
DataTypePtr k_type = applyVisitor(*this, tuple[0]);
key_types.push_back(k_type);
checkIfConversionSigned(k_has_signed_int, k_has_uint64, k_uint64_could_opposite, k_type, tuple[0]);
checkUInt64ToIn64Conversion(k_has_signed_int, k_uint64_convert_possible, k_type, tuple[0]);
DataTypePtr v_type = applyVisitor(*this, tuple[1]);
value_types.push_back(v_type);
checkIfConversionSigned(v_has_signed_int, v_has_uint64, v_uint64_could_opposite, v_type, tuple[1]);
checkUInt64ToIn64Conversion(v_has_signed_int, v_uint64_convert_possible, v_type, tuple[1]);
}
// Convert the UInt64 type to Int64 in order to cover other signed_integer types
// and obtain the least super type of all ints.
if (k_has_signed_int && k_has_uint64 && k_uint64_could_opposite)
updateUInt64Types(key_types);
if (k_has_signed_int && k_uint64_convert_possible)
convertUInt64ToInt64IfPossible(key_types);
if (v_has_signed_int && v_has_uint64 && v_uint64_could_opposite)
updateUInt64Types(value_types);
if (v_has_signed_int && v_uint64_convert_possible)
convertUInt64ToInt64IfPossible(value_types);
return std::make_shared<DataTypeMap>(
getLeastSupertype<on_error>(key_types),
@ -275,6 +227,28 @@ DataTypePtr FieldToDataType<on_error>::operator()(const bool &) const
return DataTypeFactory::instance().get("Bool");
}
template <LeastSupertypeOnError on_error>
void FieldToDataType<on_error>::checkUInt64ToIn64Conversion(bool & has_signed_int, bool & uint64_convert_possible, const DataTypePtr & type, const Field & elem) const
{
if (uint64_convert_possible)
{
bool is_native_int = WhichDataType(type).isNativeInt();
if (is_native_int)
has_signed_int |= is_native_int;
else if (type->getTypeId() == TypeIndex::UInt64)
uint64_convert_possible &= (elem.template get<UInt64>() <= std::numeric_limits<Int64>::max());
}
}
template <LeastSupertypeOnError on_error>
void FieldToDataType<on_error>::convertUInt64ToInt64IfPossible(DataTypes & data_types) const
{
for (auto& type : data_types)
if (type->getTypeId() == TypeIndex::UInt64)
type = std::make_shared<DataTypeInt64>();
}
template class FieldToDataType<LeastSupertypeOnError::Throw>;
template class FieldToDataType<LeastSupertypeOnError::String>;
template class FieldToDataType<LeastSupertypeOnError::Null>;

View File

@ -45,6 +45,16 @@ public:
DataTypePtr operator() (const UInt256 & x) const;
DataTypePtr operator() (const Int256 & x) const;
DataTypePtr operator() (const bool & x) const;
private:
// The conditions for converting UInt64 to Int64 are:
// 1. The existence of Int.
// 2. The existence of UInt64, and the UInt64 value must be <= Int64.max.
void checkUInt64ToIn64Conversion(bool& has_signed_int, bool& uint64_convert_possible, const DataTypePtr & type, const Field & elem) const;
// Convert the UInt64 type to Int64 in order to cover other signed_integer types
// and obtain the least super type of all ints.
void convertUInt64ToInt64IfPossible(DataTypes & data_types) const;
};
}