summaryrefslogtreecommitdiff
path: root/absl/strings/cord.h
diff options
context:
space:
mode:
Diffstat (limited to 'absl/strings/cord.h')
-rw-r--r--absl/strings/cord.h43
1 files changed, 41 insertions, 2 deletions
diff --git a/absl/strings/cord.h b/absl/strings/cord.h
index abef98fe..17341bda 100644
--- a/absl/strings/cord.h
+++ b/absl/strings/cord.h
@@ -78,6 +78,8 @@
#include "absl/functional/function_ref.h"
#include "absl/meta/type_traits.h"
#include "absl/strings/internal/cord_internal.h"
+#include "absl/strings/internal/cord_rep_ring.h"
+#include "absl/strings/internal/cord_rep_ring_reader.h"
#include "absl/strings/internal/resize_uninitialized.h"
#include "absl/strings/internal/string_constant.h"
#include "absl/strings/string_view.h"
@@ -361,6 +363,10 @@ class Cord {
friend class CharIterator;
private:
+ using CordRep = absl::cord_internal::CordRep;
+ using CordRepRing = absl::cord_internal::CordRepRing;
+ using CordRepRingReader = absl::cord_internal::CordRepRingReader;
+
// Stack of right children of concat nodes that we have to visit.
// Keep this at the end of the structure to avoid cache-thrashing.
// TODO(jgm): Benchmark to see if there's a more optimal value than 47 for
@@ -385,6 +391,10 @@ class Cord {
// Stack specific operator++
ChunkIterator& AdvanceStack();
+ // Ring buffer specific operator++
+ ChunkIterator& AdvanceRing();
+ void AdvanceBytesRing(size_t n);
+
// Iterates `n` bytes, where `n` is expected to be greater than or equal to
// `current_chunk_.size()`.
void AdvanceBytesSlowPath(size_t n);
@@ -398,6 +408,10 @@ class Cord {
absl::cord_internal::CordRep* current_leaf_ = nullptr;
// The number of bytes left in the `Cord` over which we are iterating.
size_t bytes_remaining_ = 0;
+
+ // Cord reader for ring buffers. Empty if not traversing a ring buffer.
+ CordRepRingReader ring_reader_;
+
// See 'Stack' alias definition.
Stack stack_of_right_children_;
};
@@ -1107,6 +1121,11 @@ inline bool Cord::StartsWith(absl::string_view rhs) const {
}
inline void Cord::ChunkIterator::InitTree(cord_internal::CordRep* tree) {
+ if (tree->tag == cord_internal::RING) {
+ current_chunk_ = ring_reader_.Reset(tree->ring());
+ return;
+ }
+
stack_of_right_children_.push_back(tree);
operator++();
}
@@ -1126,13 +1145,33 @@ inline Cord::ChunkIterator::ChunkIterator(const Cord* cord)
}
}
+inline Cord::ChunkIterator& Cord::ChunkIterator::AdvanceRing() {
+ current_chunk_ = ring_reader_.Next();
+ return *this;
+}
+
+inline void Cord::ChunkIterator::AdvanceBytesRing(size_t n) {
+ assert(n >= current_chunk_.size());
+ bytes_remaining_ -= n;
+ if (bytes_remaining_) {
+ if (n == current_chunk_.size()) {
+ current_chunk_ = ring_reader_.Next();
+ } else {
+ size_t offset = ring_reader_.length() - bytes_remaining_;
+ current_chunk_ = ring_reader_.Seek(offset);
+ }
+ } else {
+ current_chunk_ = {};
+ }
+}
+
inline Cord::ChunkIterator& Cord::ChunkIterator::operator++() {
ABSL_HARDENING_ASSERT(bytes_remaining_ > 0 &&
"Attempted to iterate past `end()`");
assert(bytes_remaining_ >= current_chunk_.size());
bytes_remaining_ -= current_chunk_.size();
if (bytes_remaining_ > 0) {
- return AdvanceStack();
+ return ring_reader_ ? AdvanceRing() : AdvanceStack();
} else {
current_chunk_ = {};
}
@@ -1174,7 +1213,7 @@ inline void Cord::ChunkIterator::AdvanceBytes(size_t n) {
if (ABSL_PREDICT_TRUE(n < current_chunk_.size())) {
RemoveChunkPrefix(n);
} else if (n != 0) {
- AdvanceBytesSlowPath(n);
+ ring_reader_ ? AdvanceBytesRing(n) : AdvanceBytesSlowPath(n);
}
}