summaryrefslogtreecommitdiff
path: root/absl/strings/cord.cc
diff options
context:
space:
mode:
authorGravatar Abseil Team <absl-team@google.com>2021-04-28 11:49:29 -0700
committerGravatar Derek Mauro <dmauro@google.com>2021-04-28 15:09:58 -0400
commitf14d5f4af12eb521a5142151d6ea3addbbed42bb (patch)
tree526a1feb786c03f64ed29f97d395b18480311dac /absl/strings/cord.cc
parentbcc11a8918f8cc9b43c9a0dc5da7b52d48452bd3 (diff)
Export of internal Abseil changes
-- a78c34c705b15598ea00171d4ff8755e38fad863 by Derek Mauro <dmauro@google.com>: Improve compiler support for ABSL_FALLTHROUGH_INTENDED PiperOrigin-RevId: 370952333 -- aed0c26f1a2aac98e217ad1b44ce4a858780a223 by Martijn Vels <mvels@google.com>: Add Cordz instrumentation for Flatten PiperOrigin-RevId: 370815149 -- ff4a58d0109d39dc32ef7a5e5e669ca4e630c6d9 by Martijn Vels <mvels@google.com>: Add Cordz instrumentation to RemovePrefix and RemoveSuffix PiperOrigin-RevId: 370751602 -- 40220a058b30ddd89c6e547591488d15342137dd by Martijn Vels <mvels@google.com>: Add Cordz instrumentation to operator=(string_view) PiperOrigin-RevId: 370737600 -- a2e49604f18b92e50b179b5477dfddb8f57538ca by Martijn Vels <mvels@google.com>: Add cordz instrumentation for Subcord PiperOrigin-RevId: 370724107 -- bcc3902e04fb4f14270aef00e18908e6a88474cd by Derek Mauro <dmauro@google.com>: Internal change PiperOrigin-RevId: 370707219 GitOrigin-RevId: a78c34c705b15598ea00171d4ff8755e38fad863 Change-Id: I0270e536cbdeaf1f195199da822b314521de3b96
Diffstat (limited to 'absl/strings/cord.cc')
-rw-r--r--absl/strings/cord.cc121
1 files changed, 77 insertions, 44 deletions
diff --git a/absl/strings/cord.cc b/absl/strings/cord.cc
index 15d17337..9262aee6 100644
--- a/absl/strings/cord.cc
+++ b/absl/strings/cord.cc
@@ -584,26 +584,35 @@ void Cord::Clear() {
}
Cord& Cord::operator=(absl::string_view src) {
+ auto constexpr method = CordzUpdateTracker::kAssignString;
const char* data = src.data();
size_t length = src.size();
CordRep* tree = contents_.tree();
if (length <= InlineRep::kMaxInline) {
- // Embed into this->contents_
- if (tree) CordzInfo::MaybeUntrackCord(contents_.cordz_info());
+ // Embed into this->contents_, which is somewhat subtle:
+ // - MaybeUntrackCord must be called before Unref(tree).
+ // - MaybeUntrackCord must be called before set_data() clobbers cordz_info.
+ // - set_data() must be called before Unref(tree) as it may reference tree.
+ if (tree != nullptr) CordzInfo::MaybeUntrackCord(contents_.cordz_info());
contents_.set_data(data, length, true);
- if (tree) CordRep::Unref(tree);
+ if (tree != nullptr) CordRep::Unref(tree);
return *this;
}
- if (tree != nullptr && tree->tag >= FLAT &&
- tree->flat()->Capacity() >= length && tree->refcount.IsOne()) {
- // Copy in place if the existing FLAT node is reusable.
- memmove(tree->flat()->Data(), data, length);
- tree->length = length;
- VerifyTree(tree);
- return *this;
+ if (tree != nullptr) {
+ CordzUpdateScope scope(contents_.cordz_info(), method);
+ if (tree->tag >= FLAT && tree->flat()->Capacity() >= length &&
+ tree->refcount.IsOne()) {
+ // Copy in place if the existing FLAT node is reusable.
+ memmove(tree->flat()->Data(), data, length);
+ tree->length = length;
+ VerifyTree(tree);
+ return *this;
+ }
+ contents_.SetTree(NewTree(data, length, 0), scope);
+ CordRep::Unref(tree);
+ } else {
+ contents_.EmplaceTree(NewTree(data, length, 0), method);
}
- contents_.set_tree(NewTree(data, length, 0));
- if (tree) CordRep::Unref(tree);
return *this;
}
@@ -893,12 +902,17 @@ void Cord::RemovePrefix(size_t n) {
CordRep* tree = contents_.tree();
if (tree == nullptr) {
contents_.remove_prefix(n);
- } else if (tree->tag == RING) {
- contents_.replace_tree(CordRepRing::RemovePrefix(tree->ring(), n));
} else {
- CordRep* newrep = RemovePrefixFrom(tree, n);
- CordRep::Unref(tree);
- contents_.replace_tree(VerifyTree(newrep));
+ auto constexpr method = CordzUpdateTracker::kRemovePrefix;
+ CordzUpdateScope scope(contents_.cordz_info(), method);
+ if (tree->tag == RING) {
+ tree = CordRepRing::RemovePrefix(tree->ring(), n);
+ } else {
+ CordRep* newrep = RemovePrefixFrom(tree, n);
+ CordRep::Unref(tree);
+ tree = VerifyTree(newrep);
+ }
+ contents_.SetTreeOrEmpty(tree, scope);
}
}
@@ -909,12 +923,17 @@ void Cord::RemoveSuffix(size_t n) {
CordRep* tree = contents_.tree();
if (tree == nullptr) {
contents_.reduce_size(n);
- } else if (tree->tag == RING) {
- contents_.replace_tree(CordRepRing::RemoveSuffix(tree->ring(), n));
} else {
- CordRep* newrep = RemoveSuffixFrom(tree, n);
- CordRep::Unref(tree);
- contents_.replace_tree(VerifyTree(newrep));
+ auto constexpr method = CordzUpdateTracker::kRemoveSuffix;
+ CordzUpdateScope scope(contents_.cordz_info(), method);
+ if (tree->tag == RING) {
+ tree = CordRepRing::RemoveSuffix(tree->ring(), n);
+ } else {
+ CordRep* newrep = RemoveSuffixFrom(tree, n);
+ CordRep::Unref(tree);
+ tree = VerifyTree(newrep);
+ }
+ contents_.SetTreeOrEmpty(tree, scope);
}
}
@@ -969,37 +988,51 @@ static CordRep* NewSubRange(CordRep* node, size_t pos, size_t n) {
return results[0];
}
+void Cord::CopyDataAtPosition(size_t pos, size_t new_size, char* dest) const {
+ assert(new_size <= cord_internal::kMaxInline);
+ assert(pos <= size());
+ assert(new_size <= size() - pos);
+ Cord::ChunkIterator it = chunk_begin();
+ it.AdvanceBytes(pos);
+ size_t remaining_size = new_size;
+ while (remaining_size > it->size()) {
+ cord_internal::SmallMemmove(dest, it->data(), it->size());
+ remaining_size -= it->size();
+ dest += it->size();
+ ++it;
+ }
+ cord_internal::SmallMemmove(dest, it->data(), remaining_size);
+}
+
Cord Cord::Subcord(size_t pos, size_t new_size) const {
Cord sub_cord;
size_t length = size();
if (pos > length) pos = length;
if (new_size > length - pos) new_size = length - pos;
+ if (new_size == 0) return sub_cord;
+
CordRep* tree = contents_.tree();
if (tree == nullptr) {
// sub_cord is newly constructed, no need to re-zero-out the tail of
// contents_ memory.
sub_cord.contents_.set_data(contents_.data() + pos, new_size, false);
- } else if (new_size == 0) {
- // We want to return empty subcord, so nothing to do.
- } else if (new_size <= InlineRep::kMaxInline) {
- Cord::ChunkIterator it = chunk_begin();
- it.AdvanceBytes(pos);
- char* dest = sub_cord.contents_.data_.as_chars();
- size_t remaining_size = new_size;
- while (remaining_size > it->size()) {
- cord_internal::SmallMemmove(dest, it->data(), it->size());
- remaining_size -= it->size();
- dest += it->size();
- ++it;
- }
- cord_internal::SmallMemmove(dest, it->data(), remaining_size);
+ return sub_cord;
+ }
+
+ if (new_size <= InlineRep::kMaxInline) {
+ CopyDataAtPosition(pos, new_size, sub_cord.contents_.data_.as_chars());
sub_cord.contents_.set_inline_size(new_size);
- } else if (tree->tag == RING) {
- tree = CordRepRing::SubRing(CordRep::Ref(tree)->ring(), pos, new_size);
- sub_cord.contents_.set_tree(tree);
+ return sub_cord;
+ }
+
+ if (tree->tag == RING) {
+ CordRepRing* ring = CordRep::Ref(tree)->ring();
+ tree = CordRepRing::SubRing(ring, pos, new_size);
} else {
- sub_cord.contents_.set_tree(NewSubRange(tree, pos, new_size));
+ tree = NewSubRange(tree, pos, new_size);
}
+ sub_cord.contents_.EmplaceTree(tree, contents_.data_,
+ CordzUpdateTracker::kSubCord);
return sub_cord;
}
@@ -1676,6 +1709,7 @@ char Cord::operator[](size_t i) const {
}
absl::string_view Cord::FlattenSlowPath() {
+ assert(contents_.is_tree());
size_t total_size = size();
CordRep* new_rep;
char* new_buffer;
@@ -1696,10 +1730,9 @@ absl::string_view Cord::FlattenSlowPath() {
s.size());
});
}
- if (CordRep* tree = contents_.tree()) {
- CordRep::Unref(tree);
- }
- contents_.set_tree(new_rep);
+ CordzUpdateScope scope(contents_.cordz_info(), CordzUpdateTracker::kFlatten);
+ CordRep::Unref(contents_.as_tree());
+ contents_.SetTree(new_rep, scope);
return absl::string_view(new_buffer, total_size);
}