cord_rep_btree.h
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 
15 #ifndef ABSL_STRINGS_INTERNAL_CORD_REP_BTREE_H_
16 #define ABSL_STRINGS_INTERNAL_CORD_REP_BTREE_H_
17 
18 #include <cassert>
19 #include <cstdint>
20 #include <iosfwd>
21 
22 #include "absl/base/config.h"
23 #include "absl/base/internal/raw_logging.h"
24 #include "absl/base/optimization.h"
26 #include "absl/strings/internal/cord_internal.h"
27 #include "absl/strings/internal/cord_rep_flat.h"
28 #include "absl/strings/string_view.h"
29 #include "absl/types/span.h"
30 
31 namespace absl {
33 namespace cord_internal {
34 
35 class CordRepBtreeNavigator;
36 
37 // CordRepBtree is as the name implies a btree implementation of a Cordrep tree.
38 // Data is stored at the leaf level only, non leaf nodes contain down pointers
39 // only. Allowed types of data edges are FLAT, EXTERNAL and SUBSTRINGs of FLAT
40 // or EXTERNAL nodes. The implementation allows for data to be added to either
41 // end of the tree only, it does not provide any 'insert' logic. This has the
42 // benefit that we can expect good fill ratios: all nodes except the outer
43 // 'legs' will have 100% fill ratios for trees built using Append/Prepend
44 // methods. Merged trees will typically have a fill ratio well above 50% as in a
45 // similar fashion, one side of the merged tree will typically have a 100% fill
46 // ratio, and the 'open' end will average 50%. All operations are O(log(n)) or
47 // better, and the tree never needs balancing.
48 //
49 // All methods accepting a CordRep* or CordRepBtree* adopt a reference on that
50 // input unless explicitly stated otherwise. All functions returning a CordRep*
51 // or CordRepBtree* instance transfer a reference back to the caller.
52 // Simplified, callers both 'donate' and 'consume' a reference count on each
53 // call, simplifying the API. An example of building a tree:
54 //
55 // CordRepBtree* tree = CordRepBtree::Create(MakeFlat("Hello"));
56 // tree = CordRepBtree::Append(tree, MakeFlat("world"));
57 //
58 // In the above example, all inputs are consumed, making each call affecting
59 // `tree` reference count neutral. The returned `tree` value can be different
60 // from the input if the input is shared with other threads, or if the tree
61 // grows in height, but callers typically never have to concern themselves with
62 // that and trust that all methods DTRT at all times.
63 class CordRepBtree : public CordRep {
64  public:
65  // EdgeType identifies `front` and `back` enum values.
66  // Various implementations in CordRepBtree such as `Add` and `Edge` are
67  // generic and templated on operating on either of the boundary edges.
68  // For more information on the possible edges contained in a CordRepBtree
69  // instance see the documentation for `edges_`.
70  enum class EdgeType { kFront, kBack };
71 
72  // Convenience constants into `EdgeType`
73  static constexpr EdgeType kFront = EdgeType::kFront;
74  static constexpr EdgeType kBack = EdgeType::kBack;
75 
76  // Maximum number of edges: based on experiments and performance data, we can
77  // pick suitable values resulting in optimum cacheline aligned values. The
78  // preferred values are based on 64-bit systems where we aim to align this
79  // class onto 64 bytes, i.e.: 6 = 64 bytes, 14 = 128 bytes, etc.
80  // TODO(b/192061034): experiment with alternative sizes.
81  static constexpr size_t kMaxCapacity = 6;
82 
83  // Reasonable maximum height of the btree. We can expect a fill ratio of at
84  // least 50%: trees are always expanded at the front or back. Concatenating
85  // trees will then typically fold at the top most node, where the lower nodes
86  // are at least at capacity on one side of joined inputs. At a lower fill
87  // rate of 4 edges per node, we have capacity for ~16 million leaf nodes.
88  // We will fail / abort if an application ever exceeds this height, which
89  // should be extremely rare (near impossible) and be an indication of an
90  // application error: we do not assume it reasonable for any application to
91  // operate correctly with such monster trees.
92  // Another compelling reason for the number `12` is that any contextual stack
93  // required for navigation or insertion requires 12 words and 12 bytes, which
94  // fits inside 2 cache lines with some room to spare, and is reasonable as a
95  // local stack variable compared to Cord's current near 400 bytes stack use.
96  // The maximum `height` value of a node is then `kMaxDepth - 1` as node height
97  // values start with a value of 0 for leaf nodes.
98  static constexpr int kMaxDepth = 12;
99  static constexpr int kMaxHeight = kMaxDepth - 1;
100 
101  // `Action` defines the action for unwinding changes done at the btree's leaf
102  // level that need to be propagated up to the parent node(s). Each operation
103  // on a node has an effect / action defined as follows:
104  // - kSelf
105  // The operation (add / update, etc) was performed directly on the node as
106  // the node is private to the current thread (i.e.: not shared directly or
107  // indirectly through a refcount > 1). Changes can be propagated directly to
108  // all parent nodes as all parent nodes are also then private to the current
109  // thread.
110  // - kCopied
111  // The operation (add / update, etc) was performed on a copy of the original
112  // node, as the node is (potentially) directly or indirectly shared with
113  // other threads. Changes need to be propagated into the parent nodes where
114  // the old down pointer must be unreffed and replaced with this new copy.
115  // Such changes to parent nodes may themselves require a copy if the parent
116  // node is also shared. A kCopied action can propagate all the way to the
117  // top node where we then must unref the `tree` input provided by the
118  // caller, and return the new copy.
119  // - kPopped
120  // The operation (typically add) could not be satisfied due to insufficient
121  // capacity in the targeted node, and a new 'leg' was created that needs to
122  // be added into the parent node. For example, adding a FLAT inside a leaf
123  // node that is at capacity will create a new leaf node containing that
124  // FLAT, that needs to be 'popped' up the btree. Such 'pop' actions can
125  // cascade up the tree if parent nodes are also at capacity. A 'Popped'
126  // action propagating all the way to the top of the tree will result in
127  // the tree becoming one level higher than the current tree through a final
128  // `CordRepBtree::New(tree, popped)` call, resulting in a new top node
129  // referencing the old tree and the new (fully popped upwards) 'leg'.
131 
132  // Result of an operation on a node. See the `Action` enum for details.
133  struct OpResult {
136  };
137 
138  // Return value of the CopyPrefix and CopySuffix methods which can
139  // return a node or data edge at any height inside the tree.
140  // A height of 0 defines the lowest (leaf) node, a height of -1 identifies
141  // `edge` as being a plain data node: EXTERNAL / FLAT or SUBSTRING thereof.
142  struct CopyResult {
144  int height;
145  };
146 
147  // Logical position inside a node:
148  // - index: index of the edge.
149  // - n: size or offset value depending on context.
150  struct Position {
151  size_t index;
152  size_t n;
153  };
154 
155  // Creates a btree from the given input. Adopts a ref of `rep`.
156  // If the input `rep` is itself a btree, i.e., `IsBtree()`, then this
157  // function immediately returns `rep->btree()`. If the input is a valid data
158  // edge (see IsDataEdge()), then a new leaf node is returned containing `rep`
159  // as the sole data edge. Else, the input is assumed to be a (legacy) concat
160  // tree, and the input is consumed and transformed into a btree().
161  static CordRepBtree* Create(CordRep* rep);
162 
163  // Destroys the provided tree. Should only be called by cord internal API's,
164  // typically after a ref_count.Decrement() on the last reference count.
165  static void Destroy(CordRepBtree* tree);
166 
167  // Destruction
168  static void Delete(CordRepBtree* tree) { delete tree; }
169 
170  // Use CordRep::Unref() as we overload for absl::Span<CordRep* const>.
171  using CordRep::Unref;
172 
173  // Unrefs all edges in `edges` which are assumed to be 'likely one'.
174  static void Unref(absl::Span<CordRep* const> edges);
175 
176  // Appends / Prepends an existing CordRep instance to this tree.
177  // The below methods accept three types of input:
178  // 1) `rep` is a data node (See `IsDataNode` for valid data edges).
179  // `rep` is appended or prepended to this tree 'as is'.
180  // 2) `rep` is a BTREE.
181  // `rep` is merged into `tree` respecting the Append/Prepend order.
182  // 3) `rep` is some other (legacy) type.
183  // `rep` is converted in place and added to `tree`
184  // Requires `tree` and `rep` to be not null.
185  static CordRepBtree* Append(CordRepBtree* tree, CordRep* rep);
186  static CordRepBtree* Prepend(CordRepBtree* tree, CordRep* rep);
187 
188  // Append/Prepend the data in `data` to this tree.
189  // The `extra` parameter defines how much extra capacity should be allocated
190  // for any additional FLAT being allocated. This is an optimization hint from
191  // the caller. For example, a caller may need to add 2 string_views of data
192  // "abc" and "defghi" which are not consecutive. The caller can in this case
193  // invoke `AddData(tree, "abc", 6)`, and any newly added flat is allocated
194  // where possible with at least 6 bytes of extra capacity beyond `length`.
195  // This helps avoiding data getting fragmented over multiple flats.
196  // There is no limit on the size of `data`. If `data` can not be stored inside
197  // a single flat, then the function will iteratively add flats until all data
198  // has been consumed and appended or prepended to the tree.
200  size_t extra = 0);
202  size_t extra = 0);
203 
204  // Returns a new tree, containing `n` bytes of data from this instance
205  // starting at offset `offset`. Where possible, the returned tree shares
206  // (re-uses) data edges and nodes with this instance to minimize the
207  // combined memory footprint of both trees.
208  // Requires `offset + n <= length`. Returns `nullptr` if `n` is zero.
209  CordRep* SubTree(size_t offset, size_t n);
210 
211  // Removes `n` trailing bytes from `tree`, and returns the resulting tree
212  // or data edge. Returns `tree` if n is zero, and nullptr if n == length.
213  // This function is logically identical to:
214  // result = tree->SubTree(0, tree->length - n);
215  // Unref(tree);
216  // return result;
217  // However, the actual implementation will as much as possible perform 'in
218  // place' modifications on the tree on all nodes and edges that are mutable.
219  // For example, in a fully privately owned tree with the last edge being a
220  // flat of length 12, RemoveSuffix(1) will simply set the length of that data
221  // edge to 11, and reduce the length of all nodes on the edge path by 1.
222  static CordRep* RemoveSuffix(CordRepBtree* tree, size_t n);
223 
224  // Returns the character at the given offset.
225  char GetCharacter(size_t offset) const;
226 
227  // Returns true if this node holds a single data edge, and if so, sets
228  // `fragment` to reference the contained data. `fragment` is an optional
229  // output parameter and allowed to be null.
230  bool IsFlat(absl::string_view* fragment) const;
231 
232  // Returns true if the data of `n` bytes starting at offset `offset`
233  // is contained in a single data edge, and if so, sets fragment to reference
234  // the contained data. `fragment` is an optional output parameter and allowed
235  // to be null.
236  bool IsFlat(size_t offset, size_t n, absl::string_view* fragment) const;
237 
238  // Returns a span (mutable range of bytes) of up to `size` bytes into the
239  // last FLAT data edge inside this tree under the following conditions:
240  // - none of the nodes down into the FLAT node are shared.
241  // - the last data edge in this tree is a non-shared FLAT.
242  // - the referenced FLAT has additional capacity available.
243  // If all these conditions are met, a non-empty span is returned, and the
244  // length of the flat node and involved tree nodes have been increased by
245  // `span.length()`. The caller is responsible for immediately assigning values
246  // to all uninitialized data reference by the returned span.
247  // Requires `this->refcount.IsOne()`: this function forces the caller to do
248  // this fast path check on the top level node, as this is the most commonly
249  // shared node of a cord tree.
251 
252  // Extracts the right-most data edge from this tree iff:
253  // - the tree and all internal edges to the right-most node are not shared.
254  // - the right-most node is a FLAT node and not shared.
255  // - the right-most node has at least the desired extra capacity.
256  //
257  // Returns {tree, nullptr} if any of the above conditions are not met.
258  // This method effectively removes data from the tree. The intent of this
259  // method is to allow applications appending small string data to use
260  // pre-existing capacity, and add the modified rep back to the tree.
261  //
262  // Simplified such code would look similar to this:
263  // void MyTreeBuilder::Append(string_view data) {
264  // ExtractResult result = CordRepBtree::ExtractAppendBuffer(tree_, 1);
265  // if (CordRep* rep = result.extracted) {
266  // size_t available = rep->Capacity() - rep->length;
267  // size_t n = std::min(data.size(), n);
268  // memcpy(rep->Data(), data.data(), n);
269  // rep->length += n;
270  // data.remove_prefix(n);
271  // if (!result.tree->IsBtree()) {
272  // tree_ = CordRepBtree::Create(result.tree);
273  // }
274  // tree_ = CordRepBtree::Append(tree_, rep);
275  // }
276  // ...
277  // // Remaining edge in `result.tree`.
278  // }
279  static ExtractResult ExtractAppendBuffer(CordRepBtree* tree,
280  size_t extra_capacity = 1);
281 
282  // Returns the `height` of the tree. The height of a tree is limited to
283  // kMaxHeight. `height` is implemented as an `int` as in some places we
284  // use negative (-1) values for 'data edges'.
285  int height() const { return static_cast<int>(storage[0]); }
286 
287  // Properties: begin, back, end, front/back boundary indexes.
288  size_t begin() const { return static_cast<size_t>(storage[1]); }
289  size_t back() const { return static_cast<size_t>(storage[2]) - 1; }
290  size_t end() const { return static_cast<size_t>(storage[2]); }
291  size_t index(EdgeType edge) const {
292  return edge == kFront ? begin() : back();
293  }
294 
295  // Properties: size and capacity.
296  // `capacity` contains the current capacity of this instance, where
297  // `kMaxCapacity` contains the maximum capacity of a btree node.
298  // For now, `capacity` and `kMaxCapacity` return the same value, but this may
299  // change in the future if we see benefit in dynamically sizing 'small' nodes
300  // to 'large' nodes for large data trees.
301  size_t size() const { return end() - begin(); }
302  size_t capacity() const { return kMaxCapacity; }
303 
304  // Edge access
305  inline CordRep* Edge(size_t index) const;
306  inline CordRep* Edge(EdgeType edge_type) const;
307  inline absl::Span<CordRep* const> Edges() const;
308  inline absl::Span<CordRep* const> Edges(size_t begin, size_t end) const;
309 
310  // Returns reference to the data edge at `index`.
311  // Requires this instance to be a leaf node, and `index` to be valid index.
312  inline absl::string_view Data(size_t index) const;
313 
314  // Diagnostics: returns true if `tree` is valid and internally consistent.
315  // If `shallow` is false, then the provided top level node and all child nodes
316  // below it are recursively checked. If `shallow` is true, only the provided
317  // node in `tree` and the cumulative length, type and height of the direct
318  // child nodes of `tree` are checked. The value of `shallow` is ignored if the
319  // internal `cord_btree_exhaustive_validation` diagnostics variable is true,
320  // in which case the performed validations works as if `shallow` were false.
321  // This function is intended for debugging and testing purposes only.
322  static bool IsValid(const CordRepBtree* tree, bool shallow = false);
323 
324  // Diagnostics: asserts that the provided tree is valid.
325  // `AssertValid()` performs a shallow validation by default. `shallow` can be
326  // set to false in which case an exhaustive validation is performed. This
327  // function is implemented in terms of calling `IsValid()` and asserting the
328  // return value to be true. See `IsValid()` for more information.
329  // This function is intended for debugging and testing purposes only.
330  static CordRepBtree* AssertValid(CordRepBtree* tree, bool shallow = true);
331  static const CordRepBtree* AssertValid(const CordRepBtree* tree,
332  bool shallow = true);
333 
334  // Diagnostics: dump the contents of this tree to `stream`.
335  // This function is intended for debugging and testing purposes only.
336  static void Dump(const CordRep* rep, std::ostream& stream);
337  static void Dump(const CordRep* rep, absl::string_view label,
338  std::ostream& stream);
339  static void Dump(const CordRep* rep, absl::string_view label,
340  bool include_contents, std::ostream& stream);
341 
342  // Adds the edge `edge` to this node if possible. `owned` indicates if the
343  // current node is potentially shared or not with other threads. Returns:
344  // - {kSelf, <this>}
345  // The edge was directly added to this node.
346  // - {kCopied, <node>}
347  // The edge was added to a copy of this node.
348  // - {kPopped, New(edge, height())}
349  // A new leg with the edge was created as this node has no extra capacity.
350  template <EdgeType edge_type>
351  inline OpResult AddEdge(bool owned, CordRep* edge, size_t delta);
352 
353  // Replaces the front or back edge with the provided new edge. Returns:
354  // - {kSelf, <this>}
355  // The edge was directly set in this node. The old edge is unreffed.
356  // - {kCopied, <node>}
357  // A copy of this node was created with the new edge value.
358  // In both cases, the function adopts a reference on `edge`.
359  template <EdgeType edge_type>
360  OpResult SetEdge(bool owned, CordRep* edge, size_t delta);
361 
362  // Creates a new empty node at the specified height.
363  static CordRepBtree* New(int height = 0);
364 
365  // Creates a new node containing `rep`, with the height being computed
366  // automatically based on the type of `rep`.
367  static CordRepBtree* New(CordRep* rep);
368 
369  // Creates a new node containing both `front` and `back` at height
370  // `front.height() + 1`. Requires `back.height() == front.height()`.
371  static CordRepBtree* New(CordRepBtree* front, CordRepBtree* back);
372 
373  // Creates a fully balanced tree from the provided tree by rebuilding a new
374  // tree from all data edges in the input. This function is automatically
375  // invoked internally when the tree exceeds the maximum height.
376  static CordRepBtree* Rebuild(CordRepBtree* tree);
377 
378  private:
379  CordRepBtree() = default;
380  ~CordRepBtree() = default;
381 
382  // Initializes the main properties `tag`, `begin`, `end`, `height`.
383  inline void InitInstance(int height, size_t begin = 0, size_t end = 0);
384 
385  // Direct property access begin / end
386  void set_begin(size_t begin) { storage[1] = static_cast<uint8_t>(begin); }
387  void set_end(size_t end) { storage[2] = static_cast<uint8_t>(end); }
388 
389  // Decreases the value of `begin` by `n`, and returns the new value. Notice
390  // how this returns the new value unlike atomic::fetch_add which returns the
391  // old value. This is because this is used to prepend edges at 'begin - 1'.
392  size_t sub_fetch_begin(size_t n) {
393  storage[1] -= static_cast<uint8_t>(n);
394  return storage[1];
395  }
396 
397  // Increases the value of `end` by `n`, and returns the previous value. This
398  // function is typically used to append edges at 'end'.
399  size_t fetch_add_end(size_t n) {
400  const uint8_t current = storage[2];
401  storage[2] = static_cast<uint8_t>(current + n);
402  return current;
403  }
404 
405  // Returns the index of the last edge starting on, or before `offset`, with
406  // `n` containing the relative offset of `offset` inside that edge.
407  // Requires `offset` < length.
408  Position IndexOf(size_t offset) const;
409 
410  // Returns the index of the last edge starting before `offset`, with `n`
411  // containing the relative offset of `offset` inside that edge.
412  // This function is useful to find the edges for some span of bytes ending at
413  // `offset` (i.e., `n` bytes). For example:
414  //
415  // Position pos = IndexBefore(n)
416  // edges = Edges(begin(), pos.index) // All full edges (may be empty)
417  // last = Sub(Edge(pos.index), 0, pos.n) // Last partial edge (may be empty)
418  //
419  // Requires 0 < `offset` <= length.
420  Position IndexBefore(size_t offset) const;
421 
422  // Returns the index of the edge ending at (or on) length `length`, and the
423  // number of bytes inside that edge up to `length`. For example, if we have a
424  // Node with 2 edges, one of 10 and one of 20 long, then IndexOfLength(27)
425  // will return {1, 17}, and IndexOfLength(10) will return {0, 10}.
426  Position IndexOfLength(size_t n) const;
427 
428  // Identical to the above function except starting from the position `front`.
429  // This function is equivalent to `IndexBefore(front.n + offset)`, with
430  // the difference that this function is optimized to start at `front.index`.
431  Position IndexBefore(Position front, size_t offset) const;
432 
433  // Returns the index of the edge directly beyond the edge containing offset
434  // `offset`, with `n` containing the distance of that edge from `offset`.
435  // This function is useful for iteratively finding suffix nodes and remaining
436  // partial bytes in left-most suffix nodes as for example in CopySuffix.
437  // Requires `offset` < length.
438  Position IndexBeyond(size_t offset) const;
439 
440  // Creates a new leaf node containing as much data as possible from `data`.
441  // The data is added either forwards or reversed depending on `edge_type`.
442  // Callers must check the length of the returned node to determine if all data
443  // was copied or not.
444  // See the `Append/Prepend` function for the meaning and purpose of `extra`.
445  template <EdgeType edge_type>
446  static CordRepBtree* NewLeaf(absl::string_view data, size_t extra);
447 
448  // Creates a raw copy of this Btree node, copying all properties, but
449  // without adding any references to existing edges.
450  CordRepBtree* CopyRaw() const;
451 
452  // Creates a full copy of this Btree node, adding a reference on all edges.
453  CordRepBtree* Copy() const;
454 
455  // Creates a partial copy of this Btree node, copying all edges up to `end`,
456  // adding a reference on each copied edge, and sets the length of the newly
457  // created copy to `new_length`.
458  CordRepBtree* CopyBeginTo(size_t end, size_t new_length) const;
459 
460  // Returns a tree containing the edges [tree->begin(), end) and length
461  // of `new_length`. This method consumes a reference on the provided
462  // tree, and logically performs the following operation:
463  // result = tree->CopyBeginTo(end, new_length);
464  // CordRep::Unref(tree);
465  // return result;
466  static CordRepBtree* ConsumeBeginTo(CordRepBtree* tree, size_t end,
467  size_t new_length);
468 
469  // Creates a partial copy of this Btree node, copying all edges starting at
470  // `begin`, adding a reference on each copied edge, and sets the length of
471  // the newly created copy to `new_length`.
472  CordRepBtree* CopyToEndFrom(size_t begin, size_t new_length) const;
473 
474  // Extracts and returns the front edge from the provided tree.
475  // This method consumes a reference on the provided tree, and logically
476  // performs the following operation:
477  // edge = CordRep::Ref(tree->Edge(kFront));
478  // CordRep::Unref(tree);
479  // return edge;
480  static CordRep* ExtractFront(CordRepBtree* tree);
481 
482  // Returns a tree containing the result of appending `right` to `left`.
483  static CordRepBtree* MergeTrees(CordRepBtree* left, CordRepBtree* right);
484 
485  // Fallback functions for `Create()`, `Append()` and `Prepend()` which
486  // deal with legacy / non conforming input, i.e.: CONCAT trees.
490 
491  // Recursively rebuilds `tree` into `stack`. If 'consume` is set to true, the
492  // function will consume a reference on `tree`. `stack` is a null terminated
493  // array containing the new tree's state, with the current leaf node at
494  // stack[0], and parent nodes above that, or null for 'top of tree'.
495  static void Rebuild(CordRepBtree** stack, CordRepBtree* tree, bool consume);
496 
497  // Aligns existing edges to start at index 0, to allow for a new edge to be
498  // added to the back of the current edges.
499  inline void AlignBegin();
500 
501  // Aligns existing edges to end at `capacity`, to allow for a new edge to be
502  // added in front of the current edges.
503  inline void AlignEnd();
504 
505  // Adds the provided edge to this node.
506  // Requires this node to have capacity for the edge. Realigns / moves
507  // existing edges as needed to prepend or append the new edge.
508  template <EdgeType edge_type>
509  inline void Add(CordRep* rep);
510 
511  // Adds the provided edges to this node.
512  // Requires this node to have capacity for the edges. Realigns / moves
513  // existing edges as needed to prepend or append the new edges.
514  template <EdgeType edge_type>
515  inline void Add(absl::Span<CordRep* const>);
516 
517  // Adds data from `data` to this node until either all data has been consumed,
518  // or there is no more capacity for additional flat nodes inside this node.
519  // Requires the current node to be a leaf node, data to be non empty, and the
520  // current node to have capacity for at least one more data edge.
521  // Returns any remaining data from `data` that was not added, which is
522  // depending on the edge type (front / back) either the remaining prefix of
523  // suffix of the input.
524  // See the `Append/Prepend` function for the meaning and purpose of `extra`.
525  template <EdgeType edge_type>
527 
528  // Replace the front or back edge with the provided value.
529  // Adopts a reference on `edge` and unrefs the old edge.
530  template <EdgeType edge_type>
531  inline void SetEdge(CordRep* edge);
532 
533  // Returns a partial copy of the current tree containing the first `n` bytes
534  // of data. `CopyResult` contains both the resulting edge and its height. The
535  // resulting tree may be less high than the current tree, or even be a single
536  // matching data edge if `allow_folding` is set to true.
537  // For example, if `n == 1`, then the result will be the single data edge, and
538  // height will be set to -1 (one below the owning leaf node). If n == 0, this
539  // function returns null. Requires `n <= length`
540  CopyResult CopyPrefix(size_t n, bool allow_folding = true);
541 
542  // Returns a partial copy of the current tree containing all data starting
543  // after `offset`. `CopyResult` contains both the resulting edge and its
544  // height. The resulting tree may be less high than the current tree, or even
545  // be a single matching data edge. For example, if `n == length - 1`, then the
546  // result will be a single data edge, and height will be set to -1 (one below
547  // the owning leaf node).
548  // Requires `offset < length`
549  CopyResult CopySuffix(size_t offset);
550 
551  // Returns a OpResult value of {this, kSelf} or {Copy(), kCopied}
552  // depending on the value of `owned`.
553  inline OpResult ToOpResult(bool owned);
554 
555  // Adds `rep` to the specified tree, returning the modified tree.
556  template <EdgeType edge_type>
558 
559  // Adds `data` to the specified tree, returning the modified tree.
560  // See the `Append/Prepend` function for the meaning and purpose of `extra`.
561  template <EdgeType edge_type>
563  size_t extra = 0);
564 
565  // Merges `src` into `dst` with `src` being added either before (kFront) or
566  // after (kBack) `dst`. Requires the height of `dst` to be greater than or
567  // equal to the height of `src`.
568  template <EdgeType edge_type>
570 
571  // Fallback version of GetAppendBuffer for large trees: GetAppendBuffer()
572  // implements an inlined version for trees of limited height (3 levels),
573  // GetAppendBufferSlow implements the logic for large trees.
575 
576  // `edges_` contains all edges starting from this instance.
577  // These are explicitly `child` edges only, a cord btree (or any cord tree in
578  // that respect) does not store `parent` pointers anywhere: multiple trees /
579  // parents can reference the same shared child edge. The type of these edges
580  // depends on the height of the node. `Leaf nodes` (height == 0) contain `data
581  // edges` (external or flat nodes, or sub-strings thereof). All other nodes
582  // (height > 0) contain pointers to BTREE nodes with a height of `height - 1`.
584 
585  friend class CordRepBtreeTestPeer;
586  friend class CordRepBtreeNavigator;
587 };
588 
590  assert(IsBtree());
591  return static_cast<CordRepBtree*>(this);
592 }
593 
594 inline const CordRepBtree* CordRep::btree() const {
595  assert(IsBtree());
596  return static_cast<const CordRepBtree*>(this);
597 }
598 
599 inline void CordRepBtree::InitInstance(int height, size_t begin, size_t end) {
600  tag = BTREE;
601  storage[0] = static_cast<uint8_t>(height);
602  storage[1] = static_cast<uint8_t>(begin);
603  storage[2] = static_cast<uint8_t>(end);
604 }
605 
606 inline CordRep* CordRepBtree::Edge(size_t index) const {
607  assert(index >= begin());
608  assert(index < end());
609  return edges_[index];
610 }
611 
612 inline CordRep* CordRepBtree::Edge(EdgeType edge_type) const {
613  return edges_[edge_type == kFront ? begin() : back()];
614 }
615 
617  return {edges_ + begin(), size()};
618 }
619 
621  size_t end) const {
622  assert(begin <= end);
623  assert(begin >= this->begin());
624  assert(end <= this->end());
625  return {edges_ + begin, static_cast<size_t>(end - begin)};
626 }
627 
629  assert(height() == 0);
630  return EdgeData(Edge(index));
631 }
632 
634  CordRepBtree* tree = new CordRepBtree;
635  tree->length = 0;
636  tree->InitInstance(height);
637  return tree;
638 }
639 
641  CordRepBtree* tree = new CordRepBtree;
642  int height = rep->IsBtree() ? rep->btree()->height() + 1 : 0;
643  tree->length = rep->length;
644  tree->InitInstance(height, /*begin=*/0, /*end=*/1);
645  tree->edges_[0] = rep;
646  return tree;
647 }
648 
650  CordRepBtree* back) {
651  assert(front->height() == back->height());
652  CordRepBtree* tree = new CordRepBtree;
653  tree->length = front->length + back->length;
654  tree->InitInstance(front->height() + 1, /*begin=*/0, /*end=*/2);
655  tree->edges_[0] = front;
656  tree->edges_[1] = back;
657  return tree;
658 }
659 
661  for (CordRep* edge : edges) {
662  if (ABSL_PREDICT_FALSE(!edge->refcount.Decrement())) {
663  CordRep::Destroy(edge);
664  }
665  }
666 }
667 
669  auto* tree = static_cast<CordRepBtree*>(::operator new(sizeof(CordRepBtree)));
670  memcpy(static_cast<void*>(tree), this, sizeof(CordRepBtree));
671  new (&tree->refcount) RefcountAndFlags;
672  return tree;
673 }
674 
676  CordRepBtree* tree = CopyRaw();
677  for (CordRep* rep : Edges()) CordRep::Ref(rep);
678  return tree;
679 }
680 
682  size_t new_length) const {
683  assert(begin >= this->begin());
684  assert(begin <= this->end());
685  CordRepBtree* tree = CopyRaw();
686  tree->length = new_length;
687  tree->set_begin(begin);
688  for (CordRep* edge : tree->Edges()) CordRep::Ref(edge);
689  return tree;
690 }
691 
693  size_t new_length) const {
694  assert(end <= capacity());
695  assert(end >= this->begin());
696  CordRepBtree* tree = CopyRaw();
697  tree->length = new_length;
698  tree->set_end(end);
699  for (CordRep* edge : tree->Edges()) CordRep::Ref(edge);
700  return tree;
701 }
702 
704  // The below code itself does not need to be fast as typically we have
705  // mono-directional append/prepend calls, and `begin` / `end` are typically
706  // adjusted no more than once. But we want to avoid potential register clobber
707  // effects, making the compiler emit register save/store/spills, and minimize
708  // the size of code.
709  const size_t delta = begin();
710  if (ABSL_PREDICT_FALSE(delta != 0)) {
711  const size_t new_end = end() - delta;
712  set_begin(0);
713  set_end(new_end);
714  // TODO(mvels): we can write this using 2 loads / 2 stores depending on
715  // total size for the kMaxCapacity = 6 case. I.e., we can branch (switch) on
716  // size, and then do overlapping load/store of up to 4 pointers (inlined as
717  // XMM, YMM or ZMM load/store) and up to 2 pointers (XMM / YMM), which is a)
718  // compact and b) not clobbering any registers.
719  ABSL_ASSUME(new_end <= kMaxCapacity);
720 #ifdef __clang__
721 #pragma unroll 1
722 #endif
723  for (size_t i = 0; i < new_end; ++i) {
724  edges_[i] = edges_[i + delta];
725  }
726  }
727 }
728 
729 inline void CordRepBtree::AlignEnd() {
730  // See comments in `AlignBegin` for motivation on the hand-rolled for loops.
731  const size_t delta = capacity() - end();
732  if (delta != 0) {
733  const size_t new_begin = begin() + delta;
734  const size_t new_end = end() + delta;
735  set_begin(new_begin);
736  set_end(new_end);
737  ABSL_ASSUME(new_end <= kMaxCapacity);
738 #ifdef __clang__
739 #pragma unroll 1
740 #endif
741  for (size_t i = new_end - 1; i >= new_begin; --i) {
742  edges_[i] = edges_[i - delta];
743  }
744  }
745 }
746 
747 template <>
748 inline void CordRepBtree::Add<CordRepBtree::kBack>(CordRep* rep) {
749  AlignBegin();
750  edges_[fetch_add_end(1)] = rep;
751 }
752 
753 template <>
754 inline void CordRepBtree::Add<CordRepBtree::kBack>(
756  AlignBegin();
757  size_t new_end = end();
758  for (CordRep* edge : edges) edges_[new_end++] = edge;
759  set_end(new_end);
760 }
761 
762 template <>
763 inline void CordRepBtree::Add<CordRepBtree::kFront>(CordRep* rep) {
764  AlignEnd();
765  edges_[sub_fetch_begin(1)] = rep;
766 }
767 
768 template <>
769 inline void CordRepBtree::Add<CordRepBtree::kFront>(
771  AlignEnd();
772  size_t new_begin = begin() - edges.size();
773  set_begin(new_begin);
774  for (CordRep* edge : edges) edges_[new_begin++] = edge;
775 }
776 
777 template <CordRepBtree::EdgeType edge_type>
778 inline void CordRepBtree::SetEdge(CordRep* edge) {
779  const int idx = edge_type == kFront ? begin() : back();
781  edges_[idx] = edge;
782 }
783 
785  return owned ? OpResult{this, kSelf} : OpResult{Copy(), kCopied};
786 }
787 
789  assert(offset < length);
790  size_t index = begin();
791  while (offset >= edges_[index]->length) offset -= edges_[index++]->length;
792  return {index, offset};
793 }
794 
796  assert(offset > 0);
797  assert(offset <= length);
798  size_t index = begin();
799  while (offset > edges_[index]->length) offset -= edges_[index++]->length;
800  return {index, offset};
801 }
802 
804  size_t offset) const {
805  size_t index = front.index;
806  offset = offset + front.n;
807  while (offset > edges_[index]->length) offset -= edges_[index++]->length;
808  return {index, offset};
809 }
810 
812  assert(n <= length);
813  size_t index = back();
814  size_t strip = length - n;
815  while (strip >= edges_[index]->length) strip -= edges_[index--]->length;
816  return {index, edges_[index]->length - strip};
817 }
818 
820  const size_t offset) const {
821  // We need to find the edge which `starting offset` is beyond (>=)`offset`.
822  // For this we can't use the `offset -= length` logic of IndexOf. Instead, we
823  // track the offset of the `current edge` in `off`, which we increase as we
824  // iterate over the edges until we find the matching edge.
825  size_t off = 0;
826  size_t index = begin();
827  while (offset > off) off += edges_[index++]->length;
828  return {index, off - offset};
829 }
830 
832  if (IsDataEdge(rep)) return New(rep);
833  return CreateSlow(rep);
834 }
835 
837  assert(refcount.IsOne());
838  CordRepBtree* tree = this;
839  const int height = this->height();
840  CordRepBtree* n1 = tree;
841  CordRepBtree* n2 = tree;
842  CordRepBtree* n3 = tree;
843  switch (height) {
844  case 3:
845  tree = tree->Edge(kBack)->btree();
846  if (!tree->refcount.IsOne()) return {};
847  n2 = tree;
849  case 2:
850  tree = tree->Edge(kBack)->btree();
851  if (!tree->refcount.IsOne()) return {};
852  n1 = tree;
854  case 1:
855  tree = tree->Edge(kBack)->btree();
856  if (!tree->refcount.IsOne()) return {};
858  case 0:
859  CordRep* edge = tree->Edge(kBack);
860  if (!edge->refcount.IsOne()) return {};
861  if (edge->tag < FLAT) return {};
862  size_t avail = edge->flat()->Capacity() - edge->length;
863  if (avail == 0) return {};
864  size_t delta = (std::min)(size, avail);
865  Span<char> span = {edge->flat()->Data() + edge->length, delta};
866  edge->length += delta;
867  switch (height) {
868  case 3:
869  n3->length += delta;
871  case 2:
872  n2->length += delta;
874  case 1:
875  n1->length += delta;
877  case 0:
878  tree->length += delta;
879  return span;
880  }
881  break;
882  }
883  return GetAppendBufferSlow(size);
884 }
885 
886 extern template CordRepBtree* CordRepBtree::AddCordRep<CordRepBtree::kBack>(
887  CordRepBtree* tree, CordRep* rep);
888 
889 extern template CordRepBtree* CordRepBtree::AddCordRep<CordRepBtree::kFront>(
890  CordRepBtree* tree, CordRep* rep);
891 
894  return CordRepBtree::AddCordRep<kBack>(tree, rep);
895  }
896  return AppendSlow(tree, rep);
897 }
898 
901  return CordRepBtree::AddCordRep<kFront>(tree, rep);
902  }
903  return PrependSlow(tree, rep);
904 }
905 
906 #ifdef NDEBUG
907 
909  bool /* shallow */) {
910  return tree;
911 }
912 
913 inline const CordRepBtree* CordRepBtree::AssertValid(const CordRepBtree* tree,
914  bool /* shallow */) {
915  return tree;
916 }
917 
918 #endif
919 
920 } // namespace cord_internal
922 } // namespace absl
923 
924 #endif // ABSL_STRINGS_INTERNAL_CORD_REP_BTREE_H_
ABSL_PREDICT_FALSE
#define ABSL_PREDICT_FALSE(x)
Definition: abseil-cpp/absl/base/optimization.h:180
absl::cord_internal::CordRepBtree::end
size_t end() const
Definition: cord_rep_btree.h:290
dst
static const char dst[]
Definition: test-fs-copyfile.c:37
absl::cord_internal::CordRepBtree::Action
Action
Definition: cord_rep_btree.h:130
absl::cord_internal::CordRepBtree::kMaxCapacity
static constexpr size_t kMaxCapacity
Definition: cord_rep_btree.h:81
cord_data_edge.h
absl::cord_internal::CordRep::IsBtree
constexpr bool IsBtree() const
Definition: abseil-cpp/absl/strings/internal/cord_internal.h:250
absl::cord_internal::CordRepBtree::EdgeType::kBack
@ kBack
absl::cord_internal::CordRepBtree::CopyBeginTo
CordRepBtree * CopyBeginTo(size_t end, size_t new_length) const
Definition: cord_rep_btree.h:692
absl::cord_internal::EdgeData
absl::string_view EdgeData(const CordRep *edge)
Definition: cord_data_edge.h:45
absl::cord_internal::CordRepBtree::edges_
CordRep * edges_[kMaxCapacity]
Definition: cord_rep_btree.h:583
absl::cord_internal::CordRepBtree::Position::index
size_t index
Definition: cord_rep_btree.h:151
absl::cord_internal::CordRepBtree::PrependSlow
static CordRepBtree * PrependSlow(CordRepBtree *, CordRep *rep)
Definition: cord_rep_btree.cc:1063
begin
char * begin
Definition: abseil-cpp/absl/strings/internal/str_format/float_conversion.cc:1007
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::CordRepBtree::capacity
size_t capacity() const
Definition: cord_rep_btree.h:302
absl::cord_internal::CordRepBtree::CordRepBtree
CordRepBtree()=default
absl::cord_internal::CordRepBtree::IndexBefore
Position IndexBefore(size_t offset) const
Definition: cord_rep_btree.h:795
absl::cord_internal::CordRepBtree::CopyResult::height
int height
Definition: cord_rep_btree.h:144
absl::Span
Definition: abseil-cpp/absl/types/span.h:152
absl::cord_internal::CordRep::storage
uint8_t storage[3]
Definition: abseil-cpp/absl/strings/internal/cord_internal.h:242
absl::cord_internal::CordRepBtree::set_begin
void set_begin(size_t begin)
Definition: cord_rep_btree.h:386
absl::string_view
Definition: abseil-cpp/absl/strings/string_view.h:167
absl::cord_internal::CordRepFlat::Capacity
size_t Capacity() const
Definition: abseil-cpp/absl/strings/internal/cord_rep_flat.h:166
absl::cord_internal::CordRepBtree::Copy
CordRepBtree * Copy() const
Definition: cord_rep_btree.h:675
absl::cord_internal::CordRepBtree::CopyToEndFrom
CordRepBtree * CopyToEndFrom(size_t begin, size_t new_length) const
Definition: cord_rep_btree.h:681
absl::cord_internal::CordRepBtree::EdgeType::kFront
@ kFront
absl::cord_internal::CordRepBtree::IndexOf
Position IndexOf(size_t offset) const
Definition: cord_rep_btree.h:788
absl::cord_internal::CordRepBtree::Data
absl::string_view Data(size_t index) const
Definition: cord_rep_btree.h:628
ABSL_NAMESPACE_END
#define ABSL_NAMESPACE_END
Definition: third_party/abseil-cpp/absl/base/config.h:171
uint8_t
unsigned char uint8_t
Definition: stdint-msvc2008.h:78
absl::cord_internal::CordRepBtree::kMaxHeight
static constexpr int kMaxHeight
Definition: cord_rep_btree.h:99
absl::cord_internal::CordRep
Definition: abseil-cpp/absl/strings/internal/cord_internal.h:209
absl::cord_internal::CordRepBtree::Prepend
static CordRepBtree * Prepend(CordRepBtree *tree, CordRep *rep)
Definition: cord_rep_btree.h:899
absl::cord_internal::CordRepBtree::AlignEnd
void AlignEnd()
Definition: cord_rep_btree.h:729
absl::cord_internal::CordRepBtree::Add
void Add(CordRep *rep)
absl::cord_internal::CordRepBtree::AddData
absl::string_view AddData(absl::string_view data, size_t extra)
absl::cord_internal::CordRepBtree::RemoveSuffix
static CordRep * RemoveSuffix(CordRepBtree *tree, size_t n)
Definition: cord_rep_btree.cc:828
absl::cord_internal::CordRepBtree::CopyPrefix
CopyResult CopyPrefix(size_t n, bool allow_folding=true)
Definition: cord_rep_btree.cc:745
absl::cord_internal::CordRepBtree::New
static CordRepBtree * New(int height=0)
Definition: cord_rep_btree.h:633
absl::cord_internal::CordRepBtree::kFront
static constexpr EdgeType kFront
Definition: cord_rep_btree.h:73
absl::cord_internal::CordRepBtree::Delete
static void Delete(CordRepBtree *tree)
Definition: cord_rep_btree.h:168
absl::cord_internal::CordRep::tag
uint8_t tag
Definition: abseil-cpp/absl/strings/internal/cord_internal.h:232
absl::cord_internal::CordRepBtree::OpResult::action
Action action
Definition: cord_rep_btree.h:135
absl::cord_internal::CordRepBtreeNavigator
Definition: cord_rep_btree_navigator.h:46
memcpy
memcpy(mem, inblock.get(), min(CONTAINING_RECORD(inblock.get(), MEMBLOCK, data) ->size, size))
absl::cord_internal::CordRepBtree::EdgeType
EdgeType
Definition: cord_rep_btree.h:70
absl::cord_internal::CordRepBtree::kMaxDepth
static constexpr int kMaxDepth
Definition: cord_rep_btree.h:98
absl::cord_internal::CordRepBtree::kPopped
@ kPopped
Definition: cord_rep_btree.h:130
absl::cord_internal::CordRepBtree::GetCharacter
char GetCharacter(size_t offset) const
Definition: cord_rep_btree.cc:988
ABSL_NAMESPACE_BEGIN
#define ABSL_NAMESPACE_BEGIN
Definition: third_party/abseil-cpp/absl/base/config.h:170
absl::cord_internal::CordRepBtree::Dump
static void Dump(const CordRep *rep, std::ostream &stream)
Definition: cord_rep_btree.cc:380
end
char * end
Definition: abseil-cpp/absl/strings/internal/str_format/float_conversion.cc:1008
absl::cord_internal::CordRepBtree::size
size_t size() const
Definition: cord_rep_btree.h:301
gen_synthetic_protos.label
label
Definition: gen_synthetic_protos.py:102
absl::cord_internal::CordRepBtree::~CordRepBtree
~CordRepBtree()=default
absl::cord_internal::CordRepBtree::Destroy
static void Destroy(CordRepBtree *tree)
Definition: cord_rep_btree.cc:401
absl::cord_internal::CordRepBtree::InitInstance
void InitInstance(int height, size_t begin=0, size_t end=0)
Definition: cord_rep_btree.h:599
absl::cord_internal::CordRep::refcount
RefcountAndFlags refcount
Definition: abseil-cpp/absl/strings/internal/cord_internal.h:229
absl::cord_internal::CordRepBtree::SetEdge
OpResult SetEdge(bool owned, CordRep *edge, size_t delta)
Definition: cord_rep_btree.cc:491
absl::cord_internal::FLAT
@ FLAT
Definition: abseil-cpp/absl/strings/internal/cord_internal.h:194
absl::cord_internal::CordRepBtreeTestPeer
Definition: cord_rep_btree_test.cc:38
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
absl::cord_internal::CordRepBtree::Merge
static CordRepBtree * Merge(CordRepBtree *dst, CordRepBtree *src)
Definition: cord_rep_btree.cc:647
absl::cord_internal::CordRepBtree::IndexBeyond
Position IndexBeyond(size_t offset) const
Definition: cord_rep_btree.h:819
stack
NodeStack stack
Definition: cord_rep_btree.cc:356
data
char data[kBufferLength]
Definition: abseil-cpp/absl/strings/internal/str_format/float_conversion.cc:1006
absl::cord_internal::CordRepBtree::Position::n
size_t n
Definition: cord_rep_btree.h:152
absl::cord_internal::CordRepBtree::Create
static CordRepBtree * Create(CordRep *rep)
Definition: cord_rep_btree.h:831
absl::cord_internal::CordRepBtree::AlignBegin
void AlignBegin()
Definition: cord_rep_btree.h:703
absl::cord_internal::CordRepBtree::index
size_t index(EdgeType edge) const
Definition: cord_rep_btree.h:291
absl::cord_internal::CordRepBtree::CopyRaw
CordRepBtree * CopyRaw() const
Definition: cord_rep_btree.h:668
min
#define min(a, b)
Definition: qsort.h:83
absl::cord_internal::CordRepBtree::IndexOfLength
Position IndexOfLength(size_t n) const
Definition: cord_rep_btree.h:811
absl::cord_internal::CordRepBtree::AppendSlow
static CordRepBtree * AppendSlow(CordRepBtree *, CordRep *rep)
Definition: cord_rep_btree.cc:1051
absl::cord_internal::RefcountAndFlags
Definition: abseil-cpp/absl/strings/internal/cord_internal.h:96
absl::cord_internal::CordRepBtree::ExtractAppendBuffer
static ExtractResult ExtractAppendBuffer(CordRepBtree *tree, size_t extra_capacity=1)
Definition: cord_rep_btree.cc:1153
n
int n
Definition: abseil-cpp/absl/container/btree_test.cc:1080
setup.idx
idx
Definition: third_party/bloaty/third_party/capstone/bindings/python/setup.py:197
absl::cord_internal::CordRepBtree::Append
static CordRepBtree * Append(CordRepBtree *tree, CordRep *rep)
Definition: cord_rep_btree.h:892
ABSL_PREDICT_TRUE
#define ABSL_PREDICT_TRUE(x)
Definition: abseil-cpp/absl/base/optimization.h:181
absl::cord_internal::CordRepBtree::AddCordRep
static CordRepBtree * AddCordRep(CordRepBtree *tree, CordRep *rep)
Definition: cord_rep_btree.cc:514
absl::cord_internal::CordRepBtree::CopySuffix
CopyResult CopySuffix(size_t offset)
Definition: cord_rep_btree.cc:686
absl::cord_internal::CordRepBtree::GetAppendBuffer
Span< char > GetAppendBuffer(size_t size)
Definition: cord_rep_btree.h:836
absl::cord_internal::CordRep::length
size_t length
Definition: abseil-cpp/absl/strings/internal/cord_internal.h:228
absl::cord_internal::CordRep::Destroy
static void Destroy(CordRep *rep)
Definition: abseil-cpp/absl/strings/internal/cord_internal.cc:43
absl::cord_internal::CordRepBtree::MergeTrees
static CordRepBtree * MergeTrees(CordRepBtree *left, CordRepBtree *right)
Definition: cord_rep_btree.cc:954
absl::cord_internal::CordRepBtree::SubTree
CordRep * SubTree(size_t offset, size_t n)
Definition: cord_rep_btree.cc:892
absl::cord_internal::CordRepBtree::OpResult::tree
CordRepBtree * tree
Definition: cord_rep_btree.h:134
absl::cord_internal::CordRepBtree::IsValid
static bool IsValid(const CordRepBtree *tree, bool shallow=false)
Definition: cord_rep_btree.cc:417
absl::cord_internal::BTREE
@ BTREE
Definition: abseil-cpp/absl/strings/internal/cord_internal.h:181
absl::cord_internal::CordRepBtree::kCopied
@ kCopied
Definition: cord_rep_btree.h:130
absl::cord_internal::CordRep::btree
CordRepBtree * btree()
Definition: cord_rep_btree.h:589
absl::cord_internal::CordRepBtree::kSelf
@ kSelf
Definition: cord_rep_btree.h:130
absl::cord_internal::CordRepBtree::CopyResult::edge
CordRep * edge
Definition: cord_rep_btree.h:143
ABSL_ASSUME
#define ABSL_ASSUME(cond)
Definition: abseil-cpp/absl/base/optimization.h:209
absl::cord_internal::CordRepBtree
Definition: cord_rep_btree.h:63
absl::cord_internal::CordRepBtree::AddEdge
OpResult AddEdge(bool owned, CordRep *edge, size_t delta)
Definition: cord_rep_btree.cc:482
absl::cord_internal::CordRepBtree::Rebuild
static CordRepBtree * Rebuild(CordRepBtree *tree)
Definition: cord_rep_btree.cc:1134
absl::Span::size
constexpr size_type size() const noexcept
Definition: abseil-cpp/absl/types/span.h:261
index
int index
Definition: bloaty/third_party/protobuf/php/ext/google/protobuf/protobuf.h:1184
absl::cord_internal::CordRepFlat::Data
char * Data()
Definition: abseil-cpp/absl/strings/internal/cord_rep_flat.h:162
absl::cord_internal::CordRepBtree::NewLeaf
static CordRepBtree * NewLeaf(absl::string_view data, size_t extra)
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::CordRepBtree::Edges
absl::Span< CordRep *const > Edges() const
Definition: cord_rep_btree.h:616
absl::cord_internal::CordRep::Ref
static CordRep * Ref(CordRep *rep)
Definition: abseil-cpp/absl/strings/internal/cord_internal.h:634
absl::cord_internal::CordRepBtree::CopyResult
Definition: cord_rep_btree.h:142
absl::cord_internal::CordRepBtree::ExtractFront
static CordRep * ExtractFront(CordRepBtree *tree)
Definition: cord_rep_btree.cc:801
absl::cord_internal::CordRepBtree::AssertValid
static CordRepBtree * AssertValid(CordRepBtree *tree, bool shallow=true)
Definition: cord_rep_btree.cc:462
absl::cord_internal::CordRepBtree::ConsumeBeginTo
static CordRepBtree * ConsumeBeginTo(CordRepBtree *tree, size_t end, size_t new_length)
Definition: cord_rep_btree.cc:813
absl::cord_internal::CordRepBtree::sub_fetch_begin
size_t sub_fetch_begin(size_t n)
Definition: cord_rep_btree.h:392
absl::cord_internal::CordRepBtree::Position
Definition: cord_rep_btree.h:150
absl::cord_internal::IsDataEdge
bool IsDataEdge(const CordRep *edge)
Definition: cord_data_edge.h:32
absl::cord_internal::CordRepBtree::OpResult
Definition: cord_rep_btree.h:133
absl::cord_internal::CordRepBtree::back
size_t back() const
Definition: cord_rep_btree.h:289
absl
Definition: abseil-cpp/absl/algorithm/algorithm.h:31
absl::cord_internal::CordRepBtree::height
int height() const
Definition: cord_rep_btree.h:285
absl::cord_internal::CordRepBtree::kBack
static constexpr EdgeType kBack
Definition: cord_rep_btree.h:74
size
voidpf void uLong size
Definition: bloaty/third_party/zlib/contrib/minizip/ioapi.h:136
ABSL_FALLTHROUGH_INTENDED
#define ABSL_FALLTHROUGH_INTENDED
Definition: abseil-cpp/absl/base/attributes.h:641
absl::cord_internal::CordRepBtree::Unref
static void Unref(absl::Span< CordRep *const > edges)
Definition: cord_rep_btree.h:660
absl::cord_internal::RefcountAndFlags::IsOne
bool IsOne()
Definition: abseil-cpp/absl/strings/internal/cord_internal.h:144
absl::cord_internal::CordRepBtree::fetch_add_end
size_t fetch_add_end(size_t n)
Definition: cord_rep_btree.h:399
i
uint64_t i
Definition: abseil-cpp/absl/container/btree_benchmark.cc:230
absl::cord_internal::CordRepBtree::CreateSlow
static CordRepBtree * CreateSlow(CordRep *rep)
Definition: cord_rep_btree.cc:1035
offset
voidpf uLong offset
Definition: bloaty/third_party/zlib/contrib/minizip/ioapi.h:142
owned
bool owned
Definition: src/php/ext/grpc/call.h:31
absl::cord_internal::CordRepBtree::GetAppendBufferSlow
Span< char > GetAppendBufferSlow(size_t size)
Definition: cord_rep_btree.cc:1000
height
int height
Definition: libuv/docs/code/tty-gravity/main.c:10
absl::cord_internal::CordRepBtree::ToOpResult
OpResult ToOpResult(bool owned)
Definition: cord_rep_btree.h:784
absl::cord_internal::CordRep::flat
CordRepFlat * flat()
Definition: abseil-cpp/absl/strings/internal/cord_rep_flat.h:173
stream
voidpf stream
Definition: bloaty/third_party/zlib/contrib/minizip/ioapi.h:136


grpc
Author(s):
autogenerated on Thu Mar 13 2025 02:58:56