1 // Copyright 2021 The Abseil Authors 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // https://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 #ifndef ABSL_STRINGS_INTERNAL_CORD_REP_RING_READER_H_ 16 #define ABSL_STRINGS_INTERNAL_CORD_REP_RING_READER_H_ 17 18 #include <cassert> 19 #include <cstddef> 20 #include <cstdint> 21 22 #include "absl/strings/internal/cord_internal.h" 23 #include "absl/strings/internal/cord_rep_ring.h" 24 #include "absl/strings/string_view.h" 25 26 namespace absl { 27 ABSL_NAMESPACE_BEGIN 28 namespace cord_internal { 29 30 // CordRepRingReader provides basic navigation over CordRepRing data. 31 class CordRepRingReader { 32 public: 33 // Returns true if this instance is not empty. 34 explicit operator bool() const { return ring_ != nullptr; } 35 36 // Returns the ring buffer reference for this instance, or nullptr if empty. ring()37 CordRepRing* ring() const { return ring_; } 38 39 // Returns the current node index inside the ring buffer for this instance. 40 // The returned value is undefined if this instance is empty. index()41 CordRepRing::index_type index() const { return index_; } 42 43 // Returns the current node inside the ring buffer for this instance. 44 // The returned value is undefined if this instance is empty. node()45 CordRep* node() const { return ring_->entry_child(index_); } 46 47 // Returns the length of the referenced ring buffer. 48 // Requires the current instance to be non empty. length()49 size_t length() const { 50 assert(ring_); 51 return ring_->length; 52 } 53 54 // Returns the end offset of the last navigated-to chunk, which represents the 55 // total bytes 'consumed' relative to the start of the ring. The returned 56 // value is never zero. For example, initializing a reader with a ring buffer 57 // with a first chunk of 19 bytes will return consumed() = 19. 58 // Requires the current instance to be non empty. consumed()59 size_t consumed() const { 60 assert(ring_); 61 return ring_->entry_end_offset(index_); 62 } 63 64 // Returns the number of bytes remaining beyond the last navigated-to chunk. 65 // Requires the current instance to be non empty. remaining()66 size_t remaining() const { 67 assert(ring_); 68 return length() - consumed(); 69 } 70 71 // Resets this instance to an empty value Reset()72 void Reset() { ring_ = nullptr; } 73 74 // Resets this instance to the start of `ring`. `ring` must not be null. 75 // Returns a reference into the first chunk of the provided ring. Reset(CordRepRing * ring)76 absl::string_view Reset(CordRepRing* ring) { 77 assert(ring); 78 ring_ = ring; 79 index_ = ring_->head(); 80 return ring_->entry_data(index_); 81 } 82 83 // Navigates to the next chunk inside the reference ring buffer. 84 // Returns a reference into the navigated-to chunk. 85 // Requires remaining() to be non zero. Next()86 absl::string_view Next() { 87 assert(remaining()); 88 index_ = ring_->advance(index_); 89 return ring_->entry_data(index_); 90 } 91 92 // Navigates to the chunk at offset `offset`. 93 // Returns a reference into the navigated-to chunk, adjusted for the relative 94 // position of `offset` into that chunk. For example, calling Seek(13) on a 95 // ring buffer containing 2 chunks of 10 and 20 bytes respectively will return 96 // a string view into the second chunk starting at offset 3 with a size of 17. 97 // Requires `offset` to be less than `length()` Seek(size_t offset)98 absl::string_view Seek(size_t offset) { 99 assert(offset < length()); 100 size_t current = ring_->entry_end_offset(index_); 101 CordRepRing::index_type hint = (offset >= current) ? index_ : ring_->head(); 102 const CordRepRing::Position head = ring_->Find(hint, offset); 103 index_ = head.index; 104 auto data = ring_->entry_data(head.index); 105 data.remove_prefix(head.offset); 106 return data; 107 } 108 109 private: 110 CordRepRing* ring_ = nullptr; 111 CordRepRing::index_type index_; 112 }; 113 114 } // namespace cord_internal 115 ABSL_NAMESPACE_END 116 } // namespace absl 117 118 #endif // ABSL_STRINGS_INTERNAL_CORD_REP_RING_READER_H_ 119