| // Copyright 2017 The Chromium Authors. All rights reserved. | 
 | // Use of this source code is governed by a BSD-style license that can be | 
 | // found in the LICENSE file. | 
 |  | 
 | #include "base/strings/strcat.h" | 
 |  | 
 | namespace base { | 
 |  | 
 | namespace { | 
 |  | 
 | // Reserves an additional amount of size in the given string, growing by at | 
 | // least 2x. Used by StrAppend(). | 
 | // | 
 | // The "at least 2x" growing rule duplicates the exponential growth of | 
 | // std::string. The problem is that most implementations of reserve() will grow | 
 | // exactly to the requested amount instead of exponentially growing like would | 
 | // happen when appending normally. If we didn't do this, an append after the | 
 | // call to StrAppend() would definitely cause a reallocation, and loops with | 
 | // StrAppend() calls would have O(n^2) complexity to execute. Instead, we want | 
 | // StrAppend() to have the same semantics as std::string::append(). | 
 | // | 
 | // If the string is empty, we assume that exponential growth is not necessary. | 
 | template <typename String> | 
 | void ReserveAdditional(String* str, typename String::size_type additional) { | 
 |   str->reserve(std::max(str->size() + additional, str->size() * 2)); | 
 | } | 
 |  | 
 | template <typename DestString, typename InputString> | 
 | void StrAppendT(DestString* dest, span<const InputString> pieces) { | 
 |   size_t additional_size = 0; | 
 |   for (const auto& cur : pieces) | 
 |     additional_size += cur.size(); | 
 |   ReserveAdditional(dest, additional_size); | 
 |  | 
 |   for (const auto& cur : pieces) | 
 |     dest->append(cur.data(), cur.size()); | 
 | } | 
 |  | 
 | }  // namespace | 
 |  | 
 | std::string StrCat(span<const StringPiece> pieces) { | 
 |   std::string result; | 
 |   StrAppendT(&result, pieces); | 
 |   return result; | 
 | } | 
 |  | 
 | string16 StrCat(span<const StringPiece16> pieces) { | 
 |   string16 result; | 
 |   StrAppendT(&result, pieces); | 
 |   return result; | 
 | } | 
 |  | 
 | std::string StrCat(span<const std::string> pieces) { | 
 |   std::string result; | 
 |   StrAppendT(&result, pieces); | 
 |   return result; | 
 | } | 
 |  | 
 | string16 StrCat(span<const string16> pieces) { | 
 |   string16 result; | 
 |   StrAppendT(&result, pieces); | 
 |   return result; | 
 | } | 
 |  | 
 | void StrAppend(std::string* dest, span<const StringPiece> pieces) { | 
 |   StrAppendT(dest, pieces); | 
 | } | 
 |  | 
 | void StrAppend(string16* dest, span<const StringPiece16> pieces) { | 
 |   StrAppendT(dest, pieces); | 
 | } | 
 |  | 
 | void StrAppend(std::string* dest, span<const std::string> pieces) { | 
 |   StrAppendT(dest, pieces); | 
 | } | 
 |  | 
 | void StrAppend(string16* dest, span<const string16> pieces) { | 
 |   StrAppendT(dest, pieces); | 
 | } | 
 |  | 
 | }  // namespace base |