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 // This file declares INTERNAL parts of the Join API that are inlined/templated 18 // or otherwise need to be available at compile time. The main abstractions 19 // defined in this file are: 20 // 21 // - A handful of default Formatters 22 // - JoinAlgorithm() overloads 23 // - JoinRange() overloads 24 // - JoinTuple() 25 // 26 // DO NOT INCLUDE THIS FILE DIRECTLY. Use this file by including 27 // absl/strings/str_join.h 28 // 29 // IWYU pragma: private, include "absl/strings/str_join.h" 30 31 #ifndef ABSL_STRINGS_INTERNAL_STR_JOIN_INTERNAL_H_ 32 #define ABSL_STRINGS_INTERNAL_STR_JOIN_INTERNAL_H_ 33 34 #include <cstring> 35 #include <iterator> 36 #include <memory> 37 #include <string> 38 #include <type_traits> 39 #include <utility> 40 41 #include "absl/strings/internal/ostringstream.h" 42 #include "absl/strings/internal/resize_uninitialized.h" 43 #include "absl/strings/str_cat.h" 44 45 namespace absl { 46 ABSL_NAMESPACE_BEGIN 47 namespace strings_internal { 48 49 // 50 // Formatter objects 51 // 52 // The following are implementation classes for standard Formatter objects. The 53 // factory functions that users will call to create and use these formatters are 54 // defined and documented in strings/join.h. 55 // 56 57 // The default formatter. Converts alpha-numeric types to strings. 58 struct AlphaNumFormatterImpl { 59 // This template is needed in order to support passing in a dereferenced 60 // vector<bool>::iterator 61 template <typename T> operatorAlphaNumFormatterImpl62 void operator()(std::string* out, const T& t) const { 63 StrAppend(out, AlphaNum(t)); 64 } 65 operatorAlphaNumFormatterImpl66 void operator()(std::string* out, const AlphaNum& t) const { 67 StrAppend(out, t); 68 } 69 }; 70 71 // A type that's used to overload the JoinAlgorithm() function (defined below) 72 // for ranges that do not require additional formatting (e.g., a range of 73 // strings). 74 75 struct NoFormatter : public AlphaNumFormatterImpl {}; 76 77 // Formats types to strings using the << operator. 78 class StreamFormatterImpl { 79 public: 80 // The method isn't const because it mutates state. Making it const will 81 // render StreamFormatterImpl thread-hostile. 82 template <typename T> operator()83 void operator()(std::string* out, const T& t) { 84 // The stream is created lazily to avoid paying the relatively high cost 85 // of its construction when joining an empty range. 86 if (strm_) { 87 strm_->clear(); // clear the bad, fail and eof bits in case they were set 88 strm_->str(out); 89 } else { 90 strm_.reset(new strings_internal::OStringStream(out)); 91 } 92 *strm_ << t; 93 } 94 95 private: 96 std::unique_ptr<strings_internal::OStringStream> strm_; 97 }; 98 99 // Formats a std::pair<>. The 'first' member is formatted using f1_ and the 100 // 'second' member is formatted using f2_. sep_ is the separator. 101 template <typename F1, typename F2> 102 class PairFormatterImpl { 103 public: PairFormatterImpl(F1 f1,absl::string_view sep,F2 f2)104 PairFormatterImpl(F1 f1, absl::string_view sep, F2 f2) 105 : f1_(std::move(f1)), sep_(sep), f2_(std::move(f2)) {} 106 107 template <typename T> operator()108 void operator()(std::string* out, const T& p) { 109 f1_(out, p.first); 110 out->append(sep_); 111 f2_(out, p.second); 112 } 113 114 template <typename T> operator()115 void operator()(std::string* out, const T& p) const { 116 f1_(out, p.first); 117 out->append(sep_); 118 f2_(out, p.second); 119 } 120 121 private: 122 F1 f1_; 123 std::string sep_; 124 F2 f2_; 125 }; 126 127 // Wraps another formatter and dereferences the argument to operator() then 128 // passes the dereferenced argument to the wrapped formatter. This can be 129 // useful, for example, to join a std::vector<int*>. 130 template <typename Formatter> 131 class DereferenceFormatterImpl { 132 public: DereferenceFormatterImpl()133 DereferenceFormatterImpl() : f_() {} DereferenceFormatterImpl(Formatter && f)134 explicit DereferenceFormatterImpl(Formatter&& f) 135 : f_(std::forward<Formatter>(f)) {} 136 137 template <typename T> operator()138 void operator()(std::string* out, const T& t) { 139 f_(out, *t); 140 } 141 142 template <typename T> operator()143 void operator()(std::string* out, const T& t) const { 144 f_(out, *t); 145 } 146 147 private: 148 Formatter f_; 149 }; 150 151 // DefaultFormatter<T> is a traits class that selects a default Formatter to use 152 // for the given type T. The ::Type member names the Formatter to use. This is 153 // used by the strings::Join() functions that do NOT take a Formatter argument, 154 // in which case a default Formatter must be chosen. 155 // 156 // AlphaNumFormatterImpl is the default in the base template, followed by 157 // specializations for other types. 158 template <typename ValueType> 159 struct DefaultFormatter { 160 typedef AlphaNumFormatterImpl Type; 161 }; 162 template <> 163 struct DefaultFormatter<const char*> { 164 typedef AlphaNumFormatterImpl Type; 165 }; 166 template <> 167 struct DefaultFormatter<char*> { 168 typedef AlphaNumFormatterImpl Type; 169 }; 170 template <> 171 struct DefaultFormatter<std::string> { 172 typedef NoFormatter Type; 173 }; 174 template <> 175 struct DefaultFormatter<absl::string_view> { 176 typedef NoFormatter Type; 177 }; 178 template <typename ValueType> 179 struct DefaultFormatter<ValueType*> { 180 typedef DereferenceFormatterImpl<typename DefaultFormatter<ValueType>::Type> 181 Type; 182 }; 183 184 template <typename ValueType> 185 struct DefaultFormatter<std::unique_ptr<ValueType>> 186 : public DefaultFormatter<ValueType*> {}; 187 188 // 189 // JoinAlgorithm() functions 190 // 191 192 // The main joining algorithm. This simply joins the elements in the given 193 // iterator range, each separated by the given separator, into an output string, 194 // and formats each element using the provided Formatter object. 195 template <typename Iterator, typename Formatter> 196 std::string JoinAlgorithm(Iterator start, Iterator end, absl::string_view s, 197 Formatter&& f) { 198 std::string result; 199 absl::string_view sep(""); 200 for (Iterator it = start; it != end; ++it) { 201 result.append(sep.data(), sep.size()); 202 f(&result, *it); 203 sep = s; 204 } 205 return result; 206 } 207 208 // A joining algorithm that's optimized for a forward iterator range of 209 // string-like objects that do not need any additional formatting. This is to 210 // optimize the common case of joining, say, a std::vector<string> or a 211 // std::vector<absl::string_view>. 212 // 213 // This is an overload of the previous JoinAlgorithm() function. Here the 214 // Formatter argument is of type NoFormatter. Since NoFormatter is an internal 215 // type, this overload is only invoked when strings::Join() is called with a 216 // range of string-like objects (e.g., std::string, absl::string_view), and an 217 // explicit Formatter argument was NOT specified. 218 // 219 // The optimization is that the needed space will be reserved in the output 220 // string to avoid the need to resize while appending. To do this, the iterator 221 // range will be traversed twice: once to calculate the total needed size, and 222 // then again to copy the elements and delimiters to the output string. 223 template <typename Iterator, 224 typename = typename std::enable_if<std::is_convertible< 225 typename std::iterator_traits<Iterator>::iterator_category, 226 std::forward_iterator_tag>::value>::type> 227 std::string JoinAlgorithm(Iterator start, Iterator end, absl::string_view s, 228 NoFormatter) { 229 std::string result; 230 if (start != end) { 231 // Sums size 232 size_t result_size = start->size(); 233 for (Iterator it = start; ++it != end;) { 234 result_size += s.size(); 235 result_size += it->size(); 236 } 237 238 if (result_size > 0) { 239 STLStringResizeUninitialized(&result, result_size); 240 241 // Joins strings 242 char* result_buf = &*result.begin(); 243 memcpy(result_buf, start->data(), start->size()); 244 result_buf += start->size(); 245 for (Iterator it = start; ++it != end;) { 246 memcpy(result_buf, s.data(), s.size()); 247 result_buf += s.size(); 248 memcpy(result_buf, it->data(), it->size()); 249 result_buf += it->size(); 250 } 251 } 252 } 253 254 return result; 255 } 256 257 // JoinTupleLoop implements a loop over the elements of a std::tuple, which 258 // are heterogeneous. The primary template matches the tuple interior case. It 259 // continues the iteration after appending a separator (for nonzero indices) 260 // and formatting an element of the tuple. The specialization for the I=N case 261 // matches the end-of-tuple, and terminates the iteration. 262 template <size_t I, size_t N> 263 struct JoinTupleLoop { 264 template <typename Tup, typename Formatter> 265 void operator()(std::string* out, const Tup& tup, absl::string_view sep, 266 Formatter&& fmt) { 267 if (I > 0) out->append(sep.data(), sep.size()); 268 fmt(out, std::get<I>(tup)); 269 JoinTupleLoop<I + 1, N>()(out, tup, sep, fmt); 270 } 271 }; 272 template <size_t N> 273 struct JoinTupleLoop<N, N> { 274 template <typename Tup, typename Formatter> 275 void operator()(std::string*, const Tup&, absl::string_view, Formatter&&) {} 276 }; 277 278 template <typename... T, typename Formatter> 279 std::string JoinAlgorithm(const std::tuple<T...>& tup, absl::string_view sep, 280 Formatter&& fmt) { 281 std::string result; 282 JoinTupleLoop<0, sizeof...(T)>()(&result, tup, sep, fmt); 283 return result; 284 } 285 286 template <typename Iterator> 287 std::string JoinRange(Iterator first, Iterator last, 288 absl::string_view separator) { 289 // No formatter was explicitly given, so a default must be chosen. 290 typedef typename std::iterator_traits<Iterator>::value_type ValueType; 291 typedef typename DefaultFormatter<ValueType>::Type Formatter; 292 return JoinAlgorithm(first, last, separator, Formatter()); 293 } 294 295 template <typename Range, typename Formatter> 296 std::string JoinRange(const Range& range, absl::string_view separator, 297 Formatter&& fmt) { 298 using std::begin; 299 using std::end; 300 return JoinAlgorithm(begin(range), end(range), separator, fmt); 301 } 302 303 template <typename Range> 304 std::string JoinRange(const Range& range, absl::string_view separator) { 305 using std::begin; 306 using std::end; 307 return JoinRange(begin(range), end(range), separator); 308 } 309 310 } // namespace strings_internal 311 ABSL_NAMESPACE_END 312 } // namespace absl 313 314 #endif // ABSL_STRINGS_INTERNAL_STR_JOIN_INTERNAL_H_ 315