• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 //
2 // Copyright 2017 The Abseil Authors.
3 //
4 // Licensed under the Apache License, Version 2.0 (the "License");
5 // you may not use this file except in compliance with the License.
6 // You may obtain a copy of the License at
7 //
8 //      https://www.apache.org/licenses/LICENSE-2.0
9 //
10 // Unless required by applicable law or agreed to in writing, software
11 // distributed under the License is distributed on an "AS IS" BASIS,
12 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 // See the License for the specific language governing permissions and
14 // limitations under the License.
15 //
16 // -----------------------------------------------------------------------------
17 // File: str_join.h
18 // -----------------------------------------------------------------------------
19 //
20 // This header file contains functions for joining a range of elements and
21 // returning the result as a std::string. StrJoin operations are specified by
22 // passing a range, a separator string to use between the elements joined, and
23 // an optional Formatter responsible for converting each argument in the range
24 // to a string. If omitted, a default `AlphaNumFormatter()` is called on the
25 // elements to be joined, using the same formatting that `absl::StrCat()` uses.
26 // This package defines a number of default formatters, and you can define your
27 // own implementations.
28 //
29 // Ranges are specified by passing a container with `std::begin()` and
30 // `std::end()` iterators, container-specific `begin()` and `end()` iterators, a
31 // brace-initialized `std::initializer_list`, or a `std::tuple` of heterogeneous
32 // objects. The separator string is specified as an `absl::string_view`.
33 //
34 // Because the default formatter uses the `absl::AlphaNum` class,
35 // `absl::StrJoin()`, like `absl::StrCat()`, will work out-of-the-box on
36 // collections of strings, ints, floats, doubles, etc.
37 //
38 // Example:
39 //
40 //   std::vector<std::string> v = {"foo", "bar", "baz"};
41 //   std::string s = absl::StrJoin(v, "-");
42 //   EXPECT_EQ("foo-bar-baz", s);
43 //
44 // See comments on the `absl::StrJoin()` function for more examples.
45 
46 #ifndef ABSL_STRINGS_STR_JOIN_H_
47 #define ABSL_STRINGS_STR_JOIN_H_
48 
49 #include <cstdio>
50 #include <cstring>
51 #include <initializer_list>
52 #include <iterator>
53 #include <string>
54 #include <tuple>
55 #include <type_traits>
56 #include <utility>
57 
58 #include "absl/base/macros.h"
59 #include "absl/strings/internal/str_join_internal.h"
60 #include "absl/strings/string_view.h"
61 
62 namespace absl {
63 ABSL_NAMESPACE_BEGIN
64 
65 // -----------------------------------------------------------------------------
66 // Concept: Formatter
67 // -----------------------------------------------------------------------------
68 //
69 // A Formatter is a function object that is responsible for formatting its
70 // argument as a string and appending it to a given output std::string.
71 // Formatters may be implemented as function objects, lambdas, or normal
72 // functions. You may provide your own Formatter to enable `absl::StrJoin()` to
73 // work with arbitrary types.
74 //
75 // The following is an example of a custom Formatter that simply uses
76 // `std::to_string()` to format an integer as a std::string.
77 //
78 //   struct MyFormatter {
79 //     void operator()(std::string* out, int i) const {
80 //       out->append(std::to_string(i));
81 //     }
82 //   };
83 //
84 // You would use the above formatter by passing an instance of it as the final
85 // argument to `absl::StrJoin()`:
86 //
87 //   std::vector<int> v = {1, 2, 3, 4};
88 //   std::string s = absl::StrJoin(v, "-", MyFormatter());
89 //   EXPECT_EQ("1-2-3-4", s);
90 //
91 // The following standard formatters are provided within this file:
92 //
93 // - `AlphaNumFormatter()` (the default)
94 // - `StreamFormatter()`
95 // - `PairFormatter()`
96 // - `DereferenceFormatter()`
97 
98 // AlphaNumFormatter()
99 //
100 // Default formatter used if none is specified. Uses `absl::AlphaNum` to convert
101 // numeric arguments to strings.
AlphaNumFormatter()102 inline strings_internal::AlphaNumFormatterImpl AlphaNumFormatter() {
103   return strings_internal::AlphaNumFormatterImpl();
104 }
105 
106 // StreamFormatter()
107 //
108 // Formats its argument using the << operator.
StreamFormatter()109 inline strings_internal::StreamFormatterImpl StreamFormatter() {
110   return strings_internal::StreamFormatterImpl();
111 }
112 
113 // Function Template: PairFormatter(Formatter, absl::string_view, Formatter)
114 //
115 // Formats a `std::pair` by putting a given separator between the pair's
116 // `.first` and `.second` members. This formatter allows you to specify
117 // custom Formatters for both the first and second member of each pair.
118 template <typename FirstFormatter, typename SecondFormatter>
119 inline strings_internal::PairFormatterImpl<FirstFormatter, SecondFormatter>
PairFormatter(FirstFormatter f1,absl::string_view sep,SecondFormatter f2)120 PairFormatter(FirstFormatter f1, absl::string_view sep, SecondFormatter f2) {
121   return strings_internal::PairFormatterImpl<FirstFormatter, SecondFormatter>(
122       std::move(f1), sep, std::move(f2));
123 }
124 
125 // Function overload of PairFormatter() for using a default
126 // `AlphaNumFormatter()` for each Formatter in the pair.
127 inline strings_internal::PairFormatterImpl<
128     strings_internal::AlphaNumFormatterImpl,
129     strings_internal::AlphaNumFormatterImpl>
PairFormatter(absl::string_view sep)130 PairFormatter(absl::string_view sep) {
131   return PairFormatter(AlphaNumFormatter(), sep, AlphaNumFormatter());
132 }
133 
134 // Function Template: DereferenceFormatter(Formatter)
135 //
136 // Formats its argument by dereferencing it and then applying the given
137 // formatter. This formatter is useful for formatting a container of
138 // pointer-to-T. This pattern often shows up when joining repeated fields in
139 // protocol buffers.
140 template <typename Formatter>
DereferenceFormatter(Formatter && f)141 strings_internal::DereferenceFormatterImpl<Formatter> DereferenceFormatter(
142     Formatter&& f) {
143   return strings_internal::DereferenceFormatterImpl<Formatter>(
144       std::forward<Formatter>(f));
145 }
146 
147 // Function overload of `DereferenceFormatter()` for using a default
148 // `AlphaNumFormatter()`.
149 inline strings_internal::DereferenceFormatterImpl<
150     strings_internal::AlphaNumFormatterImpl>
DereferenceFormatter()151 DereferenceFormatter() {
152   return strings_internal::DereferenceFormatterImpl<
153       strings_internal::AlphaNumFormatterImpl>(AlphaNumFormatter());
154 }
155 
156 // -----------------------------------------------------------------------------
157 // StrJoin()
158 // -----------------------------------------------------------------------------
159 //
160 // Joins a range of elements and returns the result as a std::string.
161 // `absl::StrJoin()` takes a range, a separator string to use between the
162 // elements joined, and an optional Formatter responsible for converting each
163 // argument in the range to a string.
164 //
165 // If omitted, the default `AlphaNumFormatter()` is called on the elements to be
166 // joined.
167 //
168 // Example 1:
169 //   // Joins a collection of strings. This pattern also works with a collection
170 //   // of `absl::string_view` or even `const char*`.
171 //   std::vector<std::string> v = {"foo", "bar", "baz"};
172 //   std::string s = absl::StrJoin(v, "-");
173 //   EXPECT_EQ("foo-bar-baz", s);
174 //
175 // Example 2:
176 //   // Joins the values in the given `std::initializer_list<>` specified using
177 //   // brace initialization. This pattern also works with an initializer_list
178 //   // of ints or `absl::string_view` -- any `AlphaNum`-compatible type.
179 //   std::string s = absl::StrJoin({"foo", "bar", "baz"}, "-");
180 //   EXPECT_EQ("foo-bar-baz", s);
181 //
182 // Example 3:
183 //   // Joins a collection of ints. This pattern also works with floats,
184 //   // doubles, int64s -- any `StrCat()`-compatible type.
185 //   std::vector<int> v = {1, 2, 3, -4};
186 //   std::string s = absl::StrJoin(v, "-");
187 //   EXPECT_EQ("1-2-3--4", s);
188 //
189 // Example 4:
190 //   // Joins a collection of pointer-to-int. By default, pointers are
191 //   // dereferenced and the pointee is formatted using the default format for
192 //   // that type; such dereferencing occurs for all levels of indirection, so
193 //   // this pattern works just as well for `std::vector<int**>` as for
194 //   // `std::vector<int*>`.
195 //   int x = 1, y = 2, z = 3;
196 //   std::vector<int*> v = {&x, &y, &z};
197 //   std::string s = absl::StrJoin(v, "-");
198 //   EXPECT_EQ("1-2-3", s);
199 //
200 // Example 5:
201 //   // Dereferencing of `std::unique_ptr<>` is also supported:
202 //   std::vector<std::unique_ptr<int>> v
203 //   v.emplace_back(new int(1));
204 //   v.emplace_back(new int(2));
205 //   v.emplace_back(new int(3));
206 //   std::string s = absl::StrJoin(v, "-");
207 //   EXPECT_EQ("1-2-3", s);
208 //
209 // Example 6:
210 //   // Joins a `std::map`, with each key-value pair separated by an equals
211 //   // sign. This pattern would also work with, say, a
212 //   // `std::vector<std::pair<>>`.
213 //   std::map<std::string, int> m = {
214 //       std::make_pair("a", 1),
215 //       std::make_pair("b", 2),
216 //       std::make_pair("c", 3)};
217 //   std::string s = absl::StrJoin(m, ",", absl::PairFormatter("="));
218 //   EXPECT_EQ("a=1,b=2,c=3", s);
219 //
220 // Example 7:
221 //   // These examples show how `absl::StrJoin()` handles a few common edge
222 //   // cases:
223 //   std::vector<std::string> v_empty;
224 //   EXPECT_EQ("", absl::StrJoin(v_empty, "-"));
225 //
226 //   std::vector<std::string> v_one_item = {"foo"};
227 //   EXPECT_EQ("foo", absl::StrJoin(v_one_item, "-"));
228 //
229 //   std::vector<std::string> v_empty_string = {""};
230 //   EXPECT_EQ("", absl::StrJoin(v_empty_string, "-"));
231 //
232 //   std::vector<std::string> v_one_item_empty_string = {"a", ""};
233 //   EXPECT_EQ("a-", absl::StrJoin(v_one_item_empty_string, "-"));
234 //
235 //   std::vector<std::string> v_two_empty_string = {"", ""};
236 //   EXPECT_EQ("-", absl::StrJoin(v_two_empty_string, "-"));
237 //
238 // Example 8:
239 //   // Joins a `std::tuple<T...>` of heterogeneous types, converting each to
240 //   // a std::string using the `absl::AlphaNum` class.
241 //   std::string s = absl::StrJoin(std::make_tuple(123, "abc", 0.456), "-");
242 //   EXPECT_EQ("123-abc-0.456", s);
243 
244 template <typename Iterator, typename Formatter>
StrJoin(Iterator start,Iterator end,absl::string_view sep,Formatter && fmt)245 std::string StrJoin(Iterator start, Iterator end, absl::string_view sep,
246                     Formatter&& fmt) {
247   return strings_internal::JoinAlgorithm(start, end, sep, fmt);
248 }
249 
250 template <typename Range, typename Formatter>
StrJoin(const Range & range,absl::string_view separator,Formatter && fmt)251 std::string StrJoin(const Range& range, absl::string_view separator,
252                     Formatter&& fmt) {
253   return strings_internal::JoinRange(range, separator, fmt);
254 }
255 
256 template <typename T, typename Formatter>
StrJoin(std::initializer_list<T> il,absl::string_view separator,Formatter && fmt)257 std::string StrJoin(std::initializer_list<T> il, absl::string_view separator,
258                     Formatter&& fmt) {
259   return strings_internal::JoinRange(il, separator, fmt);
260 }
261 
262 template <typename... T, typename Formatter>
StrJoin(const std::tuple<T...> & value,absl::string_view separator,Formatter && fmt)263 std::string StrJoin(const std::tuple<T...>& value, absl::string_view separator,
264                     Formatter&& fmt) {
265   return strings_internal::JoinAlgorithm(value, separator, fmt);
266 }
267 
268 template <typename Iterator>
StrJoin(Iterator start,Iterator end,absl::string_view separator)269 std::string StrJoin(Iterator start, Iterator end, absl::string_view separator) {
270   return strings_internal::JoinRange(start, end, separator);
271 }
272 
273 template <typename Range>
StrJoin(const Range & range,absl::string_view separator)274 std::string StrJoin(const Range& range, absl::string_view separator) {
275   return strings_internal::JoinRange(range, separator);
276 }
277 
278 template <typename T>
StrJoin(std::initializer_list<T> il,absl::string_view separator)279 std::string StrJoin(std::initializer_list<T> il,
280                     absl::string_view separator) {
281   return strings_internal::JoinRange(il, separator);
282 }
283 
284 template <typename... T>
StrJoin(const std::tuple<T...> & value,absl::string_view separator)285 std::string StrJoin(const std::tuple<T...>& value,
286                     absl::string_view separator) {
287   return strings_internal::JoinAlgorithm(value, separator, AlphaNumFormatter());
288 }
289 
290 ABSL_NAMESPACE_END
291 }  // namespace absl
292 
293 #endif  // ABSL_STRINGS_STR_JOIN_H_
294