ColumnPtr ColumnArray::replicateNumber(const Offsets_t & replicate_offsets) const { size_t col_size = size(); if (col_size != replicate_offsets.size()) throw Exception("Size of offsets doesn't match size of column.", ErrorCodes::SIZES_OF_COLUMNS_DOESNT_MATCH); ColumnPtr res = cloneEmpty(); if (0 == col_size) return res; ColumnArray & res_ = typeid_cast<ColumnArray &>(*res); const typename ColumnVector<T>::Container_t & src_data = typeid_cast<const ColumnVector<T> &>(*data).getData(); const Offsets_t & src_offsets = getOffsets(); typename ColumnVector<T>::Container_t & res_data = typeid_cast<ColumnVector<T> &>(res_.getData()).getData(); Offsets_t & res_offsets = res_.getOffsets(); res_data.reserve(data->size() / col_size * replicate_offsets.back()); res_offsets.reserve(replicate_offsets.back()); Offset_t prev_replicate_offset = 0; Offset_t prev_data_offset = 0; Offset_t current_new_offset = 0; for (size_t i = 0; i < col_size; ++i) { size_t size_to_replicate = replicate_offsets[i] - prev_replicate_offset; size_t value_size = src_offsets[i] - prev_data_offset; for (size_t j = 0; j < size_to_replicate; ++j) { current_new_offset += value_size; res_offsets.push_back(current_new_offset); res_data.resize(res_data.size() + value_size); memcpy(&res_data[res_data.size() - value_size], &src_data[prev_data_offset], value_size * sizeof(T)); } prev_replicate_offset = replicate_offsets[i]; prev_data_offset = src_offsets[i]; } return res; }
ColumnPtr ColumnString::replicate(const Offsets_t & replicate_offsets) const { size_t col_size = size(); if (col_size != replicate_offsets.size()) throw Exception("Size of offsets doesn't match size of column.", ErrorCodes::SIZES_OF_COLUMNS_DOESNT_MATCH); std::shared_ptr<ColumnString> res = std::make_shared<ColumnString>(); if (0 == col_size) return res; Chars_t & res_chars = res->chars; Offsets_t & res_offsets = res->offsets; res_chars.reserve(chars.size() / col_size * replicate_offsets.back()); res_offsets.reserve(replicate_offsets.back()); Offset_t prev_replicate_offset = 0; Offset_t prev_string_offset = 0; Offset_t current_new_offset = 0; for (size_t i = 0; i < col_size; ++i) { size_t size_to_replicate = replicate_offsets[i] - prev_replicate_offset; size_t string_size = offsets[i] - prev_string_offset; for (size_t j = 0; j < size_to_replicate; ++j) { current_new_offset += string_size; res_offsets.push_back(current_new_offset); res_chars.resize(res_chars.size() + string_size); memcpySmallAllowReadWriteOverflow15( &res_chars[res_chars.size() - string_size], &chars[prev_string_offset], string_size); } prev_replicate_offset = replicate_offsets[i]; prev_string_offset = offsets[i]; } return res; }
ColumnPtr ColumnArray::replicateConst(const Offsets_t & replicate_offsets) const { size_t col_size = size(); if (col_size != replicate_offsets.size()) throw Exception("Size of offsets doesn't match size of column.", ErrorCodes::SIZES_OF_COLUMNS_DOESNT_MATCH); if (0 == col_size) return cloneEmpty(); const Offsets_t & src_offsets = getOffsets(); auto res_column_offsets = std::make_shared<ColumnOffsets_t>(); Offsets_t & res_offsets = res_column_offsets->getData(); res_offsets.reserve(replicate_offsets.back()); Offset_t prev_replicate_offset = 0; Offset_t prev_data_offset = 0; Offset_t current_new_offset = 0; for (size_t i = 0; i < col_size; ++i) { size_t size_to_replicate = replicate_offsets[i] - prev_replicate_offset; size_t value_size = src_offsets[i] - prev_data_offset; for (size_t j = 0; j < size_to_replicate; ++j) { current_new_offset += value_size; res_offsets.push_back(current_new_offset); } prev_replicate_offset = replicate_offsets[i]; prev_data_offset = src_offsets[i]; } return std::make_shared<ColumnArray>(getData().cloneResized(current_new_offset), res_column_offsets); }
ColumnPtr ColumnArray::replicateString(const Offsets_t & replicate_offsets) const { size_t col_size = size(); if (col_size != replicate_offsets.size()) throw Exception("Size of offsets doesn't match size of column.", ErrorCodes::SIZES_OF_COLUMNS_DOESNT_MATCH); ColumnPtr res = cloneEmpty(); if (0 == col_size) return res; ColumnArray & res_ = static_cast<ColumnArray &>(*res); const ColumnString & src_string = typeid_cast<const ColumnString &>(*data); const ColumnString::Chars_t & src_chars = src_string.getChars(); const Offsets_t & src_string_offsets = src_string.getOffsets(); const Offsets_t & src_offsets = getOffsets(); ColumnString::Chars_t & res_chars = typeid_cast<ColumnString &>(res_.getData()).getChars(); Offsets_t & res_string_offsets = typeid_cast<ColumnString &>(res_.getData()).getOffsets(); Offsets_t & res_offsets = res_.getOffsets(); res_chars.reserve(src_chars.size() / col_size * replicate_offsets.back()); res_string_offsets.reserve(src_string_offsets.size() / col_size * replicate_offsets.back()); res_offsets.reserve(replicate_offsets.back()); Offset_t prev_replicate_offset = 0; Offset_t prev_src_offset = 0; Offset_t prev_src_string_offset = 0; Offset_t current_res_offset = 0; Offset_t current_res_string_offset = 0; for (size_t i = 0; i < col_size; ++i) { /// Насколько размножить массив. size_t size_to_replicate = replicate_offsets[i] - prev_replicate_offset; /// Количество строк в массиве. size_t value_size = src_offsets[i] - prev_src_offset; /// Количество символов в строках массива, включая нулевые байты. size_t sum_chars_size = value_size == 0 ? 0 : (src_string_offsets[prev_src_offset + value_size - 1] - prev_src_string_offset); for (size_t j = 0; j < size_to_replicate; ++j) { current_res_offset += value_size; res_offsets.push_back(current_res_offset); size_t prev_src_string_offset_local = prev_src_string_offset; for (size_t k = 0; k < value_size; ++k) { /// Размер одной строки. size_t chars_size = src_string_offsets[k + prev_src_offset] - prev_src_string_offset_local; current_res_string_offset += chars_size; res_string_offsets.push_back(current_res_string_offset); prev_src_string_offset_local += chars_size; } /// Копирование символов массива строк. res_chars.resize(res_chars.size() + sum_chars_size); memcpySmallAllowReadWriteOverflow15( &res_chars[res_chars.size() - sum_chars_size], &src_chars[prev_src_string_offset], sum_chars_size); } prev_replicate_offset = replicate_offsets[i]; prev_src_offset = src_offsets[i]; prev_src_string_offset += sum_chars_size; } return res; }