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