Add absl::CopyCordToSpan()

PiperOrigin-RevId: 912247630
Change-Id: Ie5d2837c9b878e6094dce4d2ec7e60441a7c6bb7
This commit is contained in:
Derek Mauro
2026-05-07 17:54:36 -07:00
committed by Copybara-Service
parent d0d4c59910
commit 638e17aedd
4 changed files with 75 additions and 0 deletions

View File

@@ -1014,6 +1014,7 @@ cc_test(
"//absl/log:check",
"//absl/random",
"//absl/types:compare",
"//absl/types:span",
"@googletest//:gtest",
"@googletest//:gtest_main",
],

View File

@@ -1086,6 +1086,24 @@ void Cord::CopyToArraySlowPath(char* absl_nonnull dst) const {
}
}
size_t CopyCordToSpan(const Cord& src, absl::Span<char> dst) {
if (src.size() <= dst.size()) {
src.CopyToArrayImpl(dst.data());
return src.size();
}
const size_t result = dst.size();
for (absl::string_view chunk : src.Chunks()) {
size_t n = std::min(chunk.size(), dst.size());
if (n == 0) {
break;
}
memcpy(dst.data(), chunk.data(), n);
dst.remove_prefix(n);
}
return result;
}
Cord Cord::ChunkIterator::AdvanceAndReadBytes(size_t n) {
// Failure of this assertion indicates an attempt to iterate past `end()`.
absl::base_internal::HardeningAssertGE(bytes_remaining_, n);

View File

@@ -98,6 +98,7 @@
#include "absl/strings/string_view.h"
#include "absl/types/compare.h"
#include "absl/types/optional.h"
#include "absl/types/span.h"
namespace absl {
ABSL_NAMESPACE_BEGIN
@@ -107,6 +108,7 @@ template <typename Releaser>
Cord MakeCordFromExternal(absl::string_view, Releaser&&);
void CopyCordToString(const Cord& src, std::string* absl_nonnull dst);
void AppendCordToString(const Cord& src, std::string* absl_nonnull dst);
[[nodiscard]] size_t CopyCordToSpan(const Cord& src, absl::Span<char> dst);
// Cord memory accounting modes
enum class CordMemoryAccounting {
@@ -434,6 +436,12 @@ class Cord {
friend void AppendCordToString(const Cord& src,
std::string* absl_nonnull dst);
// CopyCordToSpan()
//
// Copies up to `dest.size()` bytes starting from the beginning of `src` to
// `dst`. Returns the number of bytes copied.
friend size_t CopyCordToSpan(const Cord& src, absl::Span<char> dst);
class CharIterator;
//----------------------------------------------------------------------------

View File

@@ -62,6 +62,7 @@
#include "absl/strings/str_format.h"
#include "absl/strings/string_view.h"
#include "absl/types/compare.h"
#include "absl/types/span.h"
// convenience local constants
static constexpr auto FLAT = absl::cord_internal::FLAT;
@@ -735,6 +736,53 @@ TEST_P(CordTest, AppendToString) {
"appending ", "to ", "a ", "string."})));
}
static void VerifyCopyToSpan(const absl::Cord& cord) {
// Test with span exactly the same size as the cord.
{
std::string dst(cord.size(), '\0');
size_t copied = absl::CopyCordToSpan(cord, absl::MakeSpan(dst));
EXPECT_EQ(copied, cord.size());
EXPECT_EQ(dst, cord);
}
// Test with span larger than the cord.
{
std::string dst(cord.size() + 10, 'x');
size_t copied = absl::CopyCordToSpan(cord, absl::MakeSpan(dst));
EXPECT_EQ(copied, cord.size());
EXPECT_EQ(absl::string_view(dst).substr(0, copied), cord);
if (cord.size() < dst.size()) {
absl::string_view tail = absl::string_view(dst).substr(copied);
EXPECT_EQ(tail, std::string(tail.size(), 'x'));
}
}
// Test with span smaller than the cord.
{
size_t target_size = cord.size() / 2;
std::string dst(target_size, '\0');
size_t copied = absl::CopyCordToSpan(cord, absl::MakeSpan(dst));
EXPECT_EQ(copied, target_size);
EXPECT_EQ(dst, std::string(cord).substr(0, target_size));
}
// Test with empty span.
{
char c = 'x';
size_t copied = absl::CopyCordToSpan(cord, absl::MakeSpan(&c, 0));
EXPECT_EQ(copied, 0);
EXPECT_EQ(c, 'x');
}
}
TEST_P(CordTest, CopyToSpan) {
VerifyCopyToSpan(absl::Cord()); // Empty cords cannot be hardened.
VerifyCopyToSpan(MaybeHardened(absl::Cord("small cord")));
VerifyCopyToSpan(MaybeHardened(
absl::MakeFragmentedCord({"fragmented ", "cord ", "to ", "test ",
"copying ", "to ", "a ", "span."})));
}
TEST_P(CordTest, AppendEmptyBuffer) {
absl::Cord cord;
cord.Append(absl::CordBuffer());