diff options
Diffstat (limited to 'absl/strings/cord.h')
-rw-r--r-- | absl/strings/cord.h | 43 |
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); } } |