Commit f4b4cee4 authored by Brett Wilson's avatar Brett Wilson Committed by Commit Bot

Add base::StrCat and StrAppend

This functions concatenate many strings at once, resulting in ~3x code
size and >2x speed improvement compared to a sequence of "operator+".

Some calls to JoinString that used an empty separator are replaced with
the new StrCat function.

I considered generating many overrides with different numbers of
arguments. This generates different code. In some cases I observed the
compiler generating more code vs. initializer_list, in others it seemed
to generate slightly less. Even when it generates a little more code
having a much simpler header file seemed preferable so I opted for the
initializer list.

Change-Id: Ie0fb52aabf60ad30ead55bdbeca1e586b33950fd
Reviewed-on: https://chromium-review.googlesource.com/805115
Commit-Queue: Brett Wilson <brettw@chromium.org>
Reviewed-by: default avatarDaniel Cheng <dcheng@chromium.org>
Cr-Commit-Position: refs/heads/master@{#522374}
parent 2c963b87
...@@ -733,6 +733,8 @@ jumbo_component("base") { ...@@ -733,6 +733,8 @@ jumbo_component("base") {
"strings/pattern.h", "strings/pattern.h",
"strings/safe_sprintf.cc", "strings/safe_sprintf.cc",
"strings/safe_sprintf.h", "strings/safe_sprintf.h",
"strings/strcat.cc",
"strings/strcat.h",
"strings/string16.cc", "strings/string16.cc",
"strings/string16.h", "strings/string16.h",
"strings/string_number_conversions.cc", "strings/string_number_conversions.cc",
...@@ -2189,6 +2191,7 @@ test("base_unittests") { ...@@ -2189,6 +2191,7 @@ test("base_unittests") {
"strings/nullable_string16_unittest.cc", "strings/nullable_string16_unittest.cc",
"strings/pattern_unittest.cc", "strings/pattern_unittest.cc",
"strings/safe_sprintf_unittest.cc", "strings/safe_sprintf_unittest.cc",
"strings/strcat_unittest.cc",
"strings/string16_unittest.cc", "strings/string16_unittest.cc",
"strings/string_number_conversions_unittest.cc", "strings/string_number_conversions_unittest.cc",
"strings/string_piece_unittest.cc", "strings/string_piece_unittest.cc",
......
// 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
// 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.
#ifndef BASE_STRINGS_STRCAT_H_
#define BASE_STRINGS_STRCAT_H_
#include <initializer_list>
#include "base/base_export.h"
#include "base/compiler_specific.h"
#include "base/containers/span.h"
#include "base/strings/string_piece.h"
namespace base {
// StrCat ----------------------------------------------------------------------
//
// StrCat is a function to perform concatenation on a sequence of strings.
// It is preferrable to a sequence of "a + b + c" because it is both faster and
// generates less code.
//
// std::string result = base::StrCat({"foo ", result, "\nfoo ", bar});
//
// To join an array of strings with a separator, see base::JoinString in
// base/strings/string_util.h.
//
// MORE INFO
//
// StrCat can see all arguments at once, so it can allocate one return buffer
// of exactly the right size and copy once, as opposed to a sequence of
// operator+ which generates a series of temporary strings, copying as it goes.
// And by using StringPiece arguments, StrCat can avoid creating temporary
// string objects for char* constants.
//
// ALTERNATIVES
//
// Internal Google / Abseil has a similar StrCat function. That version takes
// an overloaded number of arguments instead of initializer list (overflowing
// to initializer list for many arguments). We don't have any legacy
// requirements and using only initializer_list is simpler and generates
// roughly the same amount of code at the call sites.
//
// Abseil's StrCat also allows numbers by using an intermediate class that can
// be implicitly constructed from either a string or various number types. This
// class formats the numbers into a static buffer for increased performance,
// and the call sites look nice.
//
// As-written Abseil's helper class for numbers generates slightly more code
// than the raw StringPiece version. We can de-inline the helper class'
// constructors which will cause the StringPiece constructors to be de-inlined
// for this call and generate slightly less code. This is something we can
// explore more in the future.
BASE_EXPORT std::string StrCat(span<const StringPiece> pieces);
BASE_EXPORT string16 StrCat(span<const StringPiece16> pieces);
BASE_EXPORT std::string StrCat(span<const std::string> pieces);
BASE_EXPORT string16 StrCat(span<const string16> pieces);
// Initializer list forwards to the array version.
inline std::string StrCat(std::initializer_list<StringPiece> pieces) {
return StrCat(make_span(pieces.begin(), pieces.size()));
}
inline string16 StrCat(std::initializer_list<StringPiece16> pieces) {
return StrCat(make_span(pieces.begin(), pieces.size()));
}
// StrAppend -------------------------------------------------------------------
//
// Appends a sequence of strings to a destination. Prefer:
// StrAppend(&foo, ...);
// over:
// foo += StrCat(...);
// because it avoids a temporary string allocation and copy.
BASE_EXPORT void StrAppend(std::string* dest, span<const StringPiece> pieces);
BASE_EXPORT void StrAppend(string16* dest, span<const StringPiece16> pieces);
BASE_EXPORT void StrAppend(std::string* dest, span<const std::string> pieces);
BASE_EXPORT void StrAppend(string16* dest, span<const string16> pieces);
// Initializer list forwards to the array version.
inline void StrAppend(std::string* dest,
std::initializer_list<StringPiece> pieces) {
return StrAppend(dest, make_span(pieces.begin(), pieces.size()));
}
inline void StrAppend(string16* dest,
std::initializer_list<StringPiece16> pieces) {
return StrAppend(dest, make_span(pieces.begin(), pieces.size()));
}
} // namespace base
#endif // BASE_STRINGS_STRCAT_H_
// 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"
#include "base/strings/utf_string_conversions.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace base {
TEST(StrCat, 8Bit) {
EXPECT_EQ("", StrCat({""}));
EXPECT_EQ("1", StrCat({"1"}));
EXPECT_EQ("122", StrCat({"1", "22"}));
EXPECT_EQ("122333", StrCat({"1", "22", "333"}));
EXPECT_EQ("1223334444", StrCat({"1", "22", "333", "4444"}));
EXPECT_EQ("122333444455555", StrCat({"1", "22", "333", "4444", "55555"}));
}
TEST(StrCat, 16Bit) {
string16 arg1 = ASCIIToUTF16("1");
string16 arg2 = ASCIIToUTF16("22");
string16 arg3 = ASCIIToUTF16("333");
EXPECT_EQ(ASCIIToUTF16(""), StrCat({string16()}));
EXPECT_EQ(ASCIIToUTF16("1"), StrCat({arg1}));
EXPECT_EQ(ASCIIToUTF16("122"), StrCat({arg1, arg2}));
EXPECT_EQ(ASCIIToUTF16("122333"), StrCat({arg1, arg2, arg3}));
}
TEST(StrAppend, 8Bit) {
std::string result;
result = "foo";
StrAppend(&result, {std::string()});
EXPECT_EQ("foo", result);
result = "foo";
StrAppend(&result, {"1"});
EXPECT_EQ("foo1", result);
result = "foo";
StrAppend(&result, {"1", "22", "333"});
EXPECT_EQ("foo122333", result);
}
TEST(StrAppend, 16Bit) {
string16 arg1 = ASCIIToUTF16("1");
string16 arg2 = ASCIIToUTF16("22");
string16 arg3 = ASCIIToUTF16("333");
string16 result;
result = ASCIIToUTF16("foo");
StrAppend(&result, {string16()});
EXPECT_EQ(ASCIIToUTF16("foo"), result);
result = ASCIIToUTF16("foo");
StrAppend(&result, {arg1});
EXPECT_EQ(ASCIIToUTF16("foo1"), result);
result = ASCIIToUTF16("foo");
StrAppend(&result, {arg1, arg2, arg3});
EXPECT_EQ(ASCIIToUTF16("foo122333"), result);
}
} // namespace base
...@@ -437,6 +437,8 @@ BASE_EXPORT char16* WriteInto(string16* str, size_t length_with_null); ...@@ -437,6 +437,8 @@ BASE_EXPORT char16* WriteInto(string16* str, size_t length_with_null);
// strings. For example, instead of using SplitString, modifying the vector, // strings. For example, instead of using SplitString, modifying the vector,
// then using JoinString, use SplitStringPiece followed by JoinString so that no // then using JoinString, use SplitStringPiece followed by JoinString so that no
// copies of those strings are created until the final join operation. // copies of those strings are created until the final join operation.
//
// Use StrCat (in base/strings/strcat.h) if you don't need a separator.
BASE_EXPORT std::string JoinString(const std::vector<std::string>& parts, BASE_EXPORT std::string JoinString(const std::vector<std::string>& parts,
StringPiece separator); StringPiece separator);
BASE_EXPORT string16 JoinString(const std::vector<string16>& parts, BASE_EXPORT string16 JoinString(const std::vector<string16>& parts,
......
...@@ -12,6 +12,7 @@ ...@@ -12,6 +12,7 @@
#include "base/location.h" #include "base/location.h"
#include "base/memory/ptr_util.h" #include "base/memory/ptr_util.h"
#include "base/message_loop/message_loop.h" #include "base/message_loop/message_loop.h"
#include "base/strings/strcat.h"
#include "base/strings/string_number_conversions.h" #include "base/strings/string_number_conversions.h"
#include "base/strings/string_util.h" #include "base/strings/string_util.h"
#include "base/strings/stringprintf.h" #include "base/strings/stringprintf.h"
...@@ -163,7 +164,7 @@ class HttpRequest { ...@@ -163,7 +164,7 @@ class HttpRequest {
} }
pieces.insert(pieces.end(), {crlf}); pieces.insert(pieces.end(), {crlf});
std::string request = base::JoinString(pieces, ""); std::string request = base::StrCat(pieces);
scoped_refptr<net::IOBuffer> base_buffer = scoped_refptr<net::IOBuffer> base_buffer =
new net::IOBuffer(request.size()); new net::IOBuffer(request.size());
memcpy(base_buffer->data(), request.data(), request.size()); memcpy(base_buffer->data(), request.data(), request.size());
......
...@@ -12,7 +12,7 @@ ...@@ -12,7 +12,7 @@
#include "base/bind.h" #include "base/bind.h"
#include "base/logging.h" #include "base/logging.h"
#include "base/memory/ref_counted_memory.h" #include "base/memory/ref_counted_memory.h"
#include "base/strings/string_util.h" #include "base/strings/strcat.h"
#include "chrome/browser/history/top_sites_factory.h" #include "chrome/browser/history/top_sites_factory.h"
#include "chrome/browser/profiles/profile.h" #include "chrome/browser/profiles/profile.h"
#include "chrome/browser/search/instant_io_context.h" #include "chrome/browser/search/instant_io_context.h"
...@@ -172,6 +172,6 @@ void ThumbnailListSource::OnMostVisitedURLsAvailable( ...@@ -172,6 +172,6 @@ void ThumbnailListSource::OnMostVisitedURLsAvailable(
} }
out.push_back(kHtmlFooter); out.push_back(kHtmlFooter);
std::string out_html = base::JoinString(out, base::StringPiece()); std::string out_html = base::StrCat(out);
callback.Run(base::RefCountedString::TakeString(&out_html)); callback.Run(base::RefCountedString::TakeString(&out_html));
} }
...@@ -9,6 +9,7 @@ ...@@ -9,6 +9,7 @@
#include <map> #include <map>
#include <utility> #include <utility>
#include "base/strings/strcat.h"
#include "base/strings/string_util.h" #include "base/strings/string_util.h"
#include "chrome/browser/engagement/site_engagement_service.h" #include "chrome/browser/engagement/site_engagement_service.h"
#include "chrome/browser/profiles/profile.h" #include "chrome/browser/profiles/profile.h"
...@@ -100,7 +101,7 @@ bool ShareServiceImpl::ReplacePlaceholders(base::StringPiece url_template, ...@@ -100,7 +101,7 @@ bool ShareServiceImpl::ReplacePlaceholders(base::StringPiece url_template,
split_template.push_back(url_template.substr( split_template.push_back(url_template.substr(
start_index_to_copy, url_template.size() - start_index_to_copy)); start_index_to_copy, url_template.size() - start_index_to_copy));
*url_template_filled = base::JoinString(split_template, base::StringPiece()); *url_template_filled = base::StrCat(split_template);
return true; return true;
} }
......
...@@ -13,8 +13,8 @@ ...@@ -13,8 +13,8 @@
#include "base/metrics/histogram_macros.h" #include "base/metrics/histogram_macros.h"
#include "base/metrics/sparse_histogram.h" #include "base/metrics/sparse_histogram.h"
#include "base/metrics/user_metrics.h" #include "base/metrics/user_metrics.h"
#include "base/strings/strcat.h"
#include "base/strings/string_piece.h" #include "base/strings/string_piece.h"
#include "base/strings/string_util.h"
#include "base/time/time.h" #include "base/time/time.h"
#include "components/autofill/core/browser/autofill_experiments.h" #include "components/autofill/core/browser/autofill_experiments.h"
#include "components/autofill/core/browser/autofill_field.h" #include "components/autofill/core/browser/autofill_field.h"
...@@ -344,11 +344,11 @@ void LogPredictionQualityMetrics( ...@@ -344,11 +344,11 @@ void LogPredictionQualityMetrics(
const char* source = GetQualityMetricPredictionSource(prediction_source); const char* source = GetQualityMetricPredictionSource(prediction_source);
const char* suffix = GetQualityMetricTypeSuffix(metric_type); const char* suffix = GetQualityMetricTypeSuffix(metric_type);
std::string raw_data_histogram = std::string raw_data_histogram =
base::JoinString({"Autofill.FieldPrediction.", source, suffix}, ""); base::StrCat({"Autofill.FieldPrediction.", source, suffix});
std::string aggregate_histogram = base::JoinString( std::string aggregate_histogram = base::StrCat(
{"Autofill.FieldPredictionQuality.Aggregate.", source, suffix}, ""); {"Autofill.FieldPredictionQuality.Aggregate.", source, suffix});
std::string type_specific_histogram = base::JoinString( std::string type_specific_histogram = base::StrCat(
{"Autofill.FieldPredictionQuality.ByFieldType.", source, suffix}, ""); {"Autofill.FieldPredictionQuality.ByFieldType.", source, suffix});
const ServerFieldTypeSet& possible_types = const ServerFieldTypeSet& possible_types =
metric_type == AutofillMetrics::TYPE_AUTOCOMPLETE_BASED metric_type == AutofillMetrics::TYPE_AUTOCOMPLETE_BASED
......
...@@ -7,6 +7,7 @@ ...@@ -7,6 +7,7 @@
#include <vector> #include <vector>
#include "base/stl_util.h" #include "base/stl_util.h"
#include "base/strings/strcat.h"
#include "base/strings/string_util.h" #include "base/strings/string_util.h"
#include "base/time/time.h" #include "base/time/time.h"
#include "components/network_time/network_time_tracker.h" #include "components/network_time/network_time_tracker.h"
...@@ -57,7 +58,7 @@ bool CertificateChainToString(scoped_refptr<net::X509Certificate> cert, ...@@ -57,7 +58,7 @@ bool CertificateChainToString(scoped_refptr<net::X509Certificate> cert,
if (!cert->GetPEMEncodedChain(&pem_encoded_chain)) if (!cert->GetPEMEncodedChain(&pem_encoded_chain))
return false; return false;
*result = base::JoinString(pem_encoded_chain, ""); *result = base::StrCat(pem_encoded_chain);
return true; return true;
} }
......
...@@ -10,7 +10,7 @@ ...@@ -10,7 +10,7 @@
#include "base/logging.h" #include "base/logging.h"
#include "base/macros.h" #include "base/macros.h"
#include "base/memory/ptr_util.h" #include "base/memory/ptr_util.h"
#include "base/strings/string_util.h" #include "base/strings/strcat.h"
#include "base/synchronization/waitable_event.h" #include "base/synchronization/waitable_event.h"
#include "components/grpc_support/include/bidirectional_stream_c.h" #include "components/grpc_support/include/bidirectional_stream_c.h"
#include "components/grpc_support/test/get_stream_engine.h" #include "components/grpc_support/test/get_stream_engine.h"
...@@ -285,7 +285,7 @@ TEST_P(BidirectionalStreamTest, StartExampleBidiStream) { ...@@ -285,7 +285,7 @@ TEST_P(BidirectionalStreamTest, StartExampleBidiStream) {
ASSERT_EQ(std::string(kHelloBodyValue, 2), test.read_data.front()); ASSERT_EQ(std::string(kHelloBodyValue, 2), test.read_data.front());
// Verify that individual read data joined using empty separator match // Verify that individual read data joined using empty separator match
// expected body. // expected body.
ASSERT_EQ(std::string(kHelloBodyValue), base::JoinString(test.read_data, "")); ASSERT_EQ(std::string(kHelloBodyValue), base::StrCat(test.read_data));
ASSERT_EQ(std::string(kHelloTrailerValue), ASSERT_EQ(std::string(kHelloTrailerValue),
test.response_trailers[kHelloTrailerName]); test.response_trailers[kHelloTrailerName]);
bidirectional_stream_destroy(test.stream); bidirectional_stream_destroy(test.stream);
...@@ -329,7 +329,7 @@ TEST_P(BidirectionalStreamTest, SimpleGetWithFlush) { ...@@ -329,7 +329,7 @@ TEST_P(BidirectionalStreamTest, SimpleGetWithFlush) {
ASSERT_EQ(std::string(kHelloHeaderValue), ASSERT_EQ(std::string(kHelloHeaderValue),
test.response_headers[kHelloHeaderName]); test.response_headers[kHelloHeaderName]);
ASSERT_EQ(TestBidirectionalStreamCallback::ON_SUCCEEDED, test.response_step); ASSERT_EQ(TestBidirectionalStreamCallback::ON_SUCCEEDED, test.response_step);
ASSERT_EQ(std::string(kHelloBodyValue), base::JoinString(test.read_data, "")); ASSERT_EQ(std::string(kHelloBodyValue), base::StrCat(test.read_data));
ASSERT_EQ(std::string(kHelloTrailerValue), ASSERT_EQ(std::string(kHelloTrailerValue),
test.response_trailers[kHelloTrailerName]); test.response_trailers[kHelloTrailerName]);
// Flush after done is ignored. // Flush after done is ignored.
...@@ -356,7 +356,7 @@ TEST_P(BidirectionalStreamTest, SimplePostWithFlush) { ...@@ -356,7 +356,7 @@ TEST_P(BidirectionalStreamTest, SimplePostWithFlush) {
ASSERT_EQ(std::string(kHelloHeaderValue), ASSERT_EQ(std::string(kHelloHeaderValue),
test.response_headers[kHelloHeaderName]); test.response_headers[kHelloHeaderName]);
ASSERT_EQ(TestBidirectionalStreamCallback::ON_SUCCEEDED, test.response_step); ASSERT_EQ(TestBidirectionalStreamCallback::ON_SUCCEEDED, test.response_step);
ASSERT_EQ(std::string(kHelloBodyValue), base::JoinString(test.read_data, "")); ASSERT_EQ(std::string(kHelloBodyValue), base::StrCat(test.read_data));
ASSERT_EQ(std::string(kHelloTrailerValue), ASSERT_EQ(std::string(kHelloTrailerValue),
test.response_trailers[kHelloTrailerName]); test.response_trailers[kHelloTrailerName]);
// Flush after done is ignored. // Flush after done is ignored.
...@@ -386,7 +386,7 @@ TEST_P(BidirectionalStreamTest, SimplePostWithFlushTwice) { ...@@ -386,7 +386,7 @@ TEST_P(BidirectionalStreamTest, SimplePostWithFlushTwice) {
ASSERT_EQ(std::string(kHelloHeaderValue), ASSERT_EQ(std::string(kHelloHeaderValue),
test.response_headers[kHelloHeaderName]); test.response_headers[kHelloHeaderName]);
ASSERT_EQ(TestBidirectionalStreamCallback::ON_SUCCEEDED, test.response_step); ASSERT_EQ(TestBidirectionalStreamCallback::ON_SUCCEEDED, test.response_step);
ASSERT_EQ(std::string(kHelloBodyValue), base::JoinString(test.read_data, "")); ASSERT_EQ(std::string(kHelloBodyValue), base::StrCat(test.read_data));
ASSERT_EQ(std::string(kHelloTrailerValue), ASSERT_EQ(std::string(kHelloTrailerValue),
test.response_trailers[kHelloTrailerName]); test.response_trailers[kHelloTrailerName]);
// Flush after done is ignored. // Flush after done is ignored.
...@@ -413,7 +413,7 @@ TEST_P(BidirectionalStreamTest, SimplePostWithFlushAfterOneWrite) { ...@@ -413,7 +413,7 @@ TEST_P(BidirectionalStreamTest, SimplePostWithFlushAfterOneWrite) {
ASSERT_EQ(std::string(kHelloHeaderValue), ASSERT_EQ(std::string(kHelloHeaderValue),
test.response_headers[kHelloHeaderName]); test.response_headers[kHelloHeaderName]);
ASSERT_EQ(TestBidirectionalStreamCallback::ON_SUCCEEDED, test.response_step); ASSERT_EQ(TestBidirectionalStreamCallback::ON_SUCCEEDED, test.response_step);
ASSERT_EQ(std::string(kHelloBodyValue), base::JoinString(test.read_data, "")); ASSERT_EQ(std::string(kHelloBodyValue), base::StrCat(test.read_data));
ASSERT_EQ(std::string(kHelloTrailerValue), ASSERT_EQ(std::string(kHelloTrailerValue),
test.response_trailers[kHelloTrailerName]); test.response_trailers[kHelloTrailerName]);
// Flush after done is ignored. // Flush after done is ignored.
......
...@@ -11,6 +11,7 @@ ...@@ -11,6 +11,7 @@
#include "base/memory/ptr_util.h" #include "base/memory/ptr_util.h"
#include "base/metrics/field_trial.h" #include "base/metrics/field_trial.h"
#include "base/metrics/field_trial_params.h" #include "base/metrics/field_trial_params.h"
#include "base/strings/strcat.h"
#include "base/strings/string_util.h" #include "base/strings/string_util.h"
#include "base/values.h" #include "base/values.h"
#include "components/previews/core/previews_features.h" #include "components/previews/core/previews_features.h"
...@@ -165,7 +166,7 @@ bool PreviewsAMPConverter::GetAMPURL(const GURL& url, GURL* new_amp_url) const { ...@@ -165,7 +166,7 @@ bool PreviewsAMPConverter::GetAMPURL(const GURL& url, GURL* new_amp_url) const {
if (!entry.prefix.empty() || !entry.suffix.empty() || if (!entry.prefix.empty() || !entry.suffix.empty() ||
!entry.suffix_html.empty()) { !entry.suffix_html.empty()) {
DCHECK(entry.prefix.empty() || entry.prefix[0] == '/'); DCHECK(entry.prefix.empty() || entry.prefix[0] == '/');
path = base::JoinString({entry.prefix, url.path(), entry.suffix}, ""); path = base::StrCat({entry.prefix, url.path(), entry.suffix});
if (!entry.suffix_html.empty() && if (!entry.suffix_html.empty() &&
base::EndsWith(path, ".html", base::CompareCase::SENSITIVE)) { base::EndsWith(path, ".html", base::CompareCase::SENSITIVE)) {
// Insert suffix_html before the .html extension. // Insert suffix_html before the .html extension.
......
...@@ -6,7 +6,7 @@ ...@@ -6,7 +6,7 @@
#include "base/i18n/rtl.h" #include "base/i18n/rtl.h"
#include "base/i18n/time_formatting.h" #include "base/i18n/time_formatting.h"
#include "base/strings/string_util.h" #include "base/strings/strcat.h"
#include "components/strings/grit/components_strings.h" #include "components/strings/grit/components_strings.h"
#include "components/url_formatter/url_formatter.h" #include "components/url_formatter/url_formatter.h"
#include "net/base/net_errors.h" #include "net/base/net_errors.h"
...@@ -46,8 +46,7 @@ void PopulateSSLDebuggingStrings(const net::SSLInfo ssl_info, ...@@ -46,8 +46,7 @@ void PopulateSSLDebuggingStrings(const net::SSLInfo ssl_info,
base::TimeFormatShortDate(time_triggered)); base::TimeFormatShortDate(time_triggered));
std::vector<std::string> encoded_chain; std::vector<std::string> encoded_chain;
ssl_info.cert->GetPEMEncodedChain(&encoded_chain); ssl_info.cert->GetPEMEncodedChain(&encoded_chain);
load_time_data->SetString( load_time_data->SetString("pem", base::StrCat(encoded_chain));
"pem", base::JoinString(encoded_chain, base::StringPiece()));
} }
} // namespace common_string_util } // namespace common_string_util
......
...@@ -7,6 +7,7 @@ ...@@ -7,6 +7,7 @@
#include "base/barrier_closure.h" #include "base/barrier_closure.h"
#include "base/base64.h" #include "base/base64.h"
#include "base/bind.h" #include "base/bind.h"
#include "base/strings/strcat.h"
#include "base/strings/string16.h" #include "base/strings/string16.h"
#include "base/strings/string_number_conversions.h" #include "base/strings/string_number_conversions.h"
#include "base/strings/string_piece.h" #include "base/strings/string_piece.h"
...@@ -83,7 +84,7 @@ std::string RenderOutputHtml( ...@@ -83,7 +84,7 @@ std::string RenderOutputHtml(
} }
out.push_back("</ul>"); out.push_back("</ul>");
out.push_back(kHtmlFooter); out.push_back(kHtmlFooter);
return base::JoinString(out, base::StringPiece()); return base::StrCat(out);
} }
// Returns the HTML needed to display that no suggestions are available. // Returns the HTML needed to display that no suggestions are available.
...@@ -96,7 +97,7 @@ std::string RenderOutputHtmlNoSuggestions(const std::string& base_url, ...@@ -96,7 +97,7 @@ std::string RenderOutputHtmlNoSuggestions(const std::string& base_url,
out.push_back("<p>You have no suggestions.</p>\n"); out.push_back("<p>You have no suggestions.</p>\n");
out.push_back(GetRefreshHtml(base_url, is_refresh)); out.push_back(GetRefreshHtml(base_url, is_refresh));
out.push_back(kHtmlFooter); out.push_back(kHtmlFooter);
return base::JoinString(out, base::StringPiece()); return base::StrCat(out);
} }
} // namespace } // namespace
......
...@@ -7,6 +7,7 @@ ...@@ -7,6 +7,7 @@
#include "base/command_line.h" #include "base/command_line.h"
#include "base/logging.h" #include "base/logging.h"
#include "base/memory/ptr_util.h" #include "base/memory/ptr_util.h"
#include "base/strings/strcat.h"
#include "base/strings/string_number_conversions.h" #include "base/strings/string_number_conversions.h"
#include "base/strings/string_split.h" #include "base/strings/string_split.h"
#include "base/strings/string_util.h" #include "base/strings/string_util.h"
...@@ -48,9 +49,8 @@ std::unique_ptr<base::SchedulerWorkerPoolParams> GetWorkerPoolParams( ...@@ -48,9 +49,8 @@ std::unique_ptr<base::SchedulerWorkerPoolParams> GetWorkerPoolParams(
const std::map<std::string, std::string>& variation_params, const std::map<std::string, std::string>& variation_params,
base::SchedulerBackwardCompatibility backward_compatibility = base::SchedulerBackwardCompatibility backward_compatibility =
base::SchedulerBackwardCompatibility::DISABLED) { base::SchedulerBackwardCompatibility::DISABLED) {
auto pool_descriptor_it =
auto pool_descriptor_it = variation_params.find( variation_params.find(base::StrCat({variation_param_prefix, pool_name}));
base::JoinString({variation_param_prefix, pool_name}, ""));
if (pool_descriptor_it == variation_params.end()) if (pool_descriptor_it == variation_params.end())
return nullptr; return nullptr;
const auto& pool_descriptor = pool_descriptor_it->second; const auto& pool_descriptor = pool_descriptor_it->second;
......
...@@ -8,6 +8,7 @@ ...@@ -8,6 +8,7 @@
#include "base/guid.h" #include "base/guid.h"
#include "base/logging.h" #include "base/logging.h"
#include "base/strings/strcat.h"
#include "base/strings/string_number_conversions.h" #include "base/strings/string_number_conversions.h"
#include "base/strings/string_util.h" #include "base/strings/string_util.h"
#include "base/strings/stringprintf.h" #include "base/strings/stringprintf.h"
...@@ -385,13 +386,13 @@ std::string BuildEventPingRequest(const Configurator& config, ...@@ -385,13 +386,13 @@ std::string BuildEventPingRequest(const Configurator& config,
base::StringPrintf("<app appid=\"%s\"", component.id().c_str()); base::StringPrintf("<app appid=\"%s\"", component.id().c_str());
base::StringAppendF(&app, " version=\"%s\"", base::StringAppendF(&app, " version=\"%s\"",
component.previous_version().GetString().c_str()); component.previous_version().GetString().c_str());
if (component.next_version().IsValid()) if (component.next_version().IsValid()) {
base::StringAppendF(&app, " nextversion=\"%s\"", base::StrAppend(
component.next_version().GetString().c_str()); &app, {" nextversion=\"", component.next_version().GetString(), "\""});
base::StringAppendF(&app, ">"); }
base::StringAppendF(&app, "%s", app.push_back('>');
base::JoinString(component.events(), "").c_str()); base::StrAppend(&app, component.events());
base::StringAppendF(&app, "</app>"); app.append("</app>");
// The ping request does not include any updater state. // The ping request does not include any updater state.
return BuildProtocolRequest( return BuildProtocolRequest(
......
...@@ -6,6 +6,7 @@ ...@@ -6,6 +6,7 @@
#include <iostream> #include <iostream>
#include "base/strings/strcat.h"
#include "base/strings/string_number_conversions.h" #include "base/strings/string_number_conversions.h"
#include "base/strings/string_util.h" #include "base/strings/string_util.h"
#include "base/strings/stringprintf.h" #include "base/strings/stringprintf.h"
...@@ -41,7 +42,7 @@ bool DumpX509CertificateChain(const base::FilePath& file_path, ...@@ -41,7 +42,7 @@ bool DumpX509CertificateChain(const base::FilePath& file_path,
std::cerr << "ERROR: X509Certificate::GetPEMEncodedChain failed.\n"; std::cerr << "ERROR: X509Certificate::GetPEMEncodedChain failed.\n";
return false; return false;
} }
return WriteToFile(file_path, base::JoinString(pem_encoded, "")); return WriteToFile(file_path, base::StrCat(pem_encoded));
} }
// Returns a hex-encoded sha256 of the DER-encoding of |cert_handle|. // Returns a hex-encoded sha256 of the DER-encoding of |cert_handle|.
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment