Simplification #1416

This commit is contained in:
Alexey Milovidov 2017-12-25 08:48:53 +03:00
parent d899d3f8f5
commit 9b914cf93e

View File

@ -20,11 +20,9 @@ namespace ErrorCodes
}
/** Functions are logical links: and, or, not, xor.
* Accept any numeric types, return a UInt8 containing 0 or 1.
/** Return an UInt8 containing 0 or 1.
*/
template <typename B>
struct AndImpl
{
static inline bool isSaturable()
@ -37,13 +35,12 @@ struct AndImpl
return !a;
}
static inline UInt8 apply(UInt8 a, B b)
static inline UInt8 apply(UInt8 a, UInt8 b)
{
return a && b;
}
};
template <typename B>
struct OrImpl
{
static inline bool isSaturable()
@ -56,13 +53,12 @@ struct OrImpl
return a;
}
static inline UInt8 apply(UInt8 a, B b)
static inline UInt8 apply(UInt8 a, UInt8 b)
{
return a || b;
}
};
template <typename B>
struct XorImpl
{
static inline bool isSaturable()
@ -75,7 +71,7 @@ struct XorImpl
return false;
}
static inline UInt8 apply(UInt8 a, B b)
static inline UInt8 apply(UInt8 a, UInt8 b)
{
return (!a) != (!b);
}
@ -161,7 +157,7 @@ struct AssociativeOperationImpl<Op, 1>
};
template <template <typename> class Impl, typename Name>
template <typename Impl, typename Name>
class FunctionAnyArityLogical : public IFunction
{
public:
@ -179,7 +175,7 @@ private:
UInt8 x = !!in[i]->getUInt(0);
if (has_res)
{
res = Impl<UInt8>::apply(res, x);
res = Impl::apply(res, x);
}
else
{
@ -221,33 +217,6 @@ private:
throw Exception("Unexpected type of column: " + column->getName(), ErrorCodes::ILLEGAL_COLUMN);
}
template <typename T>
bool executeUInt8Type(const UInt8Container & uint8_vec, const IColumn * column, UInt8Container & res)
{
auto col = checkAndGetColumn<ColumnVector<T>>(column);
if (!col)
return false;
const typename ColumnVector<T>::Container & other_vec = col->getData();
size_t n = res.size();
for (size_t i = 0; i < n; ++i)
res[i] = Impl<T>::apply(uint8_vec[i], other_vec[i]);
return true;
}
void executeUInt8Other(const UInt8Container & uint8_vec, const IColumn * column, UInt8Container & res)
{
if (!executeUInt8Type<Int8 >(uint8_vec, column, res) &&
!executeUInt8Type<Int16>(uint8_vec, column, res) &&
!executeUInt8Type<Int32>(uint8_vec, column, res) &&
!executeUInt8Type<Int64>(uint8_vec, column, res) &&
!executeUInt8Type<UInt16>(uint8_vec, column, res) &&
!executeUInt8Type<UInt32>(uint8_vec, column, res) &&
!executeUInt8Type<UInt64>(uint8_vec, column, res) &&
!executeUInt8Type<Float32>(uint8_vec, column, res) &&
!executeUInt8Type<Float64>(uint8_vec, column, res))
throw Exception("Unexpected type of column: " + column->getName(), ErrorCodes::ILLEGAL_COLUMN);
}
public:
String getName() const override
{
@ -289,16 +258,16 @@ public:
bool has_consts = extractConstColumns(in, const_val);
// If this value uniquely determines the result, return it.
if (has_consts && (in.empty() || Impl<UInt8>::apply(const_val, 0) == Impl<UInt8>::apply(const_val, 1)))
if (has_consts && (in.empty() || Impl::apply(const_val, 0) == Impl::apply(const_val, 1)))
{
if (!in.empty())
const_val = Impl<UInt8>::apply(const_val, 0);
const_val = Impl::apply(const_val, 0);
block.getByPosition(result).column = DataTypeUInt8().createColumnConst(rows, toField(const_val));
return;
}
/// If this value is a neutral element, let's forget about it.
if (has_consts && Impl<UInt8>::apply(const_val, 0) == 0 && Impl<UInt8>::apply(const_val, 1) == 1)
if (has_consts && Impl::apply(const_val, 0) == 0 && Impl::apply(const_val, 1) == 1)
has_consts = false;
auto col_res = ColumnUInt8::create();
@ -314,27 +283,21 @@ public:
vec_res.resize(rows);
}
/// Divide the input columns into UInt8 and the rest. The first will be processed more efficiently.
/// col_res at each moment will either be at the end of uint8_in, or not contained in uint8_in.
/// Convert all columns to UInt8
UInt8ColumnPtrs uint8_in;
ColumnRawPtrs other_in;
Columns converted_columns;
for (const IColumn * column : in)
{
if (auto uint8_column = typeid_cast<const ColumnUInt8 *>(column))
if (auto uint8_column = checkAndGetColumn<ColumnUInt8>(column))
uint8_in.push_back(uint8_column);
else
other_in.push_back(column);
}
/// You need at least one column in uint8_in, so that you can combine columns from other_in.
if (uint8_in.empty())
{
if (other_in.empty())
throw Exception("Logical error in FunctionAnyArityLogical: other_in is empty", ErrorCodes::LOGICAL_ERROR);
convertToUInt8(other_in.back(), vec_res);
other_in.pop_back();
uint8_in.push_back(col_res.get());
{
auto converted_column = ColumnUInt8::create(rows);
convertToUInt8(column, converted_column->getData());
uint8_in.push_back(converted_column.get());
converted_columns.emplace_back(std::move(converted_column));
}
}
/// Effeciently combine all the columns of the correct type.
@ -342,18 +305,10 @@ public:
{
/// With a large block size, combining 6 columns per pass is the fastest.
/// When small - more, is faster.
AssociativeOperationImpl<Impl<UInt8>, 10>::execute(uint8_in, vec_res);
AssociativeOperationImpl<Impl, 10>::execute(uint8_in, vec_res);
uint8_in.push_back(col_res.get());
}
/// Add all the columns of the wrong type one at a time.
while (!other_in.empty())
{
executeUInt8Other(uint8_in[0]->getData(), other_in.back(), vec_res);
other_in.pop_back();
uint8_in[0] = col_res.get();
}
/// This is possible if there is exactly one non-constant among the arguments, and it is of type UInt8.
if (uint8_in[0] != col_res.get())
vec_res.assign(uint8_in[0]->getData());