diff options
author | Abseil Team <absl-team@google.com> | 2024-04-18 08:17:00 -0700 |
---|---|---|
committer | Copybara-Service <copybara-worker@google.com> | 2024-04-18 08:18:20 -0700 |
commit | 6645f3141269fdb88ba772439f7af7bcd87dd39a (patch) | |
tree | 7ad7595f719e20e103ed3d8e9cfe97f3bcde33cf /absl/strings | |
parent | 4eb6f626f84779f7ba5a12f93acbaafd742c6851 (diff) |
Add `absl::AppendCordToString`
PiperOrigin-RevId: 626039936
Change-Id: I6e791363bab06d66029a8565c42d158a2fe176f0
Diffstat (limited to 'absl/strings')
-rw-r--r-- | absl/strings/cord.cc | 9 | ||||
-rw-r--r-- | absl/strings/cord.h | 23 | ||||
-rw-r--r-- | absl/strings/cord_test.cc | 32 |
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()); |