cord_rep_btree_navigator.cc
Go to the documentation of this file.
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 
16 
17 #include <cassert>
18 
20 #include "absl/strings/internal/cord_internal.h"
22 
23 namespace absl {
25 namespace cord_internal {
26 
28 
29 namespace {
30 
31 // Returns a `CordRepSubstring` from `rep` starting at `offset` of size `n`.
32 // If `rep` is already a `CordRepSubstring` instance, an adjusted instance is
33 // created based on the old offset and new offset.
34 // Adopts a reference on `rep`. Rep must be a valid data edge. Returns
35 // nullptr if `n == 0`, `rep` if `n == rep->length`.
36 // Requires `offset < rep->length` and `offset + n <= rep->length`.
37 // TODO(192061034): move to utility library in internal and optimize for small
38 // substrings of larger reps.
39 inline CordRep* Substring(CordRep* rep, size_t offset, size_t n) {
40  assert(n <= rep->length);
41  assert(offset < rep->length);
42  assert(offset <= rep->length - n);
43  assert(IsDataEdge(rep));
44 
45  if (n == 0) return nullptr;
46  if (n == rep->length) return CordRep::Ref(rep);
47 
48  if (rep->tag == SUBSTRING) {
49  offset += rep->substring()->start;
50  rep = rep->substring()->child;
51  }
52 
53  assert(rep->IsExternal() || rep->IsFlat());
54  CordRepSubstring* substring = new CordRepSubstring();
55  substring->length = n;
56  substring->tag = SUBSTRING;
57  substring->start = offset;
58  substring->child = CordRep::Ref(rep);
59  return substring;
60 }
61 
62 inline CordRep* Substring(CordRep* rep, size_t offset) {
63  return Substring(rep, offset, rep->length - offset);
64 }
65 
66 } // namespace
67 
69  int height = 0;
70  size_t index = index_[0];
71  CordRepBtree* node = node_[0];
72  CordRep* edge = node->Edge(index);
73 
74  // Overall logic: Find an edge of at least the length we need to skip.
75  // We consume all edges which are smaller (i.e., must be 100% skipped).
76  // If we exhausted all edges on the current level, we move one level
77  // up the tree, and repeat until we either find the edge, or until we hit
78  // the top of the tree meaning the skip exceeds tree->length.
79  while (n >= edge->length) {
80  n -= edge->length;
81  while (++index == node->end()) {
82  if (++height > height_) return {nullptr, n};
83  node = node_[height];
84  index = index_[height];
85  }
86  edge = node->Edge(index);
87  }
88 
89  // If we moved up the tree, descend down to the leaf level, consuming all
90  // edges that must be skipped.
91  while (height > 0) {
92  node = edge->btree();
93  index_[height] = index;
94  node_[--height] = node;
95  index = node->begin();
96  edge = node->Edge(index);
97  while (n >= edge->length) {
98  n -= edge->length;
99  ++index;
100  assert(index != node->end());
101  edge = node->Edge(index);
102  }
103  }
104  index_[0] = index;
105  return {edge, n};
106 }
107 
108 ReadResult CordRepBtreeNavigator::Read(size_t edge_offset, size_t n) {
109  int height = 0;
110  size_t length = edge_offset + n;
111  size_t index = index_[0];
112  CordRepBtree* node = node_[0];
113  CordRep* edge = node->Edge(index);
114  assert(edge_offset < edge->length);
115 
116  if (length < edge->length) {
117  return {Substring(edge, edge_offset, n), length};
118  }
119 
120  // Similar to 'Skip', we consume all edges that are inside the 'length' of
121  // data that needs to be read. If we exhaust the current level, we move one
122  // level up the tree and repeat until we hit the final edge that must be
123  // (partially) read. We consume all edges into `subtree`.
124  CordRepBtree* subtree = CordRepBtree::New(Substring(edge, edge_offset));
125  size_t subtree_end = 1;
126  do {
127  length -= edge->length;
128  while (++index == node->end()) {
129  index_[height] = index;
130  if (++height > height_) {
131  subtree->set_end(subtree_end);
132  if (length == 0) return {subtree, 0};
133  CordRep::Unref(subtree);
134  return {nullptr, length};
135  }
136  if (length != 0) {
137  subtree->set_end(subtree_end);
138  subtree = CordRepBtree::New(subtree);
139  subtree_end = 1;
140  }
141  node = node_[height];
142  index = index_[height];
143  }
144  edge = node->Edge(index);
145  if (length >= edge->length) {
146  subtree->length += edge->length;
147  subtree->edges_[subtree_end++] = CordRep::Ref(edge);
148  }
149  } while (length >= edge->length);
150  CordRepBtree* tree = subtree;
151  subtree->length += length;
152 
153  // If we moved up the tree, descend down to the leaf level, consuming all
154  // edges that must be read, adding 'down' nodes to `subtree`.
155  while (height > 0) {
156  node = edge->btree();
157  index_[height] = index;
158  node_[--height] = node;
159  index = node->begin();
160  edge = node->Edge(index);
161 
162  if (length != 0) {
164  right->length = length;
165  subtree->edges_[subtree_end++] = right;
166  subtree->set_end(subtree_end);
167  subtree = right;
168  subtree_end = 0;
169  while (length >= edge->length) {
170  subtree->edges_[subtree_end++] = CordRep::Ref(edge);
171  length -= edge->length;
172  edge = node->Edge(++index);
173  }
174  }
175  }
176  // Add any (partial) edge still remaining at the leaf level.
177  if (length != 0) {
178  subtree->edges_[subtree_end++] = Substring(edge, 0, length);
179  }
180  subtree->set_end(subtree_end);
181  index_[0] = index;
182  return {tree, length};
183 }
184 
185 } // namespace cord_internal
187 } // namespace absl
absl::cord_internal::CordRepBtree::end
size_t end() const
Definition: cord_rep_btree.h:290
cord_data_edge.h
absl::cord_internal::CordRepBtree::edges_
CordRep * edges_[kMaxCapacity]
Definition: cord_rep_btree.h:583
absl::cord_internal::CordRep::Unref
static void Unref(CordRep *rep)
Definition: abseil-cpp/absl/strings/internal/cord_internal.h:642
absl::cord_internal::CordRepBtree::set_end
void set_end(size_t end)
Definition: cord_rep_btree.h:387
absl::cord_internal::CordRepBtreeNavigator::node_
CordRepBtree * node_[CordRepBtree::kMaxDepth]
Definition: cord_rep_btree_navigator.h:147
ABSL_NAMESPACE_END
#define ABSL_NAMESPACE_END
Definition: third_party/abseil-cpp/absl/base/config.h:171
absl::cord_internal::CordRep
Definition: abseil-cpp/absl/strings/internal/cord_internal.h:209
absl::cord_internal::CordRepBtree::New
static CordRepBtree * New(int height=0)
Definition: cord_rep_btree.h:633
absl::cord_internal::CordRep::tag
uint8_t tag
Definition: abseil-cpp/absl/strings/internal/cord_internal.h:232
ABSL_NAMESPACE_BEGIN
#define ABSL_NAMESPACE_BEGIN
Definition: third_party/abseil-cpp/absl/base/config.h:170
absl::cord_internal::CordRepBtree::begin
size_t begin() const
Definition: cord_rep_btree.h:288
absl::cord_internal::CordRep::IsFlat
constexpr bool IsFlat() const
Definition: abseil-cpp/absl/strings/internal/cord_internal.h:249
cord_rep_btree.h
absl::cord_internal::CordRepBtreeNavigator::Read
ReadResult Read(size_t edge_offset, size_t n)
Definition: cord_rep_btree_navigator.cc:108
absl::cord_internal::CordRepSubstring::start
size_t start
Definition: abseil-cpp/absl/strings/internal/cord_internal.h:281
n
int n
Definition: abseil-cpp/absl/container/btree_test.cc:1080
absl::cord_internal::ReadResult
CordRepBtreeNavigator::ReadResult ReadResult
Definition: cord_rep_btree_navigator.cc:27
absl::cord_internal::CordRep::length
size_t length
Definition: abseil-cpp/absl/strings/internal/cord_internal.h:228
absl::cord_internal::CordRep::IsExternal
constexpr bool IsExternal() const
Definition: abseil-cpp/absl/strings/internal/cord_internal.h:248
absl::cord_internal::CordRep::btree
CordRepBtree * btree()
Definition: cord_rep_btree.h:589
absl::cord_internal::CordRepBtree
Definition: cord_rep_btree.h:63
index
int index
Definition: bloaty/third_party/protobuf/php/ext/google/protobuf/protobuf.h:1184
absl::cord_internal::CordRepBtreeNavigator::index_
uint8_t index_[CordRepBtree::kMaxDepth]
Definition: cord_rep_btree_navigator.h:146
absl::cord_internal::SUBSTRING
@ SUBSTRING
Definition: abseil-cpp/absl/strings/internal/cord_internal.h:179
absl::cord_internal::CordRepBtree::Edge
CordRep * Edge(size_t index) const
Definition: cord_rep_btree.h:606
rep
const CordRep * rep
Definition: cord_analysis.cc:53
absl::cord_internal::CordRep::Ref
static CordRep * Ref(CordRep *rep)
Definition: abseil-cpp/absl/strings/internal/cord_internal.h:634
absl::cord_internal::CordRepSubstring::child
CordRep * child
Definition: abseil-cpp/absl/strings/internal/cord_internal.h:282
absl::cord_internal::IsDataEdge
bool IsDataEdge(const CordRep *edge)
Definition: cord_data_edge.h:32
absl
Definition: abseil-cpp/absl/algorithm/algorithm.h:31
absl::cord_internal::CordRepBtreeNavigator::Position
Definition: cord_rep_btree_navigator.h:51
length
std::size_t length
Definition: abseil-cpp/absl/time/internal/test_util.cc:57
absl::cord_internal::CordRepBtreeNavigator::height_
int height_
Definition: cord_rep_btree_navigator.h:141
absl::cord_internal::CordRepSubstring
Definition: abseil-cpp/absl/strings/internal/cord_internal.h:280
cord_rep_btree_navigator.h
absl::cord_internal::CordRep::substring
CordRepSubstring * substring()
Definition: abseil-cpp/absl/strings/internal/cord_internal.h:614
absl::cord_internal::CordRepBtreeNavigator::Skip
Position Skip(size_t n)
Definition: cord_rep_btree_navigator.cc:68
absl::cord_internal::CordRepBtreeNavigator::ReadResult
Definition: cord_rep_btree_navigator.h:61
offset
voidpf uLong offset
Definition: bloaty/third_party/zlib/contrib/minizip/ioapi.h:142
height
int height
Definition: libuv/docs/code/tty-gravity/main.c:10


grpc
Author(s):
autogenerated on Fri May 16 2025 02:58:03