summaryrefslogtreecommitdiff
path: root/absl/strings
diff options
context:
space:
mode:
authorGravatar Abseil Team <absl-team@google.com>2024-04-18 08:17:00 -0700
committerGravatar Copybara-Service <copybara-worker@google.com>2024-04-18 08:18:20 -0700
commit6645f3141269fdb88ba772439f7af7bcd87dd39a (patch)
tree7ad7595f719e20e103ed3d8e9cfe97f3bcde33cf /absl/strings
parent4eb6f626f84779f7ba5a12f93acbaafd742c6851 (diff)
Add `absl::AppendCordToString`
PiperOrigin-RevId: 626039936 Change-Id: I6e791363bab06d66029a8565c42d158a2fe176f0
Diffstat (limited to 'absl/strings')
-rw-r--r--absl/strings/cord.cc9
-rw-r--r--absl/strings/cord.h23
-rw-r--r--absl/strings/cord_test.cc32
3 files changed, 64 insertions, 0 deletions
diff --git a/absl/strings/cord.cc b/absl/strings/cord.cc
index ea84e446..025904c1 100644
--- a/absl/strings/cord.cc
+++ b/absl/strings/cord.cc
@@ -1062,6 +1062,15 @@ void CopyCordToString(const Cord& src, absl::Nonnull<std::string*> dst) {
}
}
+void AppendCordToString(const Cord& src, absl::Nonnull<std::string*> dst) {
+ const size_t cur_dst_size = dst->size();
+ const size_t new_dst_size = cur_dst_size + src.size();
+ absl::strings_internal::STLStringResizeUninitializedAmortized(dst,
+ new_dst_size);
+ char* append_ptr = &(*dst)[cur_dst_size];
+ src.CopyToArrayImpl(append_ptr);
+}
+
void Cord::CopyToArraySlowPath(absl::Nonnull<char*> dst) const {
assert(contents_.is_tree());
absl::string_view fragment;
diff --git a/absl/strings/cord.h b/absl/strings/cord.h
index c9f6767b..95519cd3 100644
--- a/absl/strings/cord.h
+++ b/absl/strings/cord.h
@@ -105,6 +105,7 @@ class CordTestPeer;
template <typename Releaser>
Cord MakeCordFromExternal(absl::string_view, Releaser&&);
void CopyCordToString(const Cord& src, absl::Nonnull<std::string*> dst);
+void AppendCordToString(const Cord& src, absl::Nonnull<std::string*> dst);
// Cord memory accounting modes
enum class CordMemoryAccounting {
@@ -421,6 +422,18 @@ class Cord {
friend void CopyCordToString(const Cord& src,
absl::Nonnull<std::string*> dst);
+ // AppendCordToString()
+ //
+ // Appends the contents of a `src` Cord to a `*dst` string.
+ //
+ // This function optimizes the case of appending to a non-empty destination
+ // string. If `*dst` already has capacity to store the contents of the cord,
+ // this function does not invalidate pointers previously returned by
+ // `dst->data()`. If `*dst` is a new object, prefer to simply use the
+ // conversion operator to `std::string`.
+ friend void AppendCordToString(const Cord& src,
+ absl::Nonnull<std::string*> dst);
+
class CharIterator;
//----------------------------------------------------------------------------
@@ -1066,6 +1079,8 @@ class Cord {
const;
CharIterator FindImpl(CharIterator it, absl::string_view needle) const;
+
+ void CopyToArrayImpl(absl::Nonnull<char*> dst) const;
};
ABSL_NAMESPACE_END
@@ -1450,6 +1465,14 @@ inline bool Cord::StartsWith(absl::string_view rhs) const {
return EqualsImpl(rhs, rhs_size);
}
+inline void Cord::CopyToArrayImpl(absl::Nonnull<char*> dst) const {
+ if (!contents_.is_tree()) {
+ if (!empty()) contents_.CopyToArray(dst);
+ } else {
+ CopyToArraySlowPath(dst);
+ }
+}
+
inline void Cord::ChunkIterator::InitTree(
absl::Nonnull<cord_internal::CordRep*> tree) {
tree = cord_internal::SkipCrcNode(tree);
diff --git a/absl/strings/cord_test.cc b/absl/strings/cord_test.cc
index cdd52463..658ad55b 100644
--- a/absl/strings/cord_test.cc
+++ b/absl/strings/cord_test.cc
@@ -703,6 +703,38 @@ TEST_P(CordTest, CopyToString) {
"copying ", "to ", "a ", "string."})));
}
+static void VerifyAppendCordToString(const absl::Cord& cord) {
+ std::string initially_empty;
+ absl::AppendCordToString(cord, &initially_empty);
+ EXPECT_EQ(initially_empty, cord);
+
+ const absl::string_view kInitialContents = "initial contents.";
+ std::string expected_after_append =
+ absl::StrCat(kInitialContents, std::string(cord));
+
+ std::string no_reserve(kInitialContents);
+ absl::AppendCordToString(cord, &no_reserve);
+ EXPECT_EQ(no_reserve, expected_after_append);
+
+ std::string has_reserved_capacity(kInitialContents);
+ has_reserved_capacity.reserve(has_reserved_capacity.size() + cord.size());
+ const char* address_before_copy = has_reserved_capacity.data();
+ absl::AppendCordToString(cord, &has_reserved_capacity);
+ EXPECT_EQ(has_reserved_capacity, expected_after_append);
+ EXPECT_EQ(has_reserved_capacity.data(), address_before_copy)
+ << "AppendCordToString allocated new string storage; "
+ "has_reserved_capacity = \""
+ << has_reserved_capacity << "\"";
+}
+
+TEST_P(CordTest, AppendToString) {
+ VerifyAppendCordToString(absl::Cord()); // empty cords cannot carry CRCs
+ VerifyAppendCordToString(MaybeHardened(absl::Cord("small cord")));
+ VerifyAppendCordToString(MaybeHardened(
+ absl::MakeFragmentedCord({"fragmented ", "cord ", "to ", "test ",
+ "appending ", "to ", "a ", "string."})));
+}
+
TEST_P(CordTest, AppendEmptyBuffer) {
absl::Cord cord;
cord.Append(absl::CordBuffer());