/root/doris/be/src/gutil/strings/join.h
Line | Count | Source (jump to first uncovered line) |
1 | | // Copyright 2008 and onwards Google, Inc. |
2 | | // |
3 | | // #status: RECOMMENDED |
4 | | // #category: operations on strings |
5 | | // #summary: Functions for joining strings and numbers using a delimiter. |
6 | | // |
7 | | #pragma once |
8 | | |
9 | | #include <iterator> |
10 | | // IWYU pragma: no_include <ext/type_traits> |
11 | | #include <type_traits> // IWYU pragma: keep |
12 | | |
13 | | using std::back_insert_iterator; |
14 | | using std::iterator_traits; |
15 | | #include <map> |
16 | | |
17 | | using std::map; |
18 | | using std::multimap; |
19 | | #include <set> |
20 | | |
21 | | using std::multiset; |
22 | | using std::set; |
23 | | #include <string> |
24 | | |
25 | | using std::string; |
26 | | #include <utility> |
27 | | |
28 | | using std::make_pair; |
29 | | using std::pair; |
30 | | #include <vector> |
31 | | |
32 | | using std::vector; |
33 | | |
34 | | #include "gutil/strings/strcat.h" // For backward compatibility. |
35 | | #include "gutil/strings/stringpiece.h" |
36 | | |
37 | | // ---------------------------------------------------------------------- |
38 | | // JoinUsing() |
39 | | // This concatenates a vector of strings "components" into a new char[] |
40 | | // buffer, using the C-string "delim" as a separator between components. |
41 | | // |
42 | | // This is essentially the same as JoinUsingToBuffer except |
43 | | // the return result is dynamically allocated using "new char[]". |
44 | | // It is the caller's responsibility to "delete []" the char* that is |
45 | | // returned. |
46 | | // |
47 | | // If result_length_p is not NULL, it will contain the length of the |
48 | | // result string (not including the trailing '\0'). |
49 | | // ---------------------------------------------------------------------- |
50 | | char* JoinUsing(const vector<const char*>& components, const char* delim, int* result_length_p); |
51 | | |
52 | | // ---------------------------------------------------------------------- |
53 | | // JoinUsingToBuffer() |
54 | | // This concatenates a vector of strings "components" into a given char[] |
55 | | // buffer, using the C-string "delim" as a separator between components. |
56 | | // User supplies the result buffer with specified buffer size. |
57 | | // The result is also returned for convenience. |
58 | | // |
59 | | // If result_length_p is not NULL, it will contain the length of the |
60 | | // result string (not including the trailing '\0'). |
61 | | // ---------------------------------------------------------------------- |
62 | | char* JoinUsingToBuffer(const vector<const char*>& components, const char* delim, |
63 | | int result_buffer_size, char* result_buffer, int* result_length_p); |
64 | | |
65 | | // ---------------------------------------------------------------------- |
66 | | // JoinStrings(), JoinStringsIterator(), JoinStringsInArray() |
67 | | // |
68 | | // JoinStrings concatenates a container of strings into a C++ string, |
69 | | // using the string "delim" as a separator between components. |
70 | | // "components" can be any sequence container whose values are C++ strings |
71 | | // or StringPieces. More precisely, "components" must support STL container |
72 | | // iteration; i.e. it must have begin() and end() methods with appropriate |
73 | | // semantics, which return forward iterators whose value type is |
74 | | // string or StringPiece. Repeated string fields of protocol messages |
75 | | // satisfy these requirements. |
76 | | // |
77 | | // JoinStringsIterator is the same as JoinStrings, except that the input |
78 | | // strings are specified with a pair of iterators. The requirements on |
79 | | // the iterators are the same as the requirements on components.begin() |
80 | | // and components.end() for JoinStrings. |
81 | | // |
82 | | // JoinStringsInArray is the same as JoinStrings, but operates on |
83 | | // an array of C++ strings or string pointers. |
84 | | // |
85 | | // There are two flavors of each function, one flavor returns the |
86 | | // concatenated string, another takes a pointer to the target string. In |
87 | | // the latter case the target string is cleared and overwritten. |
88 | | // ---------------------------------------------------------------------- |
89 | | template <class CONTAINER> |
90 | | void JoinStrings(const CONTAINER& components, const StringPiece& delim, string* result); |
91 | | template <class CONTAINER> |
92 | | string JoinStrings(const CONTAINER& components, const StringPiece& delim); |
93 | | |
94 | | template <class ITERATOR> |
95 | | void JoinStringsIterator(const ITERATOR& start, const ITERATOR& end, const StringPiece& delim, |
96 | | string* result); |
97 | | template <class ITERATOR> |
98 | | string JoinStringsIterator(const ITERATOR& start, const ITERATOR& end, const StringPiece& delim); |
99 | | |
100 | | // Join the keys of a map using the specified delimiter. |
101 | | template <typename ITERATOR> |
102 | | void JoinKeysIterator(const ITERATOR& start, const ITERATOR& end, const StringPiece& delim, |
103 | | string* result) { |
104 | | result->clear(); |
105 | | for (ITERATOR iter = start; iter != end; ++iter) { |
106 | | if (iter == start) { |
107 | | StrAppend(result, iter->first); |
108 | | } else { |
109 | | StrAppend(result, delim, iter->first); |
110 | | } |
111 | | } |
112 | | } |
113 | | |
114 | | template <typename ITERATOR> |
115 | | string JoinKeysIterator(const ITERATOR& start, const ITERATOR& end, const StringPiece& delim) { |
116 | | string result; |
117 | | JoinKeysIterator(start, end, delim, &result); |
118 | | return result; |
119 | | } |
120 | | |
121 | | // Join the keys and values of a map using the specified delimiters. |
122 | | template <typename ITERATOR> |
123 | | void JoinKeysAndValuesIterator(const ITERATOR& start, const ITERATOR& end, |
124 | | const StringPiece& intra_delim, const StringPiece& inter_delim, |
125 | | string* result) { |
126 | | result->clear(); |
127 | | for (ITERATOR iter = start; iter != end; ++iter) { |
128 | | if (iter == start) { |
129 | | StrAppend(result, iter->first, intra_delim, iter->second); |
130 | | } else { |
131 | | StrAppend(result, inter_delim, iter->first, intra_delim, iter->second); |
132 | | } |
133 | | } |
134 | | } |
135 | | |
136 | | template <typename ITERATOR> |
137 | | string JoinKeysAndValuesIterator(const ITERATOR& start, const ITERATOR& end, |
138 | | const StringPiece& intra_delim, const StringPiece& inter_delim) { |
139 | | string result; |
140 | | JoinKeysAndValuesIterator(start, end, intra_delim, inter_delim, &result); |
141 | | return result; |
142 | | } |
143 | | |
144 | | void JoinStringsInArray(string const* const* components, int num_components, const char* delim, |
145 | | string* result); |
146 | | void JoinStringsInArray(string const* components, int num_components, const char* delim, |
147 | | string* result); |
148 | | string JoinStringsInArray(string const* const* components, int num_components, const char* delim); |
149 | | string JoinStringsInArray(string const* components, int num_components, const char* delim); |
150 | | |
151 | | // ---------------------------------------------------------------------- |
152 | | // Definitions of above JoinStrings* methods |
153 | | // ---------------------------------------------------------------------- |
154 | | template <class CONTAINER> |
155 | | void JoinStrings(const CONTAINER& components, const StringPiece& delim, string* result) { |
156 | | JoinStringsIterator(components.begin(), components.end(), delim, result); |
157 | | } |
158 | | |
159 | | template <class CONTAINER> |
160 | | string JoinStrings(const CONTAINER& components, const StringPiece& delim) { |
161 | | string result; |
162 | | JoinStrings(components, delim, &result); |
163 | | return result; |
164 | | } |
165 | | |
166 | | // Join the strings produced by calling 'functor' on each element of |
167 | | // 'components'. |
168 | | template <class CONTAINER, typename FUNC> |
169 | | string JoinMapped(const CONTAINER& components, const FUNC& functor, const StringPiece& delim) { |
170 | | string result; |
171 | | for (typename CONTAINER::const_iterator iter = components.begin(); iter != components.end(); |
172 | | iter++) { |
173 | | if (iter != components.begin()) { |
174 | | result.append(delim.data(), delim.size()); |
175 | | } |
176 | | result.append(functor(*iter)); |
177 | | } |
178 | | return result; |
179 | | } |
180 | | |
181 | | template <class ITERATOR> |
182 | | void JoinStringsIterator(const ITERATOR& start, const ITERATOR& end, const StringPiece& delim, |
183 | | string* result) { |
184 | | result->clear(); |
185 | | |
186 | | // Precompute resulting length so we can reserve() memory in one shot. |
187 | | if (start != end) { |
188 | | int length = delim.size() * (distance(start, end) - 1); |
189 | | for (ITERATOR iter = start; iter != end; ++iter) { |
190 | | length += iter->size(); |
191 | | } |
192 | | result->reserve(length); |
193 | | } |
194 | | |
195 | | // Now combine everything. |
196 | | for (ITERATOR iter = start; iter != end; ++iter) { |
197 | | if (iter != start) { |
198 | | result->append(delim.data(), delim.size()); |
199 | | } |
200 | | result->append(iter->data(), iter->size()); |
201 | | } |
202 | | } |
203 | | |
204 | | template <class ITERATOR> |
205 | | string JoinStringsIterator(const ITERATOR& start, const ITERATOR& end, const StringPiece& delim) { |
206 | | string result; |
207 | | JoinStringsIterator(start, end, delim, &result); |
208 | | return result; |
209 | | } |
210 | | |
211 | | inline string JoinStringsInArray(string const* const* components, int num_components, |
212 | 0 | const char* delim) { |
213 | 0 | string result; |
214 | 0 | JoinStringsInArray(components, num_components, delim, &result); |
215 | 0 | return result; |
216 | 0 | } |
217 | | |
218 | 0 | inline string JoinStringsInArray(string const* components, int num_components, const char* delim) { |
219 | 0 | string result; |
220 | 0 | JoinStringsInArray(components, num_components, delim, &result); |
221 | 0 | return result; |
222 | 0 | } |
223 | | |
224 | | // ---------------------------------------------------------------------- |
225 | | // JoinMapKeysAndValues() |
226 | | // JoinHashMapKeysAndValues() |
227 | | // JoinVectorKeysAndValues() |
228 | | // This merges the keys and values of a string -> string map or pair |
229 | | // of strings vector, with one delim (intra_delim) between each key |
230 | | // and its associated value and another delim (inter_delim) between |
231 | | // each key/value pair. The result is returned in a string (passed |
232 | | // as the last argument). |
233 | | // ---------------------------------------------------------------------- |
234 | | |
235 | | void JoinMapKeysAndValues(const map<string, string>& components, const StringPiece& intra_delim, |
236 | | const StringPiece& inter_delim, string* result); |
237 | | void JoinVectorKeysAndValues(const vector<pair<string, string>>& components, |
238 | | const StringPiece& intra_delim, const StringPiece& inter_delim, |
239 | | string* result); |
240 | | |
241 | | // DEPRECATED(jyrki): use JoinKeysAndValuesIterator directly. |
242 | | template <typename T> |
243 | | void JoinHashMapKeysAndValues(const T& container, const StringPiece& intra_delim, |
244 | | const StringPiece& inter_delim, string* result) { |
245 | | JoinKeysAndValuesIterator(container.begin(), container.end(), intra_delim, inter_delim, result); |
246 | | } |
247 | | |
248 | | // ---------------------------------------------------------------------- |
249 | | // JoinCSVLineWithDelimiter() |
250 | | // This function is the inverse of SplitCSVLineWithDelimiter() in that the |
251 | | // string returned by JoinCSVLineWithDelimiter() can be passed to |
252 | | // SplitCSVLineWithDelimiter() to get the original string vector back. |
253 | | // Quotes and escapes the elements of original_cols according to CSV quoting |
254 | | // rules, and the joins the escaped quoted strings with commas using |
255 | | // JoinStrings(). Note that JoinCSVLineWithDelimiter() will not necessarily |
256 | | // return the same string originally passed in to |
257 | | // SplitCSVLineWithDelimiter(), since SplitCSVLineWithDelimiter() can handle |
258 | | // gratuitous spacing and quoting. 'output' must point to an empty string. |
259 | | // |
260 | | // Example: |
261 | | // [Google], [x], [Buchheit, Paul], [string with " quoite in it], [ space ] |
262 | | // ---> [Google,x,"Buchheit, Paul","string with "" quote in it"," space "] |
263 | | // |
264 | | // JoinCSVLine() |
265 | | // A convenience wrapper around JoinCSVLineWithDelimiter which uses |
266 | | // ',' as the delimiter. |
267 | | // ---------------------------------------------------------------------- |
268 | | void JoinCSVLine(const vector<string>& original_cols, string* output); |
269 | | string JoinCSVLine(const vector<string>& original_cols); |
270 | | void JoinCSVLineWithDelimiter(const vector<string>& original_cols, char delimiter, string* output); |
271 | | |
272 | | // ---------------------------------------------------------------------- |
273 | | // JoinElements() |
274 | | // This merges a container of any type supported by StrAppend() with delim |
275 | | // inserted as separators between components. This is essentially a |
276 | | // templatize version of JoinUsingToBuffer(). |
277 | | // |
278 | | // JoinElementsIterator() |
279 | | // Same as JoinElements(), except that the input elements are specified |
280 | | // with a pair of forward iterators. |
281 | | // ---------------------------------------------------------------------- |
282 | | |
283 | | template <class ITERATOR> |
284 | 0 | void JoinElementsIterator(ITERATOR first, ITERATOR last, StringPiece delim, string* result) { |
285 | 0 | result->clear(); |
286 | 0 | for (ITERATOR it = first; it != last; ++it) { |
287 | 0 | if (it != first) { |
288 | 0 | StrAppend(result, delim); |
289 | 0 | } |
290 | 0 | StrAppend(result, *it); |
291 | 0 | } |
292 | 0 | } |
293 | | |
294 | | template <class ITERATOR> |
295 | | string JoinElementsIterator(ITERATOR first, ITERATOR last, StringPiece delim) { |
296 | | string result; |
297 | | JoinElementsIterator(first, last, delim, &result); |
298 | | return result; |
299 | | } |
300 | | |
301 | | template <class CONTAINER> |
302 | 0 | void JoinElements(const CONTAINER& components, StringPiece delim, string* result) { |
303 | 0 | JoinElementsIterator(components.begin(), components.end(), delim, result); |
304 | 0 | } |
305 | | |
306 | | template <class CONTAINER> |
307 | 0 | string JoinElements(const CONTAINER& components, StringPiece delim) { |
308 | 0 | string result; |
309 | 0 | JoinElements(components, delim, &result); |
310 | 0 | return result; |
311 | 0 | } |
312 | | |
313 | | template <class CONTAINER> |
314 | | void JoinInts(const CONTAINER& components, const char* delim, string* result) { |
315 | | JoinElements(components, delim, result); |
316 | | } |
317 | | |
318 | | template <class CONTAINER> |
319 | | string JoinInts(const CONTAINER& components, const char* delim) { |
320 | | return JoinElements(components, delim); |
321 | | } |