str_join.h 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287
  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 TString. 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 `y_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 `y_absl::string_view`.
  33. //
  34. // Because the default formatter uses the `y_absl::AlphaNum` class,
  35. // `y_absl::StrJoin()`, like `y_absl::StrCat()`, will work out-of-the-box on
  36. // collections of strings, ints, floats, doubles, etc.
  37. //
  38. // Example:
  39. //
  40. // std::vector<TString> v = {"foo", "bar", "baz"};
  41. // TString s = y_absl::StrJoin(v, "-");
  42. // EXPECT_EQ("foo-bar-baz", s);
  43. //
  44. // See comments on the `y_absl::StrJoin()` function for more examples.
  45. #ifndef Y_ABSL_STRINGS_STR_JOIN_H_
  46. #define Y_ABSL_STRINGS_STR_JOIN_H_
  47. #include <cstdio>
  48. #include <cstring>
  49. #include <initializer_list>
  50. #include <iterator>
  51. #include <util/generic/string.h>
  52. #include <tuple>
  53. #include <type_traits>
  54. #include <utility>
  55. #include "y_absl/base/macros.h"
  56. #include "y_absl/strings/internal/str_join_internal.h"
  57. #include "y_absl/strings/string_view.h"
  58. namespace y_absl {
  59. Y_ABSL_NAMESPACE_BEGIN
  60. // -----------------------------------------------------------------------------
  61. // Concept: Formatter
  62. // -----------------------------------------------------------------------------
  63. //
  64. // A Formatter is a function object that is responsible for formatting its
  65. // argument as a string and appending it to a given output TString.
  66. // Formatters may be implemented as function objects, lambdas, or normal
  67. // functions. You may provide your own Formatter to enable `y_absl::StrJoin()` to
  68. // work with arbitrary types.
  69. //
  70. // The following is an example of a custom Formatter that uses
  71. // `y_absl::FormatDuration` to join a list of `y_absl::Duration`s.
  72. //
  73. // std::vector<y_absl::Duration> v = {y_absl::Seconds(1), y_absl::Milliseconds(10)};
  74. // TString s =
  75. // y_absl::StrJoin(v, ", ", [](TString* out, y_absl::Duration dur) {
  76. // y_absl::StrAppend(out, y_absl::FormatDuration(dur));
  77. // });
  78. // EXPECT_EQ("1s, 10ms", s);
  79. //
  80. // The following standard formatters are provided within this file:
  81. //
  82. // - `AlphaNumFormatter()` (the default)
  83. // - `StreamFormatter()`
  84. // - `PairFormatter()`
  85. // - `DereferenceFormatter()`
  86. // AlphaNumFormatter()
  87. //
  88. // Default formatter used if none is specified. Uses `y_absl::AlphaNum` to convert
  89. // numeric arguments to strings.
  90. inline strings_internal::AlphaNumFormatterImpl AlphaNumFormatter() {
  91. return strings_internal::AlphaNumFormatterImpl();
  92. }
  93. // StreamFormatter()
  94. //
  95. // Formats its argument using the << operator.
  96. inline strings_internal::StreamFormatterImpl StreamFormatter() {
  97. return strings_internal::StreamFormatterImpl();
  98. }
  99. // Function Template: PairFormatter(Formatter, y_absl::string_view, Formatter)
  100. //
  101. // Formats a `std::pair` by putting a given separator between the pair's
  102. // `.first` and `.second` members. This formatter allows you to specify
  103. // custom Formatters for both the first and second member of each pair.
  104. template <typename FirstFormatter, typename SecondFormatter>
  105. inline strings_internal::PairFormatterImpl<FirstFormatter, SecondFormatter>
  106. PairFormatter(FirstFormatter f1, y_absl::string_view sep, SecondFormatter f2) {
  107. return strings_internal::PairFormatterImpl<FirstFormatter, SecondFormatter>(
  108. std::move(f1), sep, std::move(f2));
  109. }
  110. // Function overload of PairFormatter() for using a default
  111. // `AlphaNumFormatter()` for each Formatter in the pair.
  112. inline strings_internal::PairFormatterImpl<
  113. strings_internal::AlphaNumFormatterImpl,
  114. strings_internal::AlphaNumFormatterImpl>
  115. PairFormatter(y_absl::string_view sep) {
  116. return PairFormatter(AlphaNumFormatter(), sep, AlphaNumFormatter());
  117. }
  118. // Function Template: DereferenceFormatter(Formatter)
  119. //
  120. // Formats its argument by dereferencing it and then applying the given
  121. // formatter. This formatter is useful for formatting a container of
  122. // pointer-to-T. This pattern often shows up when joining repeated fields in
  123. // protocol buffers.
  124. template <typename Formatter>
  125. strings_internal::DereferenceFormatterImpl<Formatter> DereferenceFormatter(
  126. Formatter&& f) {
  127. return strings_internal::DereferenceFormatterImpl<Formatter>(
  128. std::forward<Formatter>(f));
  129. }
  130. // Function overload of `DereferenceFormatter()` for using a default
  131. // `AlphaNumFormatter()`.
  132. inline strings_internal::DereferenceFormatterImpl<
  133. strings_internal::AlphaNumFormatterImpl>
  134. DereferenceFormatter() {
  135. return strings_internal::DereferenceFormatterImpl<
  136. strings_internal::AlphaNumFormatterImpl>(AlphaNumFormatter());
  137. }
  138. // -----------------------------------------------------------------------------
  139. // StrJoin()
  140. // -----------------------------------------------------------------------------
  141. //
  142. // Joins a range of elements and returns the result as a TString.
  143. // `y_absl::StrJoin()` takes a range, a separator string to use between the
  144. // elements joined, and an optional Formatter responsible for converting each
  145. // argument in the range to a string.
  146. //
  147. // If omitted, the default `AlphaNumFormatter()` is called on the elements to be
  148. // joined.
  149. //
  150. // Example 1:
  151. // // Joins a collection of strings. This pattern also works with a collection
  152. // // of `y_absl::string_view` or even `const char*`.
  153. // std::vector<TString> v = {"foo", "bar", "baz"};
  154. // TString s = y_absl::StrJoin(v, "-");
  155. // EXPECT_EQ("foo-bar-baz", s);
  156. //
  157. // Example 2:
  158. // // Joins the values in the given `std::initializer_list<>` specified using
  159. // // brace initialization. This pattern also works with an initializer_list
  160. // // of ints or `y_absl::string_view` -- any `AlphaNum`-compatible type.
  161. // TString s = y_absl::StrJoin({"foo", "bar", "baz"}, "-");
  162. // EXPECT_EQ("foo-bar-baz", s);
  163. //
  164. // Example 3:
  165. // // Joins a collection of ints. This pattern also works with floats,
  166. // // doubles, int64s -- any `StrCat()`-compatible type.
  167. // std::vector<int> v = {1, 2, 3, -4};
  168. // TString s = y_absl::StrJoin(v, "-");
  169. // EXPECT_EQ("1-2-3--4", s);
  170. //
  171. // Example 4:
  172. // // Joins a collection of pointer-to-int. By default, pointers are
  173. // // dereferenced and the pointee is formatted using the default format for
  174. // // that type; such dereferencing occurs for all levels of indirection, so
  175. // // this pattern works just as well for `std::vector<int**>` as for
  176. // // `std::vector<int*>`.
  177. // int x = 1, y = 2, z = 3;
  178. // std::vector<int*> v = {&x, &y, &z};
  179. // TString s = y_absl::StrJoin(v, "-");
  180. // EXPECT_EQ("1-2-3", s);
  181. //
  182. // Example 5:
  183. // // Dereferencing of `std::unique_ptr<>` is also supported:
  184. // std::vector<std::unique_ptr<int>> v
  185. // v.emplace_back(new int(1));
  186. // v.emplace_back(new int(2));
  187. // v.emplace_back(new int(3));
  188. // TString s = y_absl::StrJoin(v, "-");
  189. // EXPECT_EQ("1-2-3", s);
  190. //
  191. // Example 6:
  192. // // Joins a `std::map`, with each key-value pair separated by an equals
  193. // // sign. This pattern would also work with, say, a
  194. // // `std::vector<std::pair<>>`.
  195. // std::map<TString, int> m = {
  196. // std::make_pair("a", 1),
  197. // std::make_pair("b", 2),
  198. // std::make_pair("c", 3)};
  199. // TString s = y_absl::StrJoin(m, ",", y_absl::PairFormatter("="));
  200. // EXPECT_EQ("a=1,b=2,c=3", s);
  201. //
  202. // Example 7:
  203. // // These examples show how `y_absl::StrJoin()` handles a few common edge
  204. // // cases:
  205. // std::vector<TString> v_empty;
  206. // EXPECT_EQ("", y_absl::StrJoin(v_empty, "-"));
  207. //
  208. // std::vector<TString> v_one_item = {"foo"};
  209. // EXPECT_EQ("foo", y_absl::StrJoin(v_one_item, "-"));
  210. //
  211. // std::vector<TString> v_empty_string = {""};
  212. // EXPECT_EQ("", y_absl::StrJoin(v_empty_string, "-"));
  213. //
  214. // std::vector<TString> v_one_item_empty_string = {"a", ""};
  215. // EXPECT_EQ("a-", y_absl::StrJoin(v_one_item_empty_string, "-"));
  216. //
  217. // std::vector<TString> v_two_empty_string = {"", ""};
  218. // EXPECT_EQ("-", y_absl::StrJoin(v_two_empty_string, "-"));
  219. //
  220. // Example 8:
  221. // // Joins a `std::tuple<T...>` of heterogeneous types, converting each to
  222. // // a TString using the `y_absl::AlphaNum` class.
  223. // TString s = y_absl::StrJoin(std::make_tuple(123, "abc", 0.456), "-");
  224. // EXPECT_EQ("123-abc-0.456", s);
  225. template <typename Iterator, typename Formatter>
  226. TString StrJoin(Iterator start, Iterator end, y_absl::string_view sep,
  227. Formatter&& fmt) {
  228. return strings_internal::JoinAlgorithm(start, end, sep, fmt);
  229. }
  230. template <typename Range, typename Formatter>
  231. TString StrJoin(const Range& range, y_absl::string_view separator,
  232. Formatter&& fmt) {
  233. return strings_internal::JoinRange(range, separator, fmt);
  234. }
  235. template <typename T, typename Formatter>
  236. TString StrJoin(std::initializer_list<T> il, y_absl::string_view separator,
  237. Formatter&& fmt) {
  238. return strings_internal::JoinRange(il, separator, fmt);
  239. }
  240. template <typename... T, typename Formatter>
  241. TString StrJoin(const std::tuple<T...>& value, y_absl::string_view separator,
  242. Formatter&& fmt) {
  243. return strings_internal::JoinAlgorithm(value, separator, fmt);
  244. }
  245. template <typename Iterator>
  246. TString StrJoin(Iterator start, Iterator end, y_absl::string_view separator) {
  247. return strings_internal::JoinRange(start, end, separator);
  248. }
  249. template <typename Range>
  250. TString StrJoin(const Range& range, y_absl::string_view separator) {
  251. return strings_internal::JoinRange(range, separator);
  252. }
  253. template <typename T>
  254. TString StrJoin(std::initializer_list<T> il,
  255. y_absl::string_view separator) {
  256. return strings_internal::JoinRange(il, separator);
  257. }
  258. template <typename... T>
  259. TString StrJoin(const std::tuple<T...>& value,
  260. y_absl::string_view separator) {
  261. return strings_internal::JoinAlgorithm(value, separator, AlphaNumFormatter());
  262. }
  263. Y_ABSL_NAMESPACE_END
  264. } // namespace y_absl
  265. #endif // Y_ABSL_STRINGS_STR_JOIN_H_