summaryrefslogtreecommitdiff
path: root/absl/strings/cord.cc
diff options
context:
space:
mode:
authorGravatar Derek Mauro <dmauro@google.com>2022-10-28 11:21:06 -0700
committerGravatar Copybara-Service <copybara-worker@google.com>2022-10-28 11:22:03 -0700
commit1db72eb03e3685742c62abea9d13ddab2adcdf01 (patch)
treeb2e9c4182d1ba593b924152d24a8e9e1e8569c9e /absl/strings/cord.cc
parentfd9fbe74511fb2a060a3b15a1572b52fe16a6a43 (diff)
Support empty Cords with an expected checksum
PiperOrigin-RevId: 484578104 Change-Id: Ie4be3e4de27dc28d88395e16fd075fb10ab7a302
Diffstat (limited to 'absl/strings/cord.cc')
-rw-r--r--absl/strings/cord.cc47
1 files changed, 38 insertions, 9 deletions
diff --git a/absl/strings/cord.cc b/absl/strings/cord.cc
index 66f45fef..57082c5f 100644
--- a/absl/strings/cord.cc
+++ b/absl/strings/cord.cc
@@ -420,6 +420,7 @@ Cord& Cord::operator=(absl::string_view src) {
// we keep it here to make diffs easier.
void Cord::InlineRep::AppendArray(absl::string_view src,
MethodIdentifier method) {
+ MaybeRemoveEmptyCrcNode();
if (src.empty()) return; // memcpy(_, nullptr, 0) is undefined.
size_t appended = 0;
@@ -479,6 +480,10 @@ inline CordRep* Cord::TakeRep() && {
template <typename C>
inline void Cord::AppendImpl(C&& src) {
auto constexpr method = CordzUpdateTracker::kAppendCord;
+
+ contents_.MaybeRemoveEmptyCrcNode();
+ if (src.empty()) return;
+
if (empty()) {
// Since destination is empty, we can avoid allocating a node,
if (src.contents_.is_tree()) {
@@ -591,6 +596,9 @@ void Cord::Append(T&& src) {
template void Cord::Append(std::string&& src);
void Cord::Prepend(const Cord& src) {
+ contents_.MaybeRemoveEmptyCrcNode();
+ if (src.empty()) return;
+
CordRep* src_tree = src.contents_.tree();
if (src_tree != nullptr) {
CordRep::Ref(src_tree);
@@ -605,7 +613,9 @@ void Cord::Prepend(const Cord& src) {
}
void Cord::PrependArray(absl::string_view src, MethodIdentifier method) {
+ contents_.MaybeRemoveEmptyCrcNode();
if (src.empty()) return; // memcpy(_, nullptr, 0) is undefined.
+
if (!contents_.is_tree()) {
size_t cur_size = contents_.inline_size();
if (cur_size + src.size() <= InlineRep::kMaxInline) {
@@ -665,6 +675,7 @@ void Cord::RemovePrefix(size_t n) {
ABSL_INTERNAL_CHECK(n <= size(),
absl::StrCat("Requested prefix size ", n,
" exceeds Cord's size ", size()));
+ contents_.MaybeRemoveEmptyCrcNode();
CordRep* tree = contents_.tree();
if (tree == nullptr) {
contents_.remove_prefix(n);
@@ -695,6 +706,7 @@ void Cord::RemoveSuffix(size_t n) {
ABSL_INTERNAL_CHECK(n <= size(),
absl::StrCat("Requested suffix size ", n,
" exceeds Cord's size ", size()));
+ contents_.MaybeRemoveEmptyCrcNode();
CordRep* tree = contents_.tree();
if (tree == nullptr) {
contents_.reduce_size(n);
@@ -844,9 +856,10 @@ inline absl::string_view Cord::InlineRep::FindFlatStartPiece() const {
void Cord::SetExpectedChecksum(uint32_t crc) {
auto constexpr method = CordzUpdateTracker::kSetExpectedChecksum;
- if (empty()) return;
-
- if (!contents_.is_tree()) {
+ if (empty()) {
+ CordRep* rep = CordRepCrc::New(nullptr, crc);
+ contents_.EmplaceTree(rep, method);
+ } else if (!contents_.is_tree()) {
CordRep* rep = contents_.MakeFlatWithExtraCapacity(0);
rep = CordRepCrc::New(rep, crc);
contents_.EmplaceTree(rep, method);
@@ -929,6 +942,7 @@ inline int Cord::CompareSlowPath(const Cord& rhs, size_t compared_size,
}
inline absl::string_view Cord::GetFirstChunk(const Cord& c) {
+ if (c.empty()) return {};
return c.contents_.FindFlatStartPiece();
}
inline absl::string_view Cord::GetFirstChunk(absl::string_view sv) {
@@ -1166,6 +1180,10 @@ absl::string_view Cord::FlattenSlowPath() {
/* static */ bool Cord::GetFlatAux(CordRep* rep, absl::string_view* fragment) {
assert(rep != nullptr);
+ if (rep->length == 0) {
+ *fragment = absl::string_view();
+ return true;
+ }
rep = cord_internal::SkipCrcNode(rep);
if (rep->IsFlat()) {
*fragment = absl::string_view(rep->flat()->Data(), rep->length);
@@ -1197,6 +1215,7 @@ absl::string_view Cord::FlattenSlowPath() {
absl::cord_internal::CordRep* rep,
absl::FunctionRef<void(absl::string_view)> callback) {
assert(rep != nullptr);
+ if (rep->length == 0) return;
rep = cord_internal::SkipCrcNode(rep);
if (rep->IsBtree()) {
@@ -1230,7 +1249,11 @@ static void DumpNode(CordRep* rep, bool include_data, std::ostream* os,
if (include_data) *os << static_cast<void*>(rep);
*os << "]";
*os << " " << std::setw(indent) << "";
- if (rep->IsCrc()) {
+ bool leaf = false;
+ if (rep == nullptr) {
+ *os << "NULL\n";
+ leaf = true;
+ } else if (rep->IsCrc()) {
*os << "CRC crc=" << rep->crc()->crc << "\n";
indent += kIndentStep;
rep = rep->crc()->child;
@@ -1239,6 +1262,7 @@ static void DumpNode(CordRep* rep, bool include_data, std::ostream* os,
indent += kIndentStep;
rep = rep->substring()->child;
} else { // Leaf or ring
+ leaf = true;
if (rep->IsExternal()) {
*os << "EXTERNAL [";
if (include_data)
@@ -1252,6 +1276,8 @@ static void DumpNode(CordRep* rep, bool include_data, std::ostream* os,
} else {
CordRepBtree::Dump(rep, /*label=*/ "", include_data, *os);
}
+ }
+ if (leaf) {
if (stack.empty()) break;
rep = stack.back();
stack.pop_back();
@@ -1297,11 +1323,14 @@ static bool VerifyNode(CordRep* root, CordRep* start_node,
node->substring()->child->length,
ReportError(root, node));
} else if (node->IsCrc()) {
- ABSL_INTERNAL_CHECK(node->crc()->child != nullptr,
- ReportError(root, node));
- ABSL_INTERNAL_CHECK(node->crc()->length == node->crc()->child->length,
- ReportError(root, node));
- worklist.push_back(node->crc()->child);
+ ABSL_INTERNAL_CHECK(
+ node->crc()->child != nullptr || node->crc()->length == 0,
+ ReportError(root, node));
+ if (node->crc()->child != nullptr) {
+ ABSL_INTERNAL_CHECK(node->crc()->length == node->crc()->child->length,
+ ReportError(root, node));
+ worklist.push_back(node->crc()->child);
+ }
}
} while (!worklist.empty());
return true;