blob: ae5731a42b3d581cf7c4dcdea60ea2f5a11fdc48 [file] [log] [blame]
Austin Schuh36244a12019-09-21 17:52:38 -07001//
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
62namespace absl {
Austin Schuhb4691e92020-12-31 12:37:18 -080063ABSL_NAMESPACE_BEGIN
Austin Schuh36244a12019-09-21 17:52:38 -070064
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.
102inline strings_internal::AlphaNumFormatterImpl AlphaNumFormatter() {
103 return strings_internal::AlphaNumFormatterImpl();
104}
105
106// StreamFormatter()
107//
108// Formats its argument using the << operator.
109inline 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.
118template <typename FirstFormatter, typename SecondFormatter>
119inline strings_internal::PairFormatterImpl<FirstFormatter, SecondFormatter>
120PairFormatter(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.
127inline strings_internal::PairFormatterImpl<
128 strings_internal::AlphaNumFormatterImpl,
129 strings_internal::AlphaNumFormatterImpl>
130PairFormatter(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.
140template <typename Formatter>
141strings_internal::DereferenceFormatterImpl<Formatter> DereferenceFormatter(
142 Formatter&& f) {
143 return strings_internal::DereferenceFormatterImpl<Formatter>(
144 std::forward<Formatter>(f));
145}
146
147// Function overload of `DererefenceFormatter()` for using a default
148// `AlphaNumFormatter()`.
149inline strings_internal::DereferenceFormatterImpl<
150 strings_internal::AlphaNumFormatterImpl>
151DereferenceFormatter() {
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
244template <typename Iterator, typename Formatter>
245std::string StrJoin(Iterator start, Iterator end, absl::string_view sep,
246 Formatter&& fmt) {
247 return strings_internal::JoinAlgorithm(start, end, sep, fmt);
248}
249
250template <typename Range, typename Formatter>
251std::string StrJoin(const Range& range, absl::string_view separator,
252 Formatter&& fmt) {
253 return strings_internal::JoinRange(range, separator, fmt);
254}
255
256template <typename T, typename Formatter>
257std::string StrJoin(std::initializer_list<T> il, absl::string_view separator,
258 Formatter&& fmt) {
259 return strings_internal::JoinRange(il, separator, fmt);
260}
261
262template <typename... T, typename Formatter>
263std::string StrJoin(const std::tuple<T...>& value, absl::string_view separator,
264 Formatter&& fmt) {
265 return strings_internal::JoinAlgorithm(value, separator, fmt);
266}
267
268template <typename Iterator>
269std::string StrJoin(Iterator start, Iterator end, absl::string_view separator) {
270 return strings_internal::JoinRange(start, end, separator);
271}
272
273template <typename Range>
274std::string StrJoin(const Range& range, absl::string_view separator) {
275 return strings_internal::JoinRange(range, separator);
276}
277
278template <typename T>
279std::string StrJoin(std::initializer_list<T> il,
280 absl::string_view separator) {
281 return strings_internal::JoinRange(il, separator);
282}
283
284template <typename... T>
285std::string StrJoin(const std::tuple<T...>& value,
286 absl::string_view separator) {
287 return strings_internal::JoinAlgorithm(value, separator, AlphaNumFormatter());
288}
289
Austin Schuhb4691e92020-12-31 12:37:18 -0800290ABSL_NAMESPACE_END
Austin Schuh36244a12019-09-21 17:52:38 -0700291} // namespace absl
292
293#endif // ABSL_STRINGS_STR_JOIN_H_