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