// Copyright 2023 PingCAP, Inc. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. #include #include #include #include #include #include #include #include #include #include #include #include #if __SSE2__ #include #endif namespace DB { namespace ErrorCodes { extern const int PARAMETER_OUT_OF_BOUND; extern const int SIZES_OF_COLUMNS_DOESNT_MATCH; } // namespace ErrorCodes template StringRef ColumnVector::serializeValueIntoArena( size_t n, Arena & arena, char const *& begin, const TiDB::TiDBCollatorPtr &, String &) const { auto * pos = arena.allocContinue(sizeof(T), begin); memcpy(pos, &data[n], sizeof(T)); return StringRef(pos, sizeof(T)); } template void ColumnVector::updateHashWithValue(size_t n, SipHash & hash, const TiDB::TiDBCollatorPtr &, String &) const { hash.update(data[n]); } template void ColumnVector::updateHashWithValues(IColumn::HashValues & hash_values, const TiDB::TiDBCollatorPtr &, String &) const { for (size_t i = 0, sz = size(); i < sz; ++i) { hash_values[i].update(data[i]); } } template void ColumnVector::updateWeakHash32(WeakHash32 & hash, const TiDB::TiDBCollatorPtr &, String &) const { updateWeakHash32Impl(hash, {}); } template void ColumnVector::updateWeakHash32( WeakHash32 & hash, const TiDB::TiDBCollatorPtr &, String &, const BlockSelective & selective) const { updateWeakHash32Impl(hash, selective); } template template void ColumnVector::updateWeakHash32Impl(WeakHash32 & hash, const BlockSelective & selective) const { size_t rows; if constexpr (selective_block) { rows = selective.size(); } else { rows = data.size(); } RUNTIME_CHECK_MSG( hash.getData().size() == rows, "size of WeakHash32({}) doesn't match size of column({})", hash.getData().size(), rows); const T * begin = data.data(); UInt32 * hash_data = hash.getData().data(); for (size_t i = 0; i < rows; ++i) { size_t row = i; if constexpr (selective_block) row = selective[i]; if constexpr (is_fit_register) *hash_data = intHashCRC32(*(begin + row), *hash_data); else *hash_data = wideIntHashCRC32(*(begin + row), *hash_data); ++hash_data; } } template struct ColumnVector::less { const Self & parent; 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::less(parent.data[lhs], parent.data[rhs], nan_direction_hint); } }; template struct ColumnVector::greater { const Self & parent; 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::greater(parent.data[lhs], parent.data[rhs], nan_direction_hint); } }; template void ColumnVector::getPermutation(bool reverse, size_t limit, int nan_direction_hint, IColumn::Permutation & res) const { size_t s = data.size(); res.resize(s); for (size_t i = 0; i < s; ++i) res[i] = i; if (limit >= s) limit = 0; if (limit) { if (reverse) std::partial_sort(res.begin(), res.begin() + limit, res.end(), greater(*this, nan_direction_hint)); else std::partial_sort(res.begin(), res.begin() + limit, res.end(), less(*this, nan_direction_hint)); } else { if (reverse) std::sort(res.begin(), res.end(), greater(*this, nan_direction_hint)); else std::sort(res.begin(), res.end(), less(*this, nan_direction_hint)); } } template const char * ColumnVector::getFamilyName() const { return TypeName::get(); } template MutableColumnPtr ColumnVector::cloneResized(size_t size) const { auto res = this->create(); if (size > 0) { auto & new_col = static_cast(*res); new_col.data.resize(size); size_t count = std::min(this->size(), size); memcpy(&new_col.data[0], &data[0], count * sizeof(data[0])); if (size > count) memset(&new_col.data[count], static_cast(value_type()), size - count); } return res; } template UInt64 ColumnVector::get64(size_t n) const { return ext::bit_cast(data[n]); } template UInt64 ColumnVector::getUInt(size_t n) const { return static_cast(data[n]); } template Int64 ColumnVector::getInt(size_t n) const { return static_cast(data[n]); } template void ColumnVector::insertRangeFrom(const IColumn & src, size_t start, size_t length) { const auto & src_vec = static_cast(src); if (start + length > src_vec.data.size()) throw Exception( fmt::format( "Parameters are out of bound in ColumnVector::insertRangeFrom method, start={}, length={}, " "src.size()={}", start, length, src_vec.data.size()), ErrorCodes::PARAMETER_OUT_OF_BOUND); size_t old_size = data.size(); data.resize(old_size + length); memcpy(&data[old_size], &src_vec.data[start], length * sizeof(data[0])); } template ColumnPtr ColumnVector::filter(const IColumn::Filter & filt, ssize_t result_size_hint) const { size_t size = data.size(); if (size != filt.size()) throw Exception("Size of filter doesn't match size of column.", ErrorCodes::SIZES_OF_COLUMNS_DOESNT_MATCH); auto res = this->create(); Container & res_data = res->getData(); if (result_size_hint) { if (result_size_hint < 0) result_size_hint = countBytesInFilter(filt); res_data.reserve(result_size_hint); } const UInt8 * filt_pos = &filt[0]; const UInt8 * filt_end = filt_pos + size; const T * data_pos = &data[0]; filterImpl(filt_pos, filt_end, data_pos, res_data); return res; } template ColumnPtr ColumnVector::permute(const IColumn::Permutation & perm, size_t limit) const { size_t size = data.size(); if (limit == 0) limit = size; else limit = std::min(size, limit); if (perm.size() < limit) throw Exception("Size of permutation is less than required.", ErrorCodes::SIZES_OF_COLUMNS_DOESNT_MATCH); auto res = this->create(limit); typename Self::Container & res_data = res->getData(); for (size_t i = 0; i < limit; ++i) res_data[i] = data[perm[i]]; return res; } template ColumnPtr ColumnVector::replicateRange(size_t start_row, size_t end_row, const IColumn::Offsets & offsets) const { size_t size = data.size(); if (size != offsets.size()) throw Exception("Size of offsets doesn't match size of column.", ErrorCodes::SIZES_OF_COLUMNS_DOESNT_MATCH); assert(start_row < end_row); assert(end_row <= size); if (0 == size) return this->create(); auto res = this->create(); typename Self::Container & res_data = res->getData(); res_data.reserve(offsets[end_row - 1]); IColumn::Offset prev_offset = 0; for (size_t i = start_row; i < end_row; ++i) { size_t size_to_replicate = offsets[i] - prev_offset; prev_offset = offsets[i]; for (size_t j = 0; j < size_to_replicate; ++j) { res_data.push_back(data[i]); } } return res; } template void ColumnVector::gather(ColumnGathererStream & gatherer) { gatherer.gather(*this); } template void ColumnVector::getExtremes(Field & min, Field & max) const { size_t size = data.size(); if (size == 0) { min = static_cast::Type>(0); max = static_cast::Type>(0); return; } bool has_value = false; /** 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. */ T cur_min = NaNOrZero(); T cur_max = NaNOrZero(); for (const T x : data) { if (isNaN(x)) continue; if (!has_value) { cur_min = x; cur_max = x; has_value = true; continue; } if (x < cur_min) cur_min = x; else if (x > cur_max) cur_max = x; } min = static_cast::Type>(cur_min); max = static_cast::Type>(cur_max); } /// Explicit template instantiations - to avoid code bloat in headers. template class ColumnVector; template class ColumnVector; template class ColumnVector; template class ColumnVector; template class ColumnVector; template class ColumnVector; template class ColumnVector; template class ColumnVector; template class ColumnVector; template class ColumnVector; template class ColumnVector; } // namespace DB