| 1 | #include <Columns/ColumnConst.h> |
| 2 | #include <Columns/ColumnVector.h> |
| 3 | #include <Common/typeid_cast.h> |
| 4 | #include <Common/assert_cast.h> |
| 5 | |
| 6 | #include <type_traits> |
| 7 | |
| 8 | #ifdef __SSE2__ |
| 9 | #define LIBDIVIDE_USE_SSE2 1 |
| 10 | #endif |
| 11 | |
| 12 | #include <libdivide.h> |
| 13 | |
| 14 | |
| 15 | namespace DB |
| 16 | { |
| 17 | |
| 18 | template <typename T> |
| 19 | IColumn::Selector createBlockSelector( |
| 20 | const IColumn & column, |
| 21 | const std::vector<UInt64> & slots) |
| 22 | { |
| 23 | const auto total_weight = slots.size(); |
| 24 | size_t num_rows = column.size(); |
| 25 | IColumn::Selector selector(num_rows); |
| 26 | |
| 27 | /** Modulo of division of negative numbers to positive number in C++11 is negative (so called truncated division). |
| 28 | * This is not suitable for our task. So we will process signed numbers as unsigned. |
| 29 | * It is not near like remainder of division, but is suitable for our task. |
| 30 | */ |
| 31 | using UnsignedT = std::make_unsigned_t<T>; |
| 32 | |
| 33 | /// const columns contain only one value, therefore we do not need to read it at every iteration |
| 34 | if (isColumnConst(column)) |
| 35 | { |
| 36 | const auto data = assert_cast<const ColumnConst &>(column).getValue<T>(); |
| 37 | const auto shard_num = slots[static_cast<UnsignedT>(data) % total_weight]; |
| 38 | selector.assign(num_rows, shard_num); |
| 39 | } |
| 40 | else |
| 41 | { |
| 42 | /// libdivide support only UInt32 and UInt64. |
| 43 | using TUInt32Or64 = std::conditional_t<sizeof(UnsignedT) <= 4, UInt32, UInt64>; |
| 44 | |
| 45 | libdivide::divider<TUInt32Or64> divider(total_weight); |
| 46 | |
| 47 | const auto & data = typeid_cast<const ColumnVector<T> &>(column).getData(); |
| 48 | |
| 49 | for (size_t i = 0; i < num_rows; ++i) |
| 50 | selector[i] = slots[static_cast<TUInt32Or64>(data[i]) - (static_cast<TUInt32Or64>(data[i]) / divider) * total_weight]; |
| 51 | } |
| 52 | |
| 53 | return selector; |
| 54 | } |
| 55 | |
| 56 | |
| 57 | /// Explicit instantiations to avoid code bloat in headers. |
| 58 | template IColumn::Selector createBlockSelector<UInt8>(const IColumn & column, const std::vector<UInt64> & slots); |
| 59 | template IColumn::Selector createBlockSelector<UInt16>(const IColumn & column, const std::vector<UInt64> & slots); |
| 60 | template IColumn::Selector createBlockSelector<UInt32>(const IColumn & column, const std::vector<UInt64> & slots); |
| 61 | template IColumn::Selector createBlockSelector<UInt64>(const IColumn & column, const std::vector<UInt64> & slots); |
| 62 | template IColumn::Selector createBlockSelector<Int8>(const IColumn & column, const std::vector<UInt64> & slots); |
| 63 | template IColumn::Selector createBlockSelector<Int16>(const IColumn & column, const std::vector<UInt64> & slots); |
| 64 | template IColumn::Selector createBlockSelector<Int32>(const IColumn & column, const std::vector<UInt64> & slots); |
| 65 | template IColumn::Selector createBlockSelector<Int64>(const IColumn & column, const std::vector<UInt64> & slots); |
| 66 | |
| 67 | } |
| 68 | |