1 // Copyright (C) 2019 Google LLC
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 // http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14
15 #ifndef ICING_ABSL_PORTS_STR_JOIN_H_
16 #define ICING_ABSL_PORTS_STR_JOIN_H_
17
18 #include <string>
19 #include <string_view>
20 #include <vector>
21
22 #include "icing/absl_ports/str_cat.h"
23
24 namespace icing {
25 namespace lib {
26 namespace absl_ports {
27
28 class DefaultFormatter {
29 public:
30 template <typename T>
operator()31 std::string operator()(const T& element) {
32 return std::string(element);
33 }
34 };
35
36 class NumberFormatter {
37 public:
38 template <typename T>
operator()39 std::string operator()(const T& number) {
40 return std::to_string(number);
41 }
42 };
43
44 // A port of absl::StrJoin.
45 //
46 // Joins a range of elements and returns the result as a std::string.
47 // `absl::StrJoin()` takes a range, a separator string to use between the
48 // elements joined.
49 //
50 // A Formatter may be supplied to convert the Iterator's elements to a
51 // std::string.
52 template <typename Iterator, typename Formatter>
StrJoin(Iterator first,Iterator last,std::string_view sep,Formatter && formatter)53 std::string StrJoin(Iterator first, Iterator last, std::string_view sep,
54 Formatter&& formatter) {
55 std::string::size_type result_size = 0;
56 bool add_separator_before_element = false;
57 for (Iterator current = first; current != last; ++current) {
58 if (add_separator_before_element) {
59 result_size += sep.length();
60 }
61
62 std::string formatted = formatter(*current);
63 result_size += formatted.length();
64
65 add_separator_before_element = true;
66 }
67 // Create result with enough room to fit all operands.
68 std::string result;
69 // __resize_default_init is provided by libc++ >= 8.0 and allows us to
70 // allocate room for the content we're about to copy while avoiding the
71 // unnecessary zero-initialization that the normal std::string::resize will
72 // perform.
73 //
74 // The current absl implementation copies a null char to the character at
75 // previous_size after the call to resize_default_init due to implementation
76 // differences between libstdc++ and libc++. That behavior is NOT copied over
77 // here because the following lines are just about to overwrite that character
78 // anyways.
79 result.__resize_default_init(result_size);
80
81 add_separator_before_element = false;
82 for (char* out = &result[0]; first != last; ++first) {
83 if (add_separator_before_element) {
84 out = Append(out, sep);
85 }
86
87 std::string formatted = formatter(*first);
88 out = Append(out, formatted);
89
90 add_separator_before_element = true;
91 }
92
93 return result;
94 }
95
96 template <typename Container, typename Formatter>
StrJoin(const Container & container,std::string_view sep,Formatter && formatter)97 std::string StrJoin(const Container& container, std::string_view sep,
98 Formatter&& formatter) {
99 return absl_ports::StrJoin(std::begin(container), std::end(container), sep,
100 formatter);
101 }
102
103 template <typename Container>
StrJoin(const Container & container,std::string_view sep)104 std::string StrJoin(const Container& container, std::string_view sep) {
105 return absl_ports::StrJoin(container, sep, DefaultFormatter());
106 }
107
108 std::vector<std::string_view> StrSplit(std::string_view text,
109 std::string_view sep);
110
111 } // namespace absl_ports
112 } // namespace lib
113 } // namespace icing
114
115 #endif // ICING_ABSL_PORTS_STR_JOIN_H_
116