// // Copyright 2017 The Abseil Authors. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // https://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // // ----------------------------------------------------------------------------- // File: str_join.h // ----------------------------------------------------------------------------- // // This header file contains functions for joining a range of elements and // returning the result as a std::string. StrJoin operations are specified by // passing a range, a separator string to use between the elements joined, and // an optional Formatter responsible for converting each argument in the range // to a string. If omitted, a default `AlphaNumFormatter()` is called on the // elements to be joined, using the same formatting that `absl::StrCat()` uses. // This package defines a number of default formatters, and you can define your // own implementations. // // Ranges are specified by passing a container with `std::begin()` and // `std::end()` iterators, container-specific `begin()` and `end()` iterators, a // brace-initialized `std::initializer_list`, or a `std::tuple` of heterogeneous // objects. The separator string is specified as an `absl::string_view`. // // Because the default formatter uses the `absl::AlphaNum` class, // `absl::StrJoin()`, like `absl::StrCat()`, will work out-of-the-box on // collections of strings, ints, floats, doubles, etc. // // Example: // // std::vector v = {"foo", "bar", "baz"}; // std::string s = absl::StrJoin(v, "-"); // EXPECT_EQ("foo-bar-baz", s); // // See comments on the `absl::StrJoin()` function for more examples. #ifndef ABSL_STRINGS_STR_JOIN_H_ #define ABSL_STRINGS_STR_JOIN_H_ #include #include #include #include #include #include #include #include #include "absl/base/macros.h" #include "absl/strings/internal/str_join_internal.h" #include "absl/strings/string_view.h" namespace absl { ABSL_NAMESPACE_BEGIN // ----------------------------------------------------------------------------- // Concept: Formatter // ----------------------------------------------------------------------------- // // A Formatter is a function object that is responsible for formatting its // argument as a string and appending it to a given output std::string. // Formatters may be implemented as function objects, lambdas, or normal // functions. You may provide your own Formatter to enable `absl::StrJoin()` to // work with arbitrary types. // // The following is an example of a custom Formatter that uses // `absl::FormatDuration` to join a list of `absl::Duration`s. // // std::vector v = {absl::Seconds(1), absl::Milliseconds(10)}; // std::string s = // absl::StrJoin(v, ", ", [](std::string* out, absl::Duration dur) { // absl::StrAppend(out, absl::FormatDuration(dur)); // }); // EXPECT_EQ(s, "1s, 10ms"); // // The following standard formatters are provided within this file: // // - `AlphaNumFormatter()` (the default) // - `StreamFormatter()` // - `PairFormatter()` // - `DereferenceFormatter()` // AlphaNumFormatter() // // Default formatter used if none is specified. Uses `absl::AlphaNum` to convert // numeric arguments to strings. inline strings_internal::AlphaNumFormatterImpl AlphaNumFormatter() { return strings_internal::AlphaNumFormatterImpl(); } // StreamFormatter() // // Formats its argument using the << operator. inline strings_internal::StreamFormatterImpl StreamFormatter() { return strings_internal::StreamFormatterImpl(); } // Function Template: PairFormatter(Formatter, absl::string_view, Formatter) // // Formats a `std::pair` by putting a given separator between the pair's // `.first` and `.second` members. This formatter allows you to specify // custom Formatters for both the first and second member of each pair. template inline strings_internal::PairFormatterImpl PairFormatter(FirstFormatter f1, absl::string_view sep, SecondFormatter f2) { return strings_internal::PairFormatterImpl( std::move(f1), sep, std::move(f2)); } // Function overload of PairFormatter() for using a default // `AlphaNumFormatter()` for each Formatter in the pair. inline strings_internal::PairFormatterImpl< strings_internal::AlphaNumFormatterImpl, strings_internal::AlphaNumFormatterImpl> PairFormatter(absl::string_view sep) { return PairFormatter(AlphaNumFormatter(), sep, AlphaNumFormatter()); } // Function Template: DereferenceFormatter(Formatter) // // Formats its argument by dereferencing it and then applying the given // formatter. This formatter is useful for formatting a container of // pointer-to-T. This pattern often shows up when joining repeated fields in // protocol buffers. template strings_internal::DereferenceFormatterImpl DereferenceFormatter( Formatter&& f) { return strings_internal::DereferenceFormatterImpl( std::forward(f)); } // Function overload of `DereferenceFormatter()` for using a default // `AlphaNumFormatter()`. inline strings_internal::DereferenceFormatterImpl< strings_internal::AlphaNumFormatterImpl> DereferenceFormatter() { return strings_internal::DereferenceFormatterImpl< strings_internal::AlphaNumFormatterImpl>(AlphaNumFormatter()); } // ----------------------------------------------------------------------------- // StrJoin() // ----------------------------------------------------------------------------- // // Joins a range of elements and returns the result as a std::string. // `absl::StrJoin()` takes a range, a separator string to use between the // elements joined, and an optional Formatter responsible for converting each // argument in the range to a string. // // If omitted, the default `AlphaNumFormatter()` is called on the elements to be // joined. // // Example 1: // // Joins a collection of strings. This pattern also works with a collection // // of `absl::string_view` or even `const char*`. // std::vector v = {"foo", "bar", "baz"}; // std::string s = absl::StrJoin(v, "-"); // EXPECT_EQ(s, "foo-bar-baz"); // // Example 2: // // Joins the values in the given `std::initializer_list<>` specified using // // brace initialization. This pattern also works with an initializer_list // // of ints or `absl::string_view` -- any `AlphaNum`-compatible type. // std::string s = absl::StrJoin({"foo", "bar", "baz"}, "-"); // EXPECT_EQs, "foo-bar-baz"); // // Example 3: // // Joins a collection of ints. This pattern also works with floats, // // doubles, int64s -- any `StrCat()`-compatible type. // std::vector v = {1, 2, 3, -4}; // std::string s = absl::StrJoin(v, "-"); // EXPECT_EQ(s, "1-2-3--4"); // // Example 4: // // Joins a collection of pointer-to-int. By default, pointers are // // dereferenced and the pointee is formatted using the default format for // // that type; such dereferencing occurs for all levels of indirection, so // // this pattern works just as well for `std::vector` as for // // `std::vector`. // int x = 1, y = 2, z = 3; // std::vector v = {&x, &y, &z}; // std::string s = absl::StrJoin(v, "-"); // EXPECT_EQ(s, "1-2-3"); // // Example 5: // // Dereferencing of `std::unique_ptr<>` is also supported: // std::vector> v // v.emplace_back(new int(1)); // v.emplace_back(new int(2)); // v.emplace_back(new int(3)); // std::string s = absl::StrJoin(v, "-"); // EXPECT_EQ(s, "1-2-3"); // // Example 6: // // Joins a `std::map`, with each key-value pair separated by an equals // // sign. This pattern would also work with, say, a // // `std::vector>`. // std::map m = { // {"a", 1}, // {"b", 2}, // {"c", 3}}; // std::string s = absl::StrJoin(m, ",", absl::PairFormatter("=")); // EXPECT_EQ(s, "a=1,b=2,c=3"); // // Example 7: // // These examples show how `absl::StrJoin()` handles a few common edge // // cases: // std::vector v_empty; // EXPECT_EQ(absl::StrJoin(v_empty, "-"), ""); // // std::vector v_one_item = {"foo"}; // EXPECT_EQ(absl::StrJoin(v_one_item, "-"), "foo"); // // std::vector v_empty_string = {""}; // EXPECT_EQ(absl::StrJoin(v_empty_string, "-"), ""); // // std::vector v_one_item_empty_string = {"a", ""}; // EXPECT_EQ(absl::StrJoin(v_one_item_empty_string, "-"), "a-"); // // std::vector v_two_empty_string = {"", ""}; // EXPECT_EQ(absl::StrJoin(v_two_empty_string, "-"), "-"); // // Example 8: // // Joins a `std::tuple` of heterogeneous types, converting each to // // a std::string using the `absl::AlphaNum` class. // std::string s = absl::StrJoin(std::make_tuple(123, "abc", 0.456), "-"); // EXPECT_EQ(s, "123-abc-0.456"); template std::string StrJoin(Iterator start, Iterator end, absl::string_view sep, Formatter&& fmt) { return strings_internal::JoinAlgorithm(start, end, sep, fmt); } template std::string StrJoin(const Range& range, absl::string_view separator, Formatter&& fmt) { return strings_internal::JoinRange(range, separator, fmt); } template ::value>::type> std::string StrJoin(std::initializer_list il, absl::string_view separator, Formatter&& fmt) { return strings_internal::JoinRange(il, separator, fmt); } template inline std::string StrJoin(std::initializer_list il, absl::string_view separator, Formatter&& fmt) { return strings_internal::JoinRange(il, separator, fmt); } template std::string StrJoin(const std::tuple& value, absl::string_view separator, Formatter&& fmt) { return strings_internal::JoinAlgorithm(value, separator, fmt); } template std::string StrJoin(Iterator start, Iterator end, absl::string_view separator) { return strings_internal::JoinRange(start, end, separator); } template std::string StrJoin(const Range& range, absl::string_view separator) { return strings_internal::JoinRange(range, separator); } template ::value>::type> std::string StrJoin(std::initializer_list il, absl::string_view separator) { return strings_internal::JoinRange(il, separator); } inline std::string StrJoin(std::initializer_list il, absl::string_view separator) { return strings_internal::JoinRange(il, separator); } template std::string StrJoin(const std::tuple& value, absl::string_view separator) { return strings_internal::JoinTuple(value, separator, std::index_sequence_for{}); } ABSL_NAMESPACE_END } // namespace absl #endif // ABSL_STRINGS_STR_JOIN_H_