2018-11-16 12:22:51 +00:00
|
|
|
#include "ColumnVector.h"
|
|
|
|
|
2021-02-12 00:25:00 +00:00
|
|
|
#include <Columns/ColumnCompressed.h>
|
2023-12-29 14:57:36 +00:00
|
|
|
#include <Columns/ColumnsCommon.h>
|
2024-01-22 13:41:58 +00:00
|
|
|
#include <Columns/ColumnConst.h>
|
2021-04-27 12:49:58 +00:00
|
|
|
#include <Columns/MaskOperations.h>
|
2023-10-18 10:21:43 +00:00
|
|
|
#include <Columns/RadixSortHelper.h>
|
2020-11-13 11:28:18 +00:00
|
|
|
#include <IO/WriteHelpers.h>
|
2023-12-29 14:57:36 +00:00
|
|
|
#include <Processors/Transforms/ColumnGathererTransform.h>
|
|
|
|
#include <base/bit_cast.h>
|
|
|
|
#include <base/scope_guard.h>
|
|
|
|
#include <base/sort.h>
|
|
|
|
#include <base/unaligned.h>
|
2017-04-01 09:19:00 +00:00
|
|
|
#include <Common/Arena.h>
|
2020-11-13 11:28:18 +00:00
|
|
|
#include <Common/Exception.h>
|
|
|
|
#include <Common/HashTable/Hash.h>
|
2024-05-26 19:23:17 +00:00
|
|
|
#include <Common/HashTable/StringHashSet.h>
|
2017-04-01 09:19:00 +00:00
|
|
|
#include <Common/NaNUtils.h>
|
2019-02-18 16:29:37 +00:00
|
|
|
#include <Common/RadixSort.h>
|
2020-11-13 11:28:18 +00:00
|
|
|
#include <Common/SipHash.h>
|
2022-10-24 21:11:46 +00:00
|
|
|
#include <Common/TargetSpecific.h>
|
2023-12-29 14:57:36 +00:00
|
|
|
#include <Common/WeakHash.h>
|
2020-11-13 11:28:18 +00:00
|
|
|
#include <Common/assert_cast.h>
|
2024-01-17 14:51:21 +00:00
|
|
|
#include <Common/findExtreme.h>
|
2023-12-29 14:57:36 +00:00
|
|
|
#include <Common/iota.h>
|
2017-03-11 01:29:45 +00:00
|
|
|
|
2022-10-24 21:11:46 +00:00
|
|
|
#include <bit>
|
2020-11-13 11:28:18 +00:00
|
|
|
#include <cmath>
|
|
|
|
#include <cstring>
|
|
|
|
|
|
|
|
#if defined(__SSE2__)
|
|
|
|
# include <emmintrin.h>
|
2017-03-11 01:12:51 +00:00
|
|
|
#endif
|
|
|
|
|
2022-10-24 21:11:46 +00:00
|
|
|
#if USE_MULTITARGET_CODE
|
|
|
|
# include <immintrin.h>
|
|
|
|
#endif
|
|
|
|
|
2022-02-09 16:32:52 +00:00
|
|
|
#if USE_EMBEDDED_COMPILER
|
|
|
|
#include <DataTypes/Native.h>
|
|
|
|
#include <llvm/IR/IRBuilder.h>
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
2017-03-11 01:12:51 +00:00
|
|
|
namespace DB
|
|
|
|
{
|
|
|
|
|
|
|
|
namespace ErrorCodes
|
|
|
|
{
|
|
|
|
extern const int PARAMETER_OUT_OF_BOUND;
|
|
|
|
extern const int SIZES_OF_COLUMNS_DOESNT_MATCH;
|
2020-03-19 17:35:08 +00:00
|
|
|
extern const int LOGICAL_ERROR;
|
2021-05-03 23:46:11 +00:00
|
|
|
extern const int NOT_IMPLEMENTED;
|
2017-03-11 01:12:51 +00:00
|
|
|
}
|
|
|
|
|
2018-08-07 13:57:28 +00:00
|
|
|
template <typename T>
|
|
|
|
const char * ColumnVector<T>::deserializeAndInsertFromArena(const char * pos)
|
2017-03-11 01:12:51 +00:00
|
|
|
{
|
2021-01-26 18:22:40 +00:00
|
|
|
data.emplace_back(unalignedLoad<T>(pos));
|
|
|
|
return pos + sizeof(T);
|
2017-03-11 01:12:51 +00:00
|
|
|
}
|
|
|
|
|
2021-02-16 21:26:06 +00:00
|
|
|
template <typename T>
|
|
|
|
const char * ColumnVector<T>::skipSerializedInArena(const char * pos) const
|
|
|
|
{
|
|
|
|
return pos + sizeof(T);
|
|
|
|
}
|
|
|
|
|
2018-08-07 13:57:28 +00:00
|
|
|
template <typename T>
|
|
|
|
void ColumnVector<T>::updateHashWithValue(size_t n, SipHash & hash) const
|
2017-03-11 01:12:51 +00:00
|
|
|
{
|
2018-03-03 15:36:20 +00:00
|
|
|
hash.update(data[n]);
|
2017-03-11 01:12:51 +00:00
|
|
|
}
|
|
|
|
|
2020-03-13 17:31:50 +00:00
|
|
|
template <typename T>
|
|
|
|
void ColumnVector<T>::updateWeakHash32(WeakHash32 & hash) const
|
|
|
|
{
|
|
|
|
auto s = data.size();
|
|
|
|
|
|
|
|
if (hash.getData().size() != s)
|
2023-01-23 21:13:58 +00:00
|
|
|
throw Exception(ErrorCodes::LOGICAL_ERROR, "Size of WeakHash32 does not match size of column: "
|
|
|
|
"column size is {}, hash size is {}", std::to_string(s), std::to_string(hash.getData().size()));
|
2020-03-13 17:31:50 +00:00
|
|
|
|
2020-03-25 11:14:11 +00:00
|
|
|
const T * begin = data.data();
|
2020-03-13 17:31:50 +00:00
|
|
|
const T * end = begin + s;
|
2020-03-25 11:14:11 +00:00
|
|
|
UInt32 * hash_data = hash.getData().data();
|
2020-03-13 17:31:50 +00:00
|
|
|
|
|
|
|
while (begin < end)
|
|
|
|
{
|
2022-10-21 20:21:17 +00:00
|
|
|
*hash_data = static_cast<UInt32>(hashCRC32(*begin, *hash_data));
|
2020-03-13 17:31:50 +00:00
|
|
|
++begin;
|
|
|
|
++hash_data;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-05-20 22:16:08 +00:00
|
|
|
template <typename T>
|
|
|
|
void ColumnVector<T>::updateHashFast(SipHash & hash) const
|
|
|
|
{
|
|
|
|
hash.update(reinterpret_cast<const char *>(data.data()), size() * sizeof(data[0]));
|
|
|
|
}
|
|
|
|
|
2018-08-07 13:57:28 +00:00
|
|
|
template <typename T>
|
|
|
|
struct ColumnVector<T>::less
|
2017-03-11 01:12:51 +00:00
|
|
|
{
|
|
|
|
const Self & parent;
|
2017-03-12 12:56:59 +00:00
|
|
|
int nan_direction_hint;
|
|
|
|
less(const Self & parent_, int nan_direction_hint_) : parent(parent_), nan_direction_hint(nan_direction_hint_) {}
|
|
|
|
bool operator()(size_t lhs, size_t rhs) const { return CompareHelper<T>::less(parent.data[lhs], parent.data[rhs], nan_direction_hint); }
|
2017-03-11 01:12:51 +00:00
|
|
|
};
|
|
|
|
|
2022-02-23 17:34:19 +00:00
|
|
|
template <typename T>
|
|
|
|
struct ColumnVector<T>::less_stable
|
|
|
|
{
|
|
|
|
const Self & parent;
|
|
|
|
int nan_direction_hint;
|
|
|
|
less_stable(const Self & parent_, int nan_direction_hint_) : parent(parent_), nan_direction_hint(nan_direction_hint_) {}
|
|
|
|
bool operator()(size_t lhs, size_t rhs) const
|
|
|
|
{
|
2022-02-25 19:55:34 +00:00
|
|
|
if (unlikely(parent.data[lhs] == parent.data[rhs]))
|
2022-02-23 17:34:19 +00:00
|
|
|
return lhs < rhs;
|
|
|
|
|
2022-03-03 13:02:31 +00:00
|
|
|
if constexpr (std::is_floating_point_v<T>)
|
|
|
|
{
|
2022-03-12 18:04:08 +00:00
|
|
|
if (unlikely(std::isnan(parent.data[lhs]) && std::isnan(parent.data[rhs])))
|
|
|
|
{
|
2022-03-03 13:02:31 +00:00
|
|
|
return lhs < rhs;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-02-23 17:34:19 +00:00
|
|
|
return CompareHelper<T>::less(parent.data[lhs], parent.data[rhs], nan_direction_hint);
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2018-08-07 13:57:28 +00:00
|
|
|
template <typename T>
|
|
|
|
struct ColumnVector<T>::greater
|
2017-03-11 01:12:51 +00:00
|
|
|
{
|
|
|
|
const Self & parent;
|
2017-03-12 12:56:59 +00:00
|
|
|
int nan_direction_hint;
|
|
|
|
greater(const Self & parent_, int nan_direction_hint_) : parent(parent_), nan_direction_hint(nan_direction_hint_) {}
|
|
|
|
bool operator()(size_t lhs, size_t rhs) const { return CompareHelper<T>::greater(parent.data[lhs], parent.data[rhs], nan_direction_hint); }
|
2017-03-11 01:12:51 +00:00
|
|
|
};
|
|
|
|
|
2022-02-23 17:34:19 +00:00
|
|
|
template <typename T>
|
|
|
|
struct ColumnVector<T>::greater_stable
|
|
|
|
{
|
|
|
|
const Self & parent;
|
|
|
|
int nan_direction_hint;
|
|
|
|
greater_stable(const Self & parent_, int nan_direction_hint_) : parent(parent_), nan_direction_hint(nan_direction_hint_) {}
|
|
|
|
bool operator()(size_t lhs, size_t rhs) const
|
|
|
|
{
|
2022-02-25 19:55:34 +00:00
|
|
|
if (unlikely(parent.data[lhs] == parent.data[rhs]))
|
2022-02-23 17:34:19 +00:00
|
|
|
return lhs < rhs;
|
|
|
|
|
2022-03-03 13:02:31 +00:00
|
|
|
if constexpr (std::is_floating_point_v<T>)
|
|
|
|
{
|
2022-03-12 18:04:08 +00:00
|
|
|
if (unlikely(std::isnan(parent.data[lhs]) && std::isnan(parent.data[rhs])))
|
|
|
|
{
|
2022-03-03 13:02:31 +00:00
|
|
|
return lhs < rhs;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-02-23 17:34:19 +00:00
|
|
|
return CompareHelper<T>::greater(parent.data[lhs], parent.data[rhs], nan_direction_hint);
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2021-09-30 20:42:50 +00:00
|
|
|
template <typename T>
|
|
|
|
struct ColumnVector<T>::equals
|
|
|
|
{
|
|
|
|
const Self & parent;
|
|
|
|
int nan_direction_hint;
|
|
|
|
equals(const Self & parent_, int nan_direction_hint_) : parent(parent_), nan_direction_hint(nan_direction_hint_) {}
|
|
|
|
bool operator()(size_t lhs, size_t rhs) const { return CompareHelper<T>::equals(parent.data[lhs], parent.data[rhs], nan_direction_hint); }
|
|
|
|
};
|
|
|
|
|
2022-02-09 16:32:52 +00:00
|
|
|
#if USE_EMBEDDED_COMPILER
|
|
|
|
|
|
|
|
template <typename T>
|
|
|
|
bool ColumnVector<T>::isComparatorCompilable() const
|
|
|
|
{
|
|
|
|
/// TODO: for std::is_floating_point_v<T> we need implement is_nan in LLVM IR.
|
2022-02-17 19:29:21 +00:00
|
|
|
return std::is_integral_v<T>;
|
2022-02-09 16:32:52 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
template <typename T>
|
|
|
|
llvm::Value * ColumnVector<T>::compileComparator(llvm::IRBuilderBase & builder, llvm::Value * lhs, llvm::Value * rhs, llvm::Value *) const
|
|
|
|
{
|
|
|
|
llvm::IRBuilder<> & b = static_cast<llvm::IRBuilder<> &>(builder);
|
|
|
|
|
2022-05-11 13:35:37 +00:00
|
|
|
if constexpr (std::is_integral_v<T>)
|
2022-02-09 16:32:52 +00:00
|
|
|
{
|
|
|
|
// a > b ? 1 : (a < b ? -1 : 0);
|
|
|
|
|
|
|
|
bool is_signed = std::is_signed_v<T>;
|
|
|
|
|
|
|
|
auto * lhs_greater_than_rhs_result = llvm::ConstantInt::getSigned(b.getInt8Ty(), 1);
|
|
|
|
auto * lhs_less_than_rhs_result = llvm::ConstantInt::getSigned(b.getInt8Ty(), -1);
|
|
|
|
auto * lhs_equals_rhs_result = llvm::ConstantInt::getSigned(b.getInt8Ty(), 0);
|
|
|
|
|
|
|
|
auto * lhs_greater_than_rhs = is_signed ? b.CreateICmpSGT(lhs, rhs) : b.CreateICmpUGT(lhs, rhs);
|
|
|
|
auto * lhs_less_than_rhs = is_signed ? b.CreateICmpSLT(lhs, rhs) : b.CreateICmpULT(lhs, rhs);
|
|
|
|
auto * if_lhs_less_than_rhs_result = b.CreateSelect(lhs_less_than_rhs, lhs_less_than_rhs_result, lhs_equals_rhs_result);
|
|
|
|
|
|
|
|
return b.CreateSelect(lhs_greater_than_rhs, lhs_greater_than_rhs_result, if_lhs_less_than_rhs_result);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
throw Exception(ErrorCodes::LOGICAL_ERROR, "Method compileComparator is not supported for type {}", TypeName<T>);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#endif
|
2020-05-18 21:41:23 +00:00
|
|
|
|
2018-08-07 13:57:28 +00:00
|
|
|
template <typename T>
|
2022-02-23 17:34:19 +00:00
|
|
|
void ColumnVector<T>::getPermutation(IColumn::PermutationSortDirection direction, IColumn::PermutationSortStability stability,
|
|
|
|
size_t limit, int nan_direction_hint, IColumn::Permutation & res) const
|
2017-03-11 01:12:51 +00:00
|
|
|
{
|
2023-10-18 10:21:43 +00:00
|
|
|
size_t data_size = data.size();
|
2024-01-27 16:40:11 +00:00
|
|
|
res.resize_exact(data_size);
|
2017-04-01 07:20:54 +00:00
|
|
|
|
2023-10-18 10:21:43 +00:00
|
|
|
if (data_size == 0)
|
2019-04-25 01:16:26 +00:00
|
|
|
return;
|
|
|
|
|
2023-10-18 10:21:43 +00:00
|
|
|
if (limit >= data_size)
|
2017-03-11 01:12:51 +00:00
|
|
|
limit = 0;
|
2017-04-01 07:20:54 +00:00
|
|
|
|
2023-12-29 14:57:36 +00:00
|
|
|
iota(res.data(), data_size, IColumn::Permutation::value_type(0));
|
2023-10-18 10:21:43 +00:00
|
|
|
|
2024-01-17 14:51:21 +00:00
|
|
|
if constexpr (has_find_extreme_implementation<T> && !std::is_floating_point_v<T>)
|
|
|
|
{
|
|
|
|
/// Disabled for:floating point
|
|
|
|
/// * floating point: We don't deal with nan_direction_hint
|
|
|
|
/// * stability::Stable: We might return any value, not the first
|
|
|
|
if ((limit == 1) && (stability == IColumn::PermutationSortStability::Unstable))
|
|
|
|
{
|
|
|
|
std::optional<size_t> index;
|
|
|
|
if (direction == IColumn::PermutationSortDirection::Ascending)
|
|
|
|
index = findExtremeMinIndex(data.data(), 0, data.size());
|
|
|
|
else
|
|
|
|
index = findExtremeMaxIndex(data.data(), 0, data.size());
|
|
|
|
if (index)
|
|
|
|
{
|
|
|
|
res.data()[0] = *index;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-10-18 10:21:43 +00:00
|
|
|
if constexpr (is_arithmetic_v<T> && !is_big_int_v<T>)
|
2023-09-21 11:20:11 +00:00
|
|
|
{
|
2023-10-18 10:21:43 +00:00
|
|
|
if (!limit)
|
2019-02-18 16:29:37 +00:00
|
|
|
{
|
2023-10-18 10:21:43 +00:00
|
|
|
/// A case for radix sort
|
|
|
|
/// LSD RadixSort is stable
|
|
|
|
|
2022-02-23 17:34:19 +00:00
|
|
|
bool reverse = direction == IColumn::PermutationSortDirection::Descending;
|
2022-03-03 13:02:31 +00:00
|
|
|
bool ascending = direction == IColumn::PermutationSortDirection::Ascending;
|
|
|
|
bool sort_is_stable = stability == IColumn::PermutationSortStability::Stable;
|
|
|
|
|
|
|
|
/// TODO: LSD RadixSort is currently not stable if direction is descending, or value is floating point
|
2022-03-11 21:16:25 +00:00
|
|
|
bool use_radix_sort = (sort_is_stable && ascending && !std::is_floating_point_v<T>) || !sort_is_stable;
|
2022-02-23 17:34:19 +00:00
|
|
|
|
2019-04-25 01:16:26 +00:00
|
|
|
/// Thresholds on size. Lower threshold is arbitrary. Upper threshold is chosen by the type for histogram counters.
|
2023-10-18 10:21:43 +00:00
|
|
|
if (data_size >= 256 && data_size <= std::numeric_limits<UInt32>::max() && use_radix_sort)
|
2019-04-25 01:16:26 +00:00
|
|
|
{
|
2023-10-18 10:21:43 +00:00
|
|
|
bool try_sort = false;
|
|
|
|
|
|
|
|
if (direction == IColumn::PermutationSortDirection::Ascending && stability == IColumn::PermutationSortStability::Unstable)
|
|
|
|
try_sort = trySort(res.begin(), res.end(), less(*this, nan_direction_hint));
|
|
|
|
else if (direction == IColumn::PermutationSortDirection::Ascending && stability == IColumn::PermutationSortStability::Stable)
|
|
|
|
try_sort = trySort(res.begin(), res.end(), less_stable(*this, nan_direction_hint));
|
|
|
|
else if (direction == IColumn::PermutationSortDirection::Descending && stability == IColumn::PermutationSortStability::Unstable)
|
|
|
|
try_sort = trySort(res.begin(), res.end(), greater(*this, nan_direction_hint));
|
|
|
|
else
|
|
|
|
try_sort = trySort(res.begin(), res.end(), greater_stable(*this, nan_direction_hint));
|
|
|
|
|
|
|
|
if (try_sort)
|
|
|
|
return;
|
|
|
|
|
|
|
|
PaddedPODArray<ValueWithIndex<T>> pairs(data_size);
|
|
|
|
for (UInt32 i = 0; i < static_cast<UInt32>(data_size); ++i)
|
2019-04-25 01:16:26 +00:00
|
|
|
pairs[i] = {data[i], i};
|
|
|
|
|
2023-10-18 10:21:43 +00:00
|
|
|
RadixSort<RadixSortTraits<T>>::executeLSD(pairs.data(), data_size, reverse, res.data());
|
2019-04-25 01:16:26 +00:00
|
|
|
|
|
|
|
/// Radix sort treats all NaNs to be greater than all numbers.
|
|
|
|
/// If the user needs the opposite, we must move them accordingly.
|
|
|
|
if (std::is_floating_point_v<T> && nan_direction_hint < 0)
|
|
|
|
{
|
2020-05-18 13:13:59 +00:00
|
|
|
size_t nans_to_move = 0;
|
|
|
|
|
2023-10-18 10:21:43 +00:00
|
|
|
for (size_t i = 0; i < data_size; ++i)
|
2019-04-25 01:16:26 +00:00
|
|
|
{
|
2023-10-18 10:21:43 +00:00
|
|
|
if (isNaN(data[res[reverse ? i : data_size - 1 - i]]))
|
2019-04-25 01:16:26 +00:00
|
|
|
++nans_to_move;
|
|
|
|
else
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (nans_to_move)
|
|
|
|
{
|
2023-10-18 10:21:43 +00:00
|
|
|
std::rotate(std::begin(res), std::begin(res) + (reverse ? nans_to_move : data_size - nans_to_move), std::end(res));
|
2019-04-25 01:16:26 +00:00
|
|
|
}
|
|
|
|
}
|
2023-10-18 10:21:43 +00:00
|
|
|
|
2019-04-25 01:16:26 +00:00
|
|
|
return;
|
|
|
|
}
|
2019-02-18 16:29:37 +00:00
|
|
|
}
|
2023-10-16 16:07:11 +00:00
|
|
|
}
|
2023-10-18 10:21:43 +00:00
|
|
|
|
|
|
|
if (direction == IColumn::PermutationSortDirection::Ascending && stability == IColumn::PermutationSortStability::Unstable)
|
|
|
|
this->getPermutationImpl(limit, res, less(*this, nan_direction_hint), DefaultSort(), DefaultPartialSort());
|
|
|
|
else if (direction == IColumn::PermutationSortDirection::Ascending && stability == IColumn::PermutationSortStability::Stable)
|
|
|
|
this->getPermutationImpl(limit, res, less_stable(*this, nan_direction_hint), DefaultSort(), DefaultPartialSort());
|
|
|
|
else if (direction == IColumn::PermutationSortDirection::Descending && stability == IColumn::PermutationSortStability::Unstable)
|
|
|
|
this->getPermutationImpl(limit, res, greater(*this, nan_direction_hint), DefaultSort(), DefaultPartialSort());
|
|
|
|
else
|
|
|
|
this->getPermutationImpl(limit, res, greater_stable(*this, nan_direction_hint), DefaultSort(), DefaultPartialSort());
|
2017-03-11 01:12:51 +00:00
|
|
|
}
|
|
|
|
|
2020-05-12 00:58:58 +00:00
|
|
|
template <typename T>
|
2022-02-23 17:34:19 +00:00
|
|
|
void ColumnVector<T>::updatePermutation(IColumn::PermutationSortDirection direction, IColumn::PermutationSortStability stability,
|
|
|
|
size_t limit, int nan_direction_hint, IColumn::Permutation & res, EqualRanges & equal_ranges) const
|
2020-05-12 00:58:58 +00:00
|
|
|
{
|
2022-03-30 14:03:36 +00:00
|
|
|
auto sort = [&](auto begin, auto end, auto pred)
|
|
|
|
{
|
2023-10-18 10:21:43 +00:00
|
|
|
bool reverse = direction == IColumn::PermutationSortDirection::Descending;
|
|
|
|
bool ascending = direction == IColumn::PermutationSortDirection::Ascending;
|
|
|
|
bool sort_is_stable = stability == IColumn::PermutationSortStability::Stable;
|
|
|
|
|
2022-03-30 14:03:36 +00:00
|
|
|
/// A case for radix sort
|
|
|
|
if constexpr (is_arithmetic_v<T> && !is_big_int_v<T>)
|
|
|
|
{
|
|
|
|
/// TODO: LSD RadixSort is currently not stable if direction is descending, or value is floating point
|
|
|
|
bool use_radix_sort = (sort_is_stable && ascending && !std::is_floating_point_v<T>) || !sort_is_stable;
|
|
|
|
size_t size = end - begin;
|
|
|
|
|
|
|
|
/// Thresholds on size. Lower threshold is arbitrary. Upper threshold is chosen by the type for histogram counters.
|
|
|
|
if (size >= 256 && size <= std::numeric_limits<UInt32>::max() && use_radix_sort)
|
|
|
|
{
|
2023-10-18 10:21:43 +00:00
|
|
|
bool try_sort = trySort(begin, end, pred);
|
|
|
|
if (try_sort)
|
|
|
|
return;
|
|
|
|
|
2022-03-30 14:03:36 +00:00
|
|
|
PaddedPODArray<ValueWithIndex<T>> pairs(size);
|
|
|
|
size_t index = 0;
|
|
|
|
|
2022-06-15 15:21:05 +00:00
|
|
|
for (auto * it = begin; it != end; ++it)
|
2022-03-30 14:03:36 +00:00
|
|
|
{
|
|
|
|
pairs[index] = {data[*it], static_cast<UInt32>(*it)};
|
|
|
|
++index;
|
|
|
|
}
|
|
|
|
|
|
|
|
RadixSort<RadixSortTraits<T>>::executeLSD(pairs.data(), size, reverse, begin);
|
|
|
|
|
|
|
|
/// Radix sort treats all NaNs to be greater than all numbers.
|
|
|
|
/// If the user needs the opposite, we must move them accordingly.
|
|
|
|
if (std::is_floating_point_v<T> && nan_direction_hint < 0)
|
|
|
|
{
|
|
|
|
size_t nans_to_move = 0;
|
|
|
|
|
|
|
|
for (size_t i = 0; i < size; ++i)
|
|
|
|
{
|
|
|
|
if (isNaN(data[begin[reverse ? i : size - 1 - i]]))
|
|
|
|
++nans_to_move;
|
|
|
|
else
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (nans_to_move)
|
|
|
|
{
|
|
|
|
std::rotate(begin, begin + (reverse ? nans_to_move : size - nans_to_move), end);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
::sort(begin, end, pred);
|
|
|
|
};
|
2021-10-01 16:43:58 +00:00
|
|
|
auto partial_sort = [](auto begin, auto mid, auto end, auto pred) { ::partial_sort(begin, mid, end, pred); };
|
|
|
|
|
2022-02-23 17:34:19 +00:00
|
|
|
if (direction == IColumn::PermutationSortDirection::Ascending && stability == IColumn::PermutationSortStability::Unstable)
|
|
|
|
{
|
2021-10-01 16:43:58 +00:00
|
|
|
this->updatePermutationImpl(
|
2022-02-23 17:34:19 +00:00
|
|
|
limit, res, equal_ranges,
|
|
|
|
less(*this, nan_direction_hint),
|
|
|
|
equals(*this, nan_direction_hint),
|
|
|
|
sort, partial_sort);
|
|
|
|
}
|
|
|
|
else if (direction == IColumn::PermutationSortDirection::Ascending && stability == IColumn::PermutationSortStability::Stable)
|
|
|
|
{
|
2021-10-01 16:43:58 +00:00
|
|
|
this->updatePermutationImpl(
|
2022-02-23 17:34:19 +00:00
|
|
|
limit, res, equal_ranges,
|
|
|
|
less_stable(*this, nan_direction_hint),
|
|
|
|
equals(*this, nan_direction_hint),
|
|
|
|
sort, partial_sort);
|
|
|
|
}
|
|
|
|
else if (direction == IColumn::PermutationSortDirection::Descending && stability == IColumn::PermutationSortStability::Unstable)
|
|
|
|
{
|
|
|
|
this->updatePermutationImpl(
|
|
|
|
limit, res, equal_ranges,
|
2021-10-01 16:43:58 +00:00
|
|
|
greater(*this, nan_direction_hint),
|
|
|
|
equals(*this, nan_direction_hint),
|
|
|
|
sort, partial_sort);
|
2022-02-23 17:34:19 +00:00
|
|
|
}
|
|
|
|
else if (direction == IColumn::PermutationSortDirection::Descending && stability == IColumn::PermutationSortStability::Stable)
|
|
|
|
{
|
2021-10-01 16:43:58 +00:00
|
|
|
this->updatePermutationImpl(
|
2022-02-23 17:34:19 +00:00
|
|
|
limit, res, equal_ranges,
|
|
|
|
greater_stable(*this, nan_direction_hint),
|
2021-10-01 16:43:58 +00:00
|
|
|
equals(*this, nan_direction_hint),
|
|
|
|
sort, partial_sort);
|
2022-02-23 17:34:19 +00:00
|
|
|
}
|
2020-05-12 00:58:58 +00:00
|
|
|
}
|
|
|
|
|
2024-05-26 19:23:17 +00:00
|
|
|
template<typename T>
|
|
|
|
size_t ColumnVector<T>::estimateCardinalityInPermutedRange(const IColumn::Permutation & permutation, const EqualRange & equal_range) const
|
|
|
|
{
|
|
|
|
const size_t range_size = equal_range.size();
|
|
|
|
if (range_size <= 1)
|
|
|
|
return range_size;
|
|
|
|
|
|
|
|
/// TODO use sampling if the range is too large (e.g. 16k elements, but configurable)
|
|
|
|
StringHashSet elements;
|
|
|
|
bool inserted = false;
|
|
|
|
for (size_t i = equal_range.from; i < equal_range.to; ++i)
|
|
|
|
{
|
2024-05-27 09:39:27 +00:00
|
|
|
size_t permuted_i = permutation[i];
|
|
|
|
StringRef value = getDataAt(permuted_i);
|
|
|
|
elements.emplace(value, inserted);
|
2024-05-26 19:23:17 +00:00
|
|
|
}
|
|
|
|
return elements.size();
|
|
|
|
}
|
|
|
|
|
2018-08-07 13:57:28 +00:00
|
|
|
template <typename T>
|
|
|
|
MutableColumnPtr ColumnVector<T>::cloneResized(size_t size) const
|
2017-03-11 01:12:51 +00:00
|
|
|
{
|
2023-09-15 10:30:06 +00:00
|
|
|
auto res = this->create(size);
|
2017-03-11 01:12:51 +00:00
|
|
|
|
|
|
|
if (size > 0)
|
|
|
|
{
|
2017-12-14 03:56:56 +00:00
|
|
|
auto & new_col = static_cast<Self &>(*res);
|
2024-01-27 16:40:11 +00:00
|
|
|
new_col.data.resize_exact(size);
|
2017-03-11 01:12:51 +00:00
|
|
|
|
|
|
|
size_t count = std::min(this->size(), size);
|
2021-01-26 18:22:40 +00:00
|
|
|
memcpy(new_col.data.data(), data.data(), count * sizeof(data[0]));
|
2017-03-11 01:12:51 +00:00
|
|
|
|
2021-01-26 18:22:40 +00:00
|
|
|
if (size > count)
|
2021-05-03 22:46:51 +00:00
|
|
|
memset(static_cast<void *>(&new_col.data[count]), 0, (size - count) * sizeof(ValueType));
|
2017-03-11 01:12:51 +00:00
|
|
|
}
|
|
|
|
|
Get rid of useless std::move to get NRVO
http://eel.is/c++draft/class.copy.elision#:constructor,copy,elision
Some quote:
> Speaking of RVO, return std::move(w); prohibits it. It means "use move constructor or fail to compile", whereas return w; means "use RVO, and if you can't, use move constructor, and if you can't, use copy constructor, and if you can't, fail to compile."
There is one exception to this rule:
```cpp
Block FilterBlockInputStream::removeFilterIfNeed(Block && block)
{
if (block && remove_filter)
block.erase(static_cast<size_t>(filter_column));
return std::move(block);
}
```
because references are not eligible for NRVO, which is another rule "always move rvalue references and forward universal references" that takes precedence.
2018-08-27 14:04:22 +00:00
|
|
|
return res;
|
2017-03-11 01:12:51 +00:00
|
|
|
}
|
|
|
|
|
2018-08-07 13:57:28 +00:00
|
|
|
template <typename T>
|
2021-05-06 22:57:41 +00:00
|
|
|
UInt64 ColumnVector<T>::get64(size_t n [[maybe_unused]]) const
|
2017-03-11 01:12:51 +00:00
|
|
|
{
|
2021-05-09 21:26:34 +00:00
|
|
|
if constexpr (is_arithmetic_v<T>)
|
2021-06-15 19:55:21 +00:00
|
|
|
return bit_cast<UInt64>(data[n]);
|
2021-05-03 22:46:51 +00:00
|
|
|
else
|
2021-05-04 17:26:09 +00:00
|
|
|
throw Exception(ErrorCodes::NOT_IMPLEMENTED, "Cannot get the value of {} as UInt64", TypeName<T>);
|
2017-03-11 01:12:51 +00:00
|
|
|
}
|
|
|
|
|
2019-05-30 21:59:40 +00:00
|
|
|
template <typename T>
|
2021-05-06 22:57:41 +00:00
|
|
|
inline Float64 ColumnVector<T>::getFloat64(size_t n [[maybe_unused]]) const
|
2019-05-30 21:59:40 +00:00
|
|
|
{
|
2021-05-09 21:26:34 +00:00
|
|
|
if constexpr (is_arithmetic_v<T>)
|
2021-05-03 22:46:51 +00:00
|
|
|
return static_cast<Float64>(data[n]);
|
|
|
|
else
|
2021-05-04 17:26:09 +00:00
|
|
|
throw Exception(ErrorCodes::NOT_IMPLEMENTED, "Cannot get the value of {} as Float64", TypeName<T>);
|
2019-05-30 21:59:40 +00:00
|
|
|
}
|
|
|
|
|
2019-12-03 01:55:46 +00:00
|
|
|
template <typename T>
|
2021-05-06 22:57:41 +00:00
|
|
|
Float32 ColumnVector<T>::getFloat32(size_t n [[maybe_unused]]) const
|
2019-12-03 01:55:46 +00:00
|
|
|
{
|
2021-05-09 21:26:34 +00:00
|
|
|
if constexpr (is_arithmetic_v<T>)
|
2021-05-03 22:46:51 +00:00
|
|
|
return static_cast<Float32>(data[n]);
|
|
|
|
else
|
2021-05-04 17:26:09 +00:00
|
|
|
throw Exception(ErrorCodes::NOT_IMPLEMENTED, "Cannot get the value of {} as Float32", TypeName<T>);
|
2019-12-03 01:55:46 +00:00
|
|
|
}
|
|
|
|
|
2024-03-18 18:46:17 +00:00
|
|
|
template <typename T>
|
|
|
|
bool ColumnVector<T>::tryInsert(const DB::Field & x)
|
|
|
|
{
|
|
|
|
NearestFieldType<T> value;
|
|
|
|
if (!x.tryGet<NearestFieldType<T>>(value))
|
|
|
|
{
|
|
|
|
if constexpr (std::is_same_v<T, UInt8>)
|
|
|
|
{
|
|
|
|
/// It's also possible to insert boolean values into UInt8 column.
|
|
|
|
bool boolean_value;
|
|
|
|
if (x.tryGet<bool>(boolean_value))
|
|
|
|
{
|
|
|
|
data.push_back(static_cast<T>(boolean_value));
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
data.push_back(static_cast<T>(value));
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2018-08-07 13:57:28 +00:00
|
|
|
template <typename T>
|
|
|
|
void ColumnVector<T>::insertRangeFrom(const IColumn & src, size_t start, size_t length)
|
2017-03-11 01:12:51 +00:00
|
|
|
{
|
2019-08-21 02:28:04 +00:00
|
|
|
const ColumnVector & src_vec = assert_cast<const ColumnVector &>(src);
|
2017-04-01 07:20:54 +00:00
|
|
|
|
2017-03-11 01:12:51 +00:00
|
|
|
if (start + length > src_vec.data.size())
|
2023-01-23 21:13:58 +00:00
|
|
|
throw Exception(ErrorCodes::PARAMETER_OUT_OF_BOUND,
|
|
|
|
"Parameters start = {}, length = {} are out of bound "
|
|
|
|
"in ColumnVector<T>::insertRangeFrom method (data.size() = {}).",
|
|
|
|
toString(start), toString(length), toString(src_vec.data.size()));
|
2017-04-01 07:20:54 +00:00
|
|
|
|
2017-03-11 01:12:51 +00:00
|
|
|
size_t old_size = data.size();
|
|
|
|
data.resize(old_size + length);
|
2021-01-26 18:22:40 +00:00
|
|
|
memcpy(data.data() + old_size, &src_vec.data[start], length * sizeof(data[0]));
|
2017-03-11 01:12:51 +00:00
|
|
|
}
|
|
|
|
|
2022-10-24 21:11:46 +00:00
|
|
|
static inline UInt64 blsr(UInt64 mask)
|
|
|
|
{
|
|
|
|
#ifdef __BMI__
|
|
|
|
return _blsr_u64(mask);
|
|
|
|
#else
|
|
|
|
return mask & (mask-1);
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
2023-01-23 21:55:52 +00:00
|
|
|
/// If mask is a number of this kind: [0]*[1]* function returns the length of the cluster of 1s.
|
|
|
|
/// Otherwise it returns the special value: 0xFF.
|
|
|
|
uint8_t prefixToCopy(UInt64 mask)
|
|
|
|
{
|
|
|
|
if (mask == 0)
|
|
|
|
return 0;
|
|
|
|
if (mask == static_cast<UInt64>(-1))
|
|
|
|
return 64;
|
|
|
|
/// Row with index 0 correspond to the least significant bit.
|
|
|
|
/// So the length of the prefix to copy is 64 - #(leading zeroes).
|
|
|
|
const UInt64 leading_zeroes = __builtin_clzll(mask);
|
|
|
|
if (mask == ((static_cast<UInt64>(-1) << leading_zeroes) >> leading_zeroes))
|
|
|
|
return 64 - leading_zeroes;
|
|
|
|
else
|
|
|
|
return 0xFF;
|
|
|
|
}
|
|
|
|
|
|
|
|
uint8_t suffixToCopy(UInt64 mask)
|
|
|
|
{
|
|
|
|
const auto prefix_to_copy = prefixToCopy(~mask);
|
|
|
|
return prefix_to_copy >= 64 ? prefix_to_copy : 64 - prefix_to_copy;
|
|
|
|
}
|
|
|
|
|
2022-10-24 21:11:46 +00:00
|
|
|
DECLARE_DEFAULT_CODE(
|
|
|
|
template <typename T, typename Container, size_t SIMD_ELEMENTS>
|
|
|
|
inline void doFilterAligned(const UInt8 *& filt_pos, const UInt8 *& filt_end_aligned, const T *& data_pos, Container & res_data)
|
|
|
|
{
|
|
|
|
while (filt_pos < filt_end_aligned)
|
|
|
|
{
|
|
|
|
UInt64 mask = bytes64MaskToBits64Mask(filt_pos);
|
2023-01-23 21:55:52 +00:00
|
|
|
const uint8_t prefix_to_copy = prefixToCopy(mask);
|
2022-10-24 21:11:46 +00:00
|
|
|
|
2023-01-23 21:55:52 +00:00
|
|
|
if (0xFF != prefix_to_copy)
|
2022-10-24 21:11:46 +00:00
|
|
|
{
|
2023-01-23 21:55:52 +00:00
|
|
|
res_data.insert(data_pos, data_pos + prefix_to_copy);
|
2022-10-24 21:11:46 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2023-01-23 21:55:52 +00:00
|
|
|
const uint8_t suffix_to_copy = suffixToCopy(mask);
|
|
|
|
if (0xFF != suffix_to_copy)
|
|
|
|
{
|
|
|
|
res_data.insert(data_pos + SIMD_ELEMENTS - suffix_to_copy, data_pos + SIMD_ELEMENTS);
|
|
|
|
}
|
|
|
|
else
|
2022-10-24 21:11:46 +00:00
|
|
|
{
|
2023-01-23 21:55:52 +00:00
|
|
|
while (mask)
|
|
|
|
{
|
|
|
|
size_t index = std::countr_zero(mask);
|
|
|
|
res_data.push_back(data_pos[index]);
|
|
|
|
mask = blsr(mask);
|
|
|
|
}
|
2022-10-24 21:11:46 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
filt_pos += SIMD_ELEMENTS;
|
|
|
|
data_pos += SIMD_ELEMENTS;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
)
|
|
|
|
|
|
|
|
namespace
|
|
|
|
{
|
|
|
|
template <typename T, typename Container>
|
|
|
|
void resize(Container & res_data, size_t reserve_size)
|
|
|
|
{
|
|
|
|
#if defined(MEMORY_SANITIZER)
|
|
|
|
res_data.resize_fill(reserve_size, static_cast<T>(0)); // MSan doesn't recognize that all allocated memory is written by AVX-512 intrinsics.
|
|
|
|
#else
|
|
|
|
res_data.resize(reserve_size);
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
DECLARE_AVX512VBMI2_SPECIFIC_CODE(
|
|
|
|
template <size_t ELEMENT_WIDTH>
|
|
|
|
inline void compressStoreAVX512(const void *src, void *dst, const UInt64 mask)
|
|
|
|
{
|
|
|
|
__m512i vsrc = _mm512_loadu_si512(src);
|
|
|
|
if constexpr (ELEMENT_WIDTH == 1)
|
|
|
|
_mm512_mask_compressstoreu_epi8(dst, static_cast<__mmask64>(mask), vsrc);
|
|
|
|
else if constexpr (ELEMENT_WIDTH == 2)
|
|
|
|
_mm512_mask_compressstoreu_epi16(dst, static_cast<__mmask32>(mask), vsrc);
|
|
|
|
else if constexpr (ELEMENT_WIDTH == 4)
|
|
|
|
_mm512_mask_compressstoreu_epi32(dst, static_cast<__mmask16>(mask), vsrc);
|
|
|
|
else if constexpr (ELEMENT_WIDTH == 8)
|
|
|
|
_mm512_mask_compressstoreu_epi64(dst, static_cast<__mmask8>(mask), vsrc);
|
|
|
|
}
|
|
|
|
|
|
|
|
template <typename T, typename Container, size_t SIMD_ELEMENTS>
|
|
|
|
inline void doFilterAligned(const UInt8 *& filt_pos, const UInt8 *& filt_end_aligned, const T *& data_pos, Container & res_data)
|
|
|
|
{
|
|
|
|
static constexpr size_t VEC_LEN = 64; /// AVX512 vector length - 64 bytes
|
|
|
|
static constexpr size_t ELEMENT_WIDTH = sizeof(T);
|
|
|
|
static constexpr size_t ELEMENTS_PER_VEC = VEC_LEN / ELEMENT_WIDTH;
|
|
|
|
static constexpr UInt64 KMASK = 0xffffffffffffffff >> (64 - ELEMENTS_PER_VEC);
|
|
|
|
|
|
|
|
size_t current_offset = res_data.size();
|
|
|
|
size_t reserve_size = res_data.size();
|
|
|
|
size_t alloc_size = SIMD_ELEMENTS * 2;
|
|
|
|
|
|
|
|
while (filt_pos < filt_end_aligned)
|
|
|
|
{
|
|
|
|
/// to avoid calling resize too frequently, resize to reserve buffer.
|
|
|
|
if (reserve_size - current_offset < SIMD_ELEMENTS)
|
|
|
|
{
|
|
|
|
reserve_size += alloc_size;
|
|
|
|
resize<T>(res_data, reserve_size);
|
|
|
|
alloc_size *= 2;
|
|
|
|
}
|
|
|
|
|
|
|
|
UInt64 mask = bytes64MaskToBits64Mask(filt_pos);
|
|
|
|
|
|
|
|
if (0xffffffffffffffff == mask)
|
|
|
|
{
|
|
|
|
for (size_t i = 0; i < SIMD_ELEMENTS; i += ELEMENTS_PER_VEC)
|
|
|
|
_mm512_storeu_si512(reinterpret_cast<void *>(&res_data[current_offset + i]),
|
|
|
|
_mm512_loadu_si512(reinterpret_cast<const void *>(data_pos + i)));
|
|
|
|
current_offset += SIMD_ELEMENTS;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
if (mask)
|
|
|
|
{
|
|
|
|
for (size_t i = 0; i < SIMD_ELEMENTS; i += ELEMENTS_PER_VEC)
|
|
|
|
{
|
|
|
|
compressStoreAVX512<ELEMENT_WIDTH>(reinterpret_cast<const void *>(data_pos + i),
|
|
|
|
reinterpret_cast<void *>(&res_data[current_offset]), mask & KMASK);
|
|
|
|
current_offset += std::popcount(mask & KMASK);
|
|
|
|
/// prepare mask for next iter, if ELEMENTS_PER_VEC = 64, no next iter
|
|
|
|
if (ELEMENTS_PER_VEC < 64)
|
|
|
|
{
|
|
|
|
mask >>= ELEMENTS_PER_VEC;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
filt_pos += SIMD_ELEMENTS;
|
|
|
|
data_pos += SIMD_ELEMENTS;
|
|
|
|
}
|
2024-01-27 16:40:11 +00:00
|
|
|
/// Resize to the real size.
|
|
|
|
res_data.resize_exact(current_offset);
|
2022-10-24 21:11:46 +00:00
|
|
|
}
|
|
|
|
)
|
|
|
|
|
2018-08-07 13:57:28 +00:00
|
|
|
template <typename T>
|
2021-08-10 11:31:15 +00:00
|
|
|
ColumnPtr ColumnVector<T>::filter(const IColumn::Filter & filt, ssize_t result_size_hint) const
|
2017-03-11 01:12:51 +00:00
|
|
|
{
|
|
|
|
size_t size = data.size();
|
|
|
|
if (size != filt.size())
|
2022-03-01 17:20:53 +00:00
|
|
|
throw Exception(ErrorCodes::SIZES_OF_COLUMNS_DOESNT_MATCH, "Size of filter ({}) doesn't match size of column ({})", filt.size(), size);
|
2017-03-11 01:12:51 +00:00
|
|
|
|
2017-12-15 19:46:24 +00:00
|
|
|
auto res = this->create();
|
2017-12-15 21:32:25 +00:00
|
|
|
Container & res_data = res->getData();
|
2017-03-11 01:12:51 +00:00
|
|
|
|
|
|
|
if (result_size_hint)
|
2024-02-16 00:18:19 +00:00
|
|
|
res_data.reserve_exact(result_size_hint > 0 ? result_size_hint : size);
|
2017-03-11 01:12:51 +00:00
|
|
|
|
2021-01-26 18:22:40 +00:00
|
|
|
const UInt8 * filt_pos = filt.data();
|
|
|
|
const UInt8 * filt_end = filt_pos + size;
|
|
|
|
const T * data_pos = data.data();
|
2021-10-25 20:09:09 +00:00
|
|
|
|
2021-10-11 22:34:27 +00:00
|
|
|
/** A slightly more optimized version.
|
2022-05-21 20:35:04 +00:00
|
|
|
* Based on the assumption that often pieces of consecutive values
|
|
|
|
* completely pass or do not pass the filter.
|
2022-10-24 21:11:46 +00:00
|
|
|
* Therefore, we will optimistically check the parts of `SIMD_ELEMENTS` values.
|
2022-05-21 20:35:04 +00:00
|
|
|
*/
|
2022-10-24 21:11:46 +00:00
|
|
|
static constexpr size_t SIMD_ELEMENTS = 64;
|
|
|
|
const UInt8 * filt_end_aligned = filt_pos + size / SIMD_ELEMENTS * SIMD_ELEMENTS;
|
2022-09-25 15:03:52 +00:00
|
|
|
|
2022-10-24 21:11:46 +00:00
|
|
|
#if USE_MULTITARGET_CODE
|
|
|
|
static constexpr bool VBMI2_CAPABLE = sizeof(T) == 1 || sizeof(T) == 2 || sizeof(T) == 4 || sizeof(T) == 8;
|
|
|
|
if (VBMI2_CAPABLE && isArchSupported(TargetArch::AVX512VBMI2))
|
|
|
|
TargetSpecific::AVX512VBMI2::doFilterAligned<T, Container, SIMD_ELEMENTS>(filt_pos, filt_end_aligned, data_pos, res_data);
|
|
|
|
else
|
|
|
|
#endif
|
|
|
|
TargetSpecific::Default::doFilterAligned<T, Container, SIMD_ELEMENTS>(filt_pos, filt_end_aligned, data_pos, res_data);
|
2021-10-11 22:34:27 +00:00
|
|
|
|
2021-01-26 18:22:40 +00:00
|
|
|
while (filt_pos < filt_end)
|
|
|
|
{
|
2021-08-10 11:31:15 +00:00
|
|
|
if (*filt_pos)
|
2021-01-26 18:22:40 +00:00
|
|
|
res_data.push_back(*data_pos);
|
2017-03-11 01:12:51 +00:00
|
|
|
|
2021-01-26 18:22:40 +00:00
|
|
|
++filt_pos;
|
|
|
|
++data_pos;
|
2017-03-11 01:12:51 +00:00
|
|
|
}
|
|
|
|
|
Get rid of useless std::move to get NRVO
http://eel.is/c++draft/class.copy.elision#:constructor,copy,elision
Some quote:
> Speaking of RVO, return std::move(w); prohibits it. It means "use move constructor or fail to compile", whereas return w; means "use RVO, and if you can't, use move constructor, and if you can't, use copy constructor, and if you can't, fail to compile."
There is one exception to this rule:
```cpp
Block FilterBlockInputStream::removeFilterIfNeed(Block && block)
{
if (block && remove_filter)
block.erase(static_cast<size_t>(filter_column));
return std::move(block);
}
```
because references are not eligible for NRVO, which is another rule "always move rvalue references and forward universal references" that takes precedence.
2018-08-27 14:04:22 +00:00
|
|
|
return res;
|
2017-03-11 01:12:51 +00:00
|
|
|
}
|
|
|
|
|
2021-04-27 12:49:58 +00:00
|
|
|
template <typename T>
|
2021-06-07 10:55:55 +00:00
|
|
|
void ColumnVector<T>::expand(const IColumn::Filter & mask, bool inverted)
|
2021-04-27 12:49:58 +00:00
|
|
|
{
|
2021-06-07 10:55:55 +00:00
|
|
|
expandDataByMask<T>(data, mask, inverted);
|
2021-04-27 12:49:58 +00:00
|
|
|
}
|
|
|
|
|
2020-06-23 21:06:32 +00:00
|
|
|
template <typename T>
|
|
|
|
void ColumnVector<T>::applyZeroMap(const IColumn::Filter & filt, bool inverted)
|
|
|
|
{
|
|
|
|
size_t size = data.size();
|
|
|
|
if (size != filt.size())
|
2022-03-01 17:20:53 +00:00
|
|
|
throw Exception(ErrorCodes::SIZES_OF_COLUMNS_DOESNT_MATCH, "Size of filter ({}) doesn't match size of column ({})", filt.size(), size);
|
2020-06-23 21:06:32 +00:00
|
|
|
|
|
|
|
const UInt8 * filt_pos = filt.data();
|
|
|
|
const UInt8 * filt_end = filt_pos + size;
|
|
|
|
T * data_pos = data.data();
|
|
|
|
|
|
|
|
if (inverted)
|
|
|
|
{
|
|
|
|
for (; filt_pos < filt_end; ++filt_pos, ++data_pos)
|
|
|
|
if (!*filt_pos)
|
|
|
|
*data_pos = 0;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
for (; filt_pos < filt_end; ++filt_pos, ++data_pos)
|
|
|
|
if (*filt_pos)
|
|
|
|
*data_pos = 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-08-07 13:57:28 +00:00
|
|
|
template <typename T>
|
2019-02-18 19:44:26 +00:00
|
|
|
ColumnPtr ColumnVector<T>::permute(const IColumn::Permutation & perm, size_t limit) const
|
2017-03-11 01:12:51 +00:00
|
|
|
{
|
2021-09-29 17:51:58 +00:00
|
|
|
return permuteImpl(*this, perm, limit);
|
2017-03-11 01:12:51 +00:00
|
|
|
}
|
|
|
|
|
2018-04-18 21:00:47 +00:00
|
|
|
template <typename T>
|
2019-02-18 17:28:53 +00:00
|
|
|
ColumnPtr ColumnVector<T>::index(const IColumn & indexes, size_t limit) const
|
2018-04-18 21:00:47 +00:00
|
|
|
{
|
|
|
|
return selectIndexImpl(*this, indexes, limit);
|
|
|
|
}
|
|
|
|
|
2022-06-29 15:50:25 +00:00
|
|
|
#ifdef __SSE2__
|
|
|
|
|
|
|
|
namespace
|
2017-03-11 01:12:51 +00:00
|
|
|
{
|
2022-06-29 15:50:25 +00:00
|
|
|
/** Optimization for ColumnVector replicate using SIMD instructions.
|
|
|
|
* For such optimization it is important that data is right padded with 15 bytes.
|
|
|
|
*
|
|
|
|
* Replicate span size is offsets[i] - offsets[i - 1].
|
|
|
|
*
|
|
|
|
* Split spans into 3 categories.
|
|
|
|
* 1. Span with 0 size. Continue iteration.
|
|
|
|
*
|
|
|
|
* 2. Span with 1 size. Update pointer from which data must be copied into result.
|
|
|
|
* Then if we see span with size 1 or greater than 1 copy data directly into result data and reset pointer.
|
|
|
|
* Example:
|
|
|
|
* Data: 1 2 3 4
|
|
|
|
* Offsets: 1 2 3 4
|
|
|
|
* Result data: 1 2 3 4
|
|
|
|
*
|
|
|
|
* 3. Span with size greater than 1. Save single data element into register and copy it into result data.
|
|
|
|
* Example:
|
|
|
|
* Data: 1 2 3 4
|
|
|
|
* Offsets: 4 4 4 4
|
|
|
|
* Result data: 1 1 1 1
|
|
|
|
*
|
|
|
|
* Additional handling for tail is needed if pointer from which data must be copied from span with size 1 is not null.
|
|
|
|
*/
|
|
|
|
template<typename IntType>
|
|
|
|
requires (std::is_same_v<IntType, Int32> || std::is_same_v<IntType, UInt32>)
|
2023-02-24 23:27:54 +00:00
|
|
|
void replicateSSE2Int32(const IntType * __restrict data, IntType * __restrict result_data, const IColumn::Offsets & offsets)
|
2022-06-29 15:50:25 +00:00
|
|
|
{
|
|
|
|
const IntType * data_copy_begin_ptr = nullptr;
|
|
|
|
size_t offsets_size = offsets.size();
|
2017-03-11 01:12:51 +00:00
|
|
|
|
2022-06-29 15:50:25 +00:00
|
|
|
for (size_t offset_index = 0; offset_index < offsets_size; ++offset_index)
|
|
|
|
{
|
|
|
|
size_t span = offsets[offset_index] - offsets[offset_index - 1];
|
|
|
|
if (span == 1)
|
|
|
|
{
|
|
|
|
if (!data_copy_begin_ptr)
|
|
|
|
data_copy_begin_ptr = data + offset_index;
|
2017-03-11 01:12:51 +00:00
|
|
|
|
2022-06-29 15:50:25 +00:00
|
|
|
continue;
|
|
|
|
}
|
2022-05-21 20:35:04 +00:00
|
|
|
|
2022-06-29 15:50:25 +00:00
|
|
|
/// Copy data
|
2017-03-11 01:12:51 +00:00
|
|
|
|
2022-06-29 15:50:25 +00:00
|
|
|
if (data_copy_begin_ptr)
|
|
|
|
{
|
|
|
|
size_t copy_size = (data + offset_index) - data_copy_begin_ptr;
|
|
|
|
bool remainder = copy_size % 4;
|
|
|
|
size_t sse_copy_counter = (copy_size / 4) + remainder;
|
|
|
|
auto * result_data_copy = result_data;
|
2017-03-11 01:12:51 +00:00
|
|
|
|
2022-06-29 15:50:25 +00:00
|
|
|
while (sse_copy_counter)
|
|
|
|
{
|
2022-06-30 12:49:11 +00:00
|
|
|
__m128i copy_batch = _mm_loadu_si128(reinterpret_cast<const __m128i *>(data_copy_begin_ptr));
|
|
|
|
_mm_storeu_si128(reinterpret_cast<__m128i *>(result_data_copy), copy_batch);
|
2022-06-29 15:50:25 +00:00
|
|
|
result_data_copy += 4;
|
|
|
|
data_copy_begin_ptr += 4;
|
|
|
|
--sse_copy_counter;
|
|
|
|
}
|
2017-03-11 01:12:51 +00:00
|
|
|
|
2022-06-29 15:50:25 +00:00
|
|
|
result_data += copy_size;
|
|
|
|
data_copy_begin_ptr = nullptr;
|
|
|
|
}
|
2022-05-21 20:35:04 +00:00
|
|
|
|
2022-06-29 15:50:25 +00:00
|
|
|
if (span == 0)
|
|
|
|
continue;
|
2022-05-21 20:35:04 +00:00
|
|
|
|
2022-06-29 15:50:25 +00:00
|
|
|
/// Copy single data element into result data
|
2022-05-16 14:48:37 +00:00
|
|
|
|
2022-06-29 15:50:25 +00:00
|
|
|
bool span_remainder = span % 4;
|
|
|
|
size_t copy_counter = (span / 4) + span_remainder;
|
|
|
|
auto * result_data_tmp = result_data;
|
|
|
|
__m128i copy_element_data = _mm_set1_epi32(data[offset_index]);
|
2022-05-21 20:35:04 +00:00
|
|
|
|
2022-06-29 15:50:25 +00:00
|
|
|
while (copy_counter)
|
|
|
|
{
|
|
|
|
_mm_storeu_si128(reinterpret_cast<__m128i *>(result_data_tmp), copy_element_data);
|
|
|
|
result_data_tmp += 4;
|
|
|
|
--copy_counter;
|
|
|
|
}
|
2022-05-21 20:35:04 +00:00
|
|
|
|
2022-06-29 15:50:25 +00:00
|
|
|
result_data += span;
|
2022-05-16 14:48:37 +00:00
|
|
|
}
|
2022-05-21 20:35:04 +00:00
|
|
|
|
2022-06-29 15:50:25 +00:00
|
|
|
/// Copy tail if needed
|
|
|
|
|
|
|
|
if (data_copy_begin_ptr)
|
2022-05-22 17:36:59 +00:00
|
|
|
{
|
2022-06-29 15:50:25 +00:00
|
|
|
size_t copy_size = (data + offsets_size) - data_copy_begin_ptr;
|
|
|
|
bool remainder = copy_size % 4;
|
|
|
|
size_t sse_copy_counter = (copy_size / 4) + remainder;
|
|
|
|
|
2022-05-22 17:36:59 +00:00
|
|
|
while (sse_copy_counter)
|
|
|
|
{
|
2022-06-30 12:49:11 +00:00
|
|
|
__m128i copy_batch = _mm_loadu_si128(reinterpret_cast<const __m128i *>(data_copy_begin_ptr));
|
|
|
|
_mm_storeu_si128(reinterpret_cast<__m128i *>(result_data), copy_batch);
|
2022-06-29 15:50:25 +00:00
|
|
|
result_data += 4;
|
|
|
|
data_copy_begin_ptr += 4;
|
2022-05-22 17:36:59 +00:00
|
|
|
--sse_copy_counter;
|
|
|
|
}
|
|
|
|
}
|
2022-06-29 15:50:25 +00:00
|
|
|
}
|
|
|
|
}
|
2022-05-21 20:35:04 +00:00
|
|
|
|
2022-06-29 15:50:25 +00:00
|
|
|
#endif
|
|
|
|
|
|
|
|
template <typename T>
|
|
|
|
ColumnPtr ColumnVector<T>::replicate(const IColumn::Offsets & offsets) const
|
|
|
|
{
|
|
|
|
const size_t size = data.size();
|
|
|
|
if (size != offsets.size())
|
2022-12-22 21:42:11 +00:00
|
|
|
throw Exception(ErrorCodes::SIZES_OF_COLUMNS_DOESNT_MATCH, "Size of offsets {} doesn't match size of column {}", offsets.size(), size);
|
2022-06-29 15:50:25 +00:00
|
|
|
|
|
|
|
if (0 == size)
|
|
|
|
return this->create();
|
|
|
|
|
|
|
|
auto res = this->create(offsets.back());
|
|
|
|
|
|
|
|
#ifdef __SSE2__
|
|
|
|
if constexpr (std::is_same_v<T, UInt32>)
|
|
|
|
{
|
2023-02-24 23:27:54 +00:00
|
|
|
replicateSSE2Int32(getData().data(), res->getData().data(), offsets);
|
2022-06-29 15:50:25 +00:00
|
|
|
return res;
|
2022-05-21 20:35:04 +00:00
|
|
|
}
|
2022-06-29 15:50:25 +00:00
|
|
|
#endif
|
2022-05-21 20:35:04 +00:00
|
|
|
|
2022-06-29 15:50:25 +00:00
|
|
|
auto it = res->getData().begin(); // NOLINT
|
|
|
|
for (size_t i = 0; i < size; ++i)
|
2022-05-21 20:35:04 +00:00
|
|
|
{
|
2022-06-29 15:50:25 +00:00
|
|
|
const auto span_end = res->getData().begin() + offsets[i]; // NOLINT
|
|
|
|
for (; it != span_end; ++it)
|
|
|
|
*it = data[i];
|
2022-05-16 14:48:37 +00:00
|
|
|
}
|
2022-05-21 20:35:04 +00:00
|
|
|
|
2022-05-16 14:48:37 +00:00
|
|
|
return res;
|
|
|
|
}
|
2022-05-21 20:35:04 +00:00
|
|
|
|
2018-08-07 13:57:28 +00:00
|
|
|
template <typename T>
|
|
|
|
void ColumnVector<T>::getExtremes(Field & min, Field & max) const
|
2017-03-11 01:12:51 +00:00
|
|
|
{
|
|
|
|
size_t size = data.size();
|
2017-04-01 07:20:54 +00:00
|
|
|
|
2017-03-11 01:12:51 +00:00
|
|
|
if (size == 0)
|
|
|
|
{
|
2018-10-22 08:54:54 +00:00
|
|
|
min = T(0);
|
|
|
|
max = T(0);
|
2017-03-11 01:12:51 +00:00
|
|
|
return;
|
|
|
|
}
|
2017-04-01 07:20:54 +00:00
|
|
|
|
2017-03-11 01:12:51 +00:00
|
|
|
bool has_value = false;
|
2017-04-01 07:20:54 +00:00
|
|
|
|
2017-03-11 01:12:51 +00:00
|
|
|
/** Skip all NaNs in extremes calculation.
|
|
|
|
* If all values are NaNs, then return NaN.
|
|
|
|
* NOTE: There exist many different NaNs.
|
|
|
|
* Different NaN could be returned: not bit-exact value as one of NaNs from column.
|
|
|
|
*/
|
2017-04-01 07:20:54 +00:00
|
|
|
|
2017-03-11 01:12:51 +00:00
|
|
|
T cur_min = NaNOrZero<T>();
|
|
|
|
T cur_max = NaNOrZero<T>();
|
2017-04-01 07:20:54 +00:00
|
|
|
|
2021-01-26 19:39:03 +00:00
|
|
|
for (const T & x : data)
|
2017-03-11 01:12:51 +00:00
|
|
|
{
|
|
|
|
if (isNaN(x))
|
|
|
|
continue;
|
2017-04-01 07:20:54 +00:00
|
|
|
|
2017-03-11 01:12:51 +00:00
|
|
|
if (!has_value)
|
|
|
|
{
|
|
|
|
cur_min = x;
|
|
|
|
cur_max = x;
|
|
|
|
has_value = true;
|
|
|
|
continue;
|
|
|
|
}
|
2017-04-01 07:20:54 +00:00
|
|
|
|
2017-03-11 01:12:51 +00:00
|
|
|
if (x < cur_min)
|
|
|
|
cur_min = x;
|
2017-09-14 11:52:22 +00:00
|
|
|
else if (x > cur_max)
|
2017-03-11 01:12:51 +00:00
|
|
|
cur_max = x;
|
|
|
|
}
|
2017-04-01 07:20:54 +00:00
|
|
|
|
2018-11-20 20:09:20 +00:00
|
|
|
min = NearestFieldType<T>(cur_min);
|
|
|
|
max = NearestFieldType<T>(cur_max);
|
2017-03-11 01:12:51 +00:00
|
|
|
}
|
|
|
|
|
2021-02-07 01:41:31 +00:00
|
|
|
template <typename T>
|
2021-02-12 00:25:00 +00:00
|
|
|
ColumnPtr ColumnVector<T>::compress() const
|
2021-02-07 01:41:31 +00:00
|
|
|
{
|
2021-12-18 20:13:42 +00:00
|
|
|
const size_t data_size = data.size();
|
|
|
|
const size_t source_size = data_size * sizeof(T);
|
2021-02-10 18:53:31 +00:00
|
|
|
|
|
|
|
/// Don't compress small blocks.
|
|
|
|
if (source_size < 4096) /// A wild guess.
|
2021-02-12 00:25:00 +00:00
|
|
|
return ColumnCompressed::wrap(this->getPtr());
|
2021-02-10 18:53:31 +00:00
|
|
|
|
2021-02-18 00:52:09 +00:00
|
|
|
auto compressed = ColumnCompressed::compressBuffer(data.data(), source_size, false);
|
2021-02-07 01:41:31 +00:00
|
|
|
|
2021-02-12 00:25:00 +00:00
|
|
|
if (!compressed)
|
|
|
|
return ColumnCompressed::wrap(this->getPtr());
|
2021-02-07 01:41:31 +00:00
|
|
|
|
2021-12-18 20:13:42 +00:00
|
|
|
const size_t compressed_size = compressed->size();
|
|
|
|
return ColumnCompressed::create(data_size, compressed_size,
|
2023-05-13 00:57:31 +00:00
|
|
|
[my_compressed = std::move(compressed), column_size = data_size]
|
2021-02-12 00:25:00 +00:00
|
|
|
{
|
|
|
|
auto res = ColumnVector<T>::create(column_size);
|
|
|
|
ColumnCompressed::decompressBuffer(
|
2023-05-13 00:57:31 +00:00
|
|
|
my_compressed->data(), res->getData().data(), my_compressed->size(), column_size * sizeof(T));
|
2021-02-12 00:25:00 +00:00
|
|
|
return res;
|
|
|
|
});
|
2021-02-07 01:41:31 +00:00
|
|
|
}
|
|
|
|
|
2021-04-01 18:18:28 +00:00
|
|
|
template <typename T>
|
2024-01-22 13:41:58 +00:00
|
|
|
ColumnPtr ColumnVector<T>::createWithOffsets(const IColumn::Offsets & offsets, const ColumnConst & column_with_default_value, size_t total_rows, size_t shift) const
|
2021-04-01 18:18:28 +00:00
|
|
|
{
|
2021-05-21 00:57:11 +00:00
|
|
|
if (offsets.size() + shift != size())
|
|
|
|
throw Exception(ErrorCodes::LOGICAL_ERROR,
|
|
|
|
"Incompatible sizes of offsets ({}), shift ({}) and size of column {}", offsets.size(), shift, size());
|
|
|
|
|
2021-04-01 18:18:28 +00:00
|
|
|
auto res = this->create();
|
|
|
|
auto & res_data = res->getData();
|
|
|
|
|
2024-01-22 13:41:58 +00:00
|
|
|
T default_value = assert_cast<const ColumnVector<T> &>(column_with_default_value.getDataColumn()).getElement(0);
|
2021-09-16 13:57:45 +00:00
|
|
|
res_data.resize_fill(total_rows, default_value);
|
2021-04-01 18:18:28 +00:00
|
|
|
for (size_t i = 0; i < offsets.size(); ++i)
|
2021-05-21 00:57:11 +00:00
|
|
|
res_data[offsets[i]] = data[i + shift];
|
2021-04-01 18:18:28 +00:00
|
|
|
|
|
|
|
return res;
|
|
|
|
}
|
|
|
|
|
2017-04-18 03:03:39 +00:00
|
|
|
/// Explicit template instantiations - to avoid code bloat in headers.
|
2018-08-07 13:57:28 +00:00
|
|
|
template class ColumnVector<UInt8>;
|
|
|
|
template class ColumnVector<UInt16>;
|
|
|
|
template class ColumnVector<UInt32>;
|
|
|
|
template class ColumnVector<UInt64>;
|
|
|
|
template class ColumnVector<UInt128>;
|
2020-09-01 09:54:50 +00:00
|
|
|
template class ColumnVector<UInt256>;
|
2018-08-07 13:57:28 +00:00
|
|
|
template class ColumnVector<Int8>;
|
|
|
|
template class ColumnVector<Int16>;
|
|
|
|
template class ColumnVector<Int32>;
|
|
|
|
template class ColumnVector<Int64>;
|
|
|
|
template class ColumnVector<Int128>;
|
2020-09-01 09:54:50 +00:00
|
|
|
template class ColumnVector<Int256>;
|
2018-08-07 13:57:28 +00:00
|
|
|
template class ColumnVector<Float32>;
|
|
|
|
template class ColumnVector<Float64>;
|
2021-05-03 22:46:51 +00:00
|
|
|
template class ColumnVector<UUID>;
|
2022-11-14 14:17:17 +00:00
|
|
|
template class ColumnVector<IPv4>;
|
|
|
|
template class ColumnVector<IPv6>;
|
2021-02-11 21:54:50 +00:00
|
|
|
|
2017-03-11 01:12:51 +00:00
|
|
|
}
|