str_join.h (11853B)
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 uses 76 // `absl::FormatDuration` to join a list of `absl::Duration`s. 77 // 78 // std::vector<absl::Duration> v = {absl::Seconds(1), absl::Milliseconds(10)}; 79 // std::string s = 80 // absl::StrJoin(v, ", ", [](std::string* out, absl::Duration dur) { 81 // absl::StrAppend(out, absl::FormatDuration(dur)); 82 // }); 83 // EXPECT_EQ(s, "1s, 10ms"); 84 // 85 // The following standard formatters are provided within this file: 86 // 87 // - `AlphaNumFormatter()` (the default) 88 // - `StreamFormatter()` 89 // - `PairFormatter()` 90 // - `DereferenceFormatter()` 91 92 // AlphaNumFormatter() 93 // 94 // Default formatter used if none is specified. Uses `absl::AlphaNum` to convert 95 // numeric arguments to strings. 96 inline strings_internal::AlphaNumFormatterImpl AlphaNumFormatter() { 97 return strings_internal::AlphaNumFormatterImpl(); 98 } 99 100 // StreamFormatter() 101 // 102 // Formats its argument using the << operator. 103 inline strings_internal::StreamFormatterImpl StreamFormatter() { 104 return strings_internal::StreamFormatterImpl(); 105 } 106 107 // Function Template: PairFormatter(Formatter, absl::string_view, Formatter) 108 // 109 // Formats a `std::pair` by putting a given separator between the pair's 110 // `.first` and `.second` members. This formatter allows you to specify 111 // custom Formatters for both the first and second member of each pair. 112 template <typename FirstFormatter, typename SecondFormatter> 113 inline strings_internal::PairFormatterImpl<FirstFormatter, SecondFormatter> 114 PairFormatter(FirstFormatter f1, absl::string_view sep, SecondFormatter f2) { 115 return strings_internal::PairFormatterImpl<FirstFormatter, SecondFormatter>( 116 std::move(f1), sep, std::move(f2)); 117 } 118 119 // Function overload of PairFormatter() for using a default 120 // `AlphaNumFormatter()` for each Formatter in the pair. 121 inline strings_internal::PairFormatterImpl< 122 strings_internal::AlphaNumFormatterImpl, 123 strings_internal::AlphaNumFormatterImpl> 124 PairFormatter(absl::string_view sep) { 125 return PairFormatter(AlphaNumFormatter(), sep, AlphaNumFormatter()); 126 } 127 128 // Function Template: DereferenceFormatter(Formatter) 129 // 130 // Formats its argument by dereferencing it and then applying the given 131 // formatter. This formatter is useful for formatting a container of 132 // pointer-to-T. This pattern often shows up when joining repeated fields in 133 // protocol buffers. 134 template <typename Formatter> 135 strings_internal::DereferenceFormatterImpl<Formatter> DereferenceFormatter( 136 Formatter&& f) { 137 return strings_internal::DereferenceFormatterImpl<Formatter>( 138 std::forward<Formatter>(f)); 139 } 140 141 // Function overload of `DereferenceFormatter()` for using a default 142 // `AlphaNumFormatter()`. 143 inline strings_internal::DereferenceFormatterImpl< 144 strings_internal::AlphaNumFormatterImpl> 145 DereferenceFormatter() { 146 return strings_internal::DereferenceFormatterImpl< 147 strings_internal::AlphaNumFormatterImpl>(AlphaNumFormatter()); 148 } 149 150 // ----------------------------------------------------------------------------- 151 // StrJoin() 152 // ----------------------------------------------------------------------------- 153 // 154 // Joins a range of elements and returns the result as a std::string. 155 // `absl::StrJoin()` takes a range, a separator string to use between the 156 // elements joined, and an optional Formatter responsible for converting each 157 // argument in the range to a string. 158 // 159 // If omitted, the default `AlphaNumFormatter()` is called on the elements to be 160 // joined. 161 // 162 // Example 1: 163 // // Joins a collection of strings. This pattern also works with a collection 164 // // of `absl::string_view` or even `const char*`. 165 // std::vector<std::string> v = {"foo", "bar", "baz"}; 166 // std::string s = absl::StrJoin(v, "-"); 167 // EXPECT_EQ(s, "foo-bar-baz"); 168 // 169 // Example 2: 170 // // Joins the values in the given `std::initializer_list<>` specified using 171 // // brace initialization. This pattern also works with an initializer_list 172 // // of ints or `absl::string_view` -- any `AlphaNum`-compatible type. 173 // std::string s = absl::StrJoin({"foo", "bar", "baz"}, "-"); 174 // EXPECT_EQs, "foo-bar-baz"); 175 // 176 // Example 3: 177 // // Joins a collection of ints. This pattern also works with floats, 178 // // doubles, int64s -- any `StrCat()`-compatible type. 179 // std::vector<int> v = {1, 2, 3, -4}; 180 // std::string s = absl::StrJoin(v, "-"); 181 // EXPECT_EQ(s, "1-2-3--4"); 182 // 183 // Example 4: 184 // // Joins a collection of pointer-to-int. By default, pointers are 185 // // dereferenced and the pointee is formatted using the default format for 186 // // that type; such dereferencing occurs for all levels of indirection, so 187 // // this pattern works just as well for `std::vector<int**>` as for 188 // // `std::vector<int*>`. 189 // int x = 1, y = 2, z = 3; 190 // std::vector<int*> v = {&x, &y, &z}; 191 // std::string s = absl::StrJoin(v, "-"); 192 // EXPECT_EQ(s, "1-2-3"); 193 // 194 // Example 5: 195 // // Dereferencing of `std::unique_ptr<>` is also supported: 196 // std::vector<std::unique_ptr<int>> v 197 // v.emplace_back(new int(1)); 198 // v.emplace_back(new int(2)); 199 // v.emplace_back(new int(3)); 200 // std::string s = absl::StrJoin(v, "-"); 201 // EXPECT_EQ(s, "1-2-3"); 202 // 203 // Example 6: 204 // // Joins a `std::map`, with each key-value pair separated by an equals 205 // // sign. This pattern would also work with, say, a 206 // // `std::vector<std::pair<>>`. 207 // std::map<std::string, int> m = { 208 // {"a", 1}, 209 // {"b", 2}, 210 // {"c", 3}}; 211 // std::string s = absl::StrJoin(m, ",", absl::PairFormatter("=")); 212 // EXPECT_EQ(s, "a=1,b=2,c=3"); 213 // 214 // Example 7: 215 // // These examples show how `absl::StrJoin()` handles a few common edge 216 // // cases: 217 // std::vector<std::string> v_empty; 218 // EXPECT_EQ(absl::StrJoin(v_empty, "-"), ""); 219 // 220 // std::vector<std::string> v_one_item = {"foo"}; 221 // EXPECT_EQ(absl::StrJoin(v_one_item, "-"), "foo"); 222 // 223 // std::vector<std::string> v_empty_string = {""}; 224 // EXPECT_EQ(absl::StrJoin(v_empty_string, "-"), ""); 225 // 226 // std::vector<std::string> v_one_item_empty_string = {"a", ""}; 227 // EXPECT_EQ(absl::StrJoin(v_one_item_empty_string, "-"), "a-"); 228 // 229 // std::vector<std::string> v_two_empty_string = {"", ""}; 230 // EXPECT_EQ(absl::StrJoin(v_two_empty_string, "-"), "-"); 231 // 232 // Example 8: 233 // // Joins a `std::tuple<T...>` of heterogeneous types, converting each to 234 // // a std::string using the `absl::AlphaNum` class. 235 // std::string s = absl::StrJoin(std::make_tuple(123, "abc", 0.456), "-"); 236 // EXPECT_EQ(s, "123-abc-0.456"); 237 238 template <typename Iterator, typename Formatter> 239 std::string StrJoin(Iterator start, Iterator end, absl::string_view sep, 240 Formatter&& fmt) { 241 return strings_internal::JoinAlgorithm(start, end, sep, fmt); 242 } 243 244 template <typename Range, typename Formatter> 245 std::string StrJoin(const Range& range, absl::string_view separator, 246 Formatter&& fmt) { 247 return strings_internal::JoinRange(range, separator, fmt); 248 } 249 250 template <typename T, typename Formatter, 251 typename = typename std::enable_if< 252 !std::is_convertible<T, absl::string_view>::value>::type> 253 std::string StrJoin(std::initializer_list<T> il, absl::string_view separator, 254 Formatter&& fmt) { 255 return strings_internal::JoinRange(il, separator, fmt); 256 } 257 258 template <typename Formatter> 259 inline std::string StrJoin(std::initializer_list<absl::string_view> il, 260 absl::string_view separator, Formatter&& fmt) { 261 return strings_internal::JoinRange(il, separator, fmt); 262 } 263 264 template <typename... T, typename Formatter> 265 std::string StrJoin(const std::tuple<T...>& value, absl::string_view separator, 266 Formatter&& fmt) { 267 return strings_internal::JoinAlgorithm(value, separator, fmt); 268 } 269 270 template <typename Iterator> 271 std::string StrJoin(Iterator start, Iterator end, absl::string_view separator) { 272 return strings_internal::JoinRange(start, end, separator); 273 } 274 275 template <typename Range> 276 std::string StrJoin(const Range& range, absl::string_view separator) { 277 return strings_internal::JoinRange(range, separator); 278 } 279 280 template <typename T, typename = typename std::enable_if<!std::is_convertible< 281 T, absl::string_view>::value>::type> 282 std::string StrJoin(std::initializer_list<T> il, absl::string_view separator) { 283 return strings_internal::JoinRange(il, separator); 284 } 285 286 inline std::string StrJoin(std::initializer_list<absl::string_view> il, 287 absl::string_view separator) { 288 return strings_internal::JoinRange(il, separator); 289 } 290 291 template <typename... T> 292 std::string StrJoin(const std::tuple<T...>& value, 293 absl::string_view separator) { 294 return strings_internal::JoinTuple(value, separator, 295 std::index_sequence_for<T...>{}); 296 } 297 298 ABSL_NAMESPACE_END 299 } // namespace absl 300 301 #endif // ABSL_STRINGS_STR_JOIN_H_