| 40 | /// Precondition: data.size() == offsets.size() == fixed_string_N.size() == constant_strings.size(). |
| 41 | template <bool has_column_string, bool has_column_fixed_string> |
| 42 | static void format( |
| 43 | String pattern, |
| 44 | const VectorWithMemoryTracking<const ColumnString::Chars *> & data, |
| 45 | const VectorWithMemoryTracking<const ColumnString::Offsets *> & offsets, |
| 46 | [[maybe_unused]] /* Because sometimes !has_column_fixed_string */ const VectorWithMemoryTracking<size_t> & fixed_string_N, |
| 47 | const VectorWithMemoryTracking<std::optional<String>> & constant_strings, |
| 48 | ColumnString::Chars & res_data, |
| 49 | ColumnString::Offsets & res_offsets, |
| 50 | size_t input_rows_count) |
| 51 | { |
| 52 | const size_t argument_number = offsets.size(); |
| 53 | |
| 54 | /// The subsequent indexes of strings we should use. e.g `Hello world {1} {3} {1} {0}` this |
| 55 | /// array will be filled with [1, 3, 1, 0] but without constant string indices. |
| 56 | Format::IndexPositions index_positions; |
| 57 | |
| 58 | /// Vector of substrings of pattern that will be copied to the answer, not string view because of escaping and iterators invalidation. |
| 59 | /// These are exactly what is between {} tokens, for `Hello {} world {}` we will have [`Hello `, ` world `, ``]. |
| 60 | VectorWithMemoryTracking<String> substrings; |
| 61 | |
| 62 | Format::init(pattern, argument_number, constant_strings, index_positions, substrings); |
| 63 | |
| 64 | UInt64 final_size = 0; |
| 65 | |
| 66 | for (String & str : substrings) |
| 67 | { |
| 68 | /// To use memcpySmallAllowReadWriteOverflow15 for substrings we should allocate a bit more to each string. |
| 69 | /// That was chosen due to performance reasons. |
| 70 | if (!str.empty()) |
| 71 | str.reserve(str.size() + right_padding); |
| 72 | final_size += str.size(); |
| 73 | } |
| 74 | |
| 75 | /// The substring number is repeated input_rows_times. |
| 76 | final_size *= input_rows_count; |
| 77 | |
| 78 | for (size_t i = 1; i < substrings.size(); ++i) |
| 79 | final_size += data[index_positions[i - 1]]->size(); |
| 80 | |
| 81 | res_data.resize(final_size); |
| 82 | res_offsets.resize(input_rows_count); |
| 83 | |
| 84 | UInt64 offset = 0; |
| 85 | for (UInt64 i = 0; i < input_rows_count; ++i) |
| 86 | { |
| 87 | memcpySmallAllowReadWriteOverflow15(res_data.data() + offset, substrings[0].data(), substrings[0].size()); |
| 88 | offset += substrings[0].size(); |
| 89 | /// All strings are constant, we should have substrings.size() == 1. |
| 90 | if constexpr (has_column_string || has_column_fixed_string) |
| 91 | { |
| 92 | for (size_t j = 1; j < substrings.size(); ++j) |
| 93 | { |
| 94 | UInt64 arg = index_positions[j - 1]; |
| 95 | const auto * offset_ptr = offsets[arg]; |
| 96 | UInt64 arg_offset = 0; |
| 97 | UInt64 size = 0; |
| 98 | |
| 99 | if constexpr (has_column_string) |
no test coverage detected