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