123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301 |
- //
- // 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<std::string> 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 <cstdio>
- #include <cstring>
- #include <initializer_list>
- #include <iterator>
- #include <string>
- #include <tuple>
- #include <type_traits>
- #include <utility>
- #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<absl::Duration> 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 <typename FirstFormatter, typename SecondFormatter>
- inline strings_internal::PairFormatterImpl<FirstFormatter, SecondFormatter>
- PairFormatter(FirstFormatter f1, absl::string_view sep, SecondFormatter f2) {
- return strings_internal::PairFormatterImpl<FirstFormatter, SecondFormatter>(
- 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 <typename Formatter>
- strings_internal::DereferenceFormatterImpl<Formatter> DereferenceFormatter(
- Formatter&& f) {
- return strings_internal::DereferenceFormatterImpl<Formatter>(
- std::forward<Formatter>(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<std::string> 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<int> 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<int**>` as for
- // // `std::vector<int*>`.
- // int x = 1, y = 2, z = 3;
- // std::vector<int*> 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<std::unique_ptr<int>> 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::pair<>>`.
- // std::map<std::string, int> 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<std::string> v_empty;
- // EXPECT_EQ(absl::StrJoin(v_empty, "-"), "");
- //
- // std::vector<std::string> v_one_item = {"foo"};
- // EXPECT_EQ(absl::StrJoin(v_one_item, "-"), "foo");
- //
- // std::vector<std::string> v_empty_string = {""};
- // EXPECT_EQ(absl::StrJoin(v_empty_string, "-"), "");
- //
- // std::vector<std::string> v_one_item_empty_string = {"a", ""};
- // EXPECT_EQ(absl::StrJoin(v_one_item_empty_string, "-"), "a-");
- //
- // std::vector<std::string> v_two_empty_string = {"", ""};
- // EXPECT_EQ(absl::StrJoin(v_two_empty_string, "-"), "-");
- //
- // Example 8:
- // // Joins a `std::tuple<T...>` 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 <typename Iterator, typename Formatter>
- std::string StrJoin(Iterator start, Iterator end, absl::string_view sep,
- Formatter&& fmt) {
- return strings_internal::JoinAlgorithm(start, end, sep, fmt);
- }
- template <typename Range, typename Formatter>
- std::string StrJoin(const Range& range, absl::string_view separator,
- Formatter&& fmt) {
- return strings_internal::JoinRange(range, separator, fmt);
- }
- template <typename T, typename Formatter,
- typename = typename std::enable_if<
- !std::is_convertible<T, absl::string_view>::value>::type>
- std::string StrJoin(std::initializer_list<T> il, absl::string_view separator,
- Formatter&& fmt) {
- return strings_internal::JoinRange(il, separator, fmt);
- }
- template <typename Formatter>
- inline std::string StrJoin(std::initializer_list<absl::string_view> il,
- absl::string_view separator, Formatter&& fmt) {
- return strings_internal::JoinRange(il, separator, fmt);
- }
- template <typename... T, typename Formatter>
- std::string StrJoin(const std::tuple<T...>& value, absl::string_view separator,
- Formatter&& fmt) {
- return strings_internal::JoinAlgorithm(value, separator, fmt);
- }
- template <typename Iterator>
- std::string StrJoin(Iterator start, Iterator end, absl::string_view separator) {
- return strings_internal::JoinRange(start, end, separator);
- }
- template <typename Range>
- std::string StrJoin(const Range& range, absl::string_view separator) {
- return strings_internal::JoinRange(range, separator);
- }
- template <typename T, typename = typename std::enable_if<!std::is_convertible<
- T, absl::string_view>::value>::type>
- std::string StrJoin(std::initializer_list<T> il, absl::string_view separator) {
- return strings_internal::JoinRange(il, separator);
- }
- inline std::string StrJoin(std::initializer_list<absl::string_view> il,
- absl::string_view separator) {
- return strings_internal::JoinRange(il, separator);
- }
- template <typename... T>
- std::string StrJoin(const std::tuple<T...>& value,
- absl::string_view separator) {
- return strings_internal::JoinTuple(value, separator,
- std::index_sequence_for<T...>{});
- }
- ABSL_NAMESPACE_END
- } // namespace absl
- #endif // ABSL_STRINGS_STR_JOIN_H_
|