• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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