|  | // 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 |