Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-01-18 09:27:25

0001 // Copyright 2021 The Abseil Authors
0002 //
0003 // Licensed under the Apache License, Version 2.0 (the "License");
0004 // you may not use this file except in compliance with the License.
0005 // You may obtain a copy of the License at
0006 //
0007 //     https://www.apache.org/licenses/LICENSE-2.0
0008 //
0009 // Unless required by applicable law or agreed to in writing, software
0010 // distributed under the License is distributed on an "AS IS" BASIS,
0011 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
0012 // See the License for the specific language governing permissions and
0013 // limitations under the License.
0014 
0015 #ifndef ABSL_STRINGS_INTERNAL_CORD_REP_BTREE_NAVIGATOR_H_
0016 #define ABSL_STRINGS_INTERNAL_CORD_REP_BTREE_NAVIGATOR_H_
0017 
0018 #include <cassert>
0019 #include <iostream>
0020 
0021 #include "absl/strings/internal/cord_internal.h"
0022 #include "absl/strings/internal/cord_rep_btree.h"
0023 
0024 namespace absl {
0025 ABSL_NAMESPACE_BEGIN
0026 namespace cord_internal {
0027 
0028 // CordRepBtreeNavigator is a bi-directional navigator allowing callers to
0029 // navigate all the (leaf) data edges in a CordRepBtree instance.
0030 //
0031 // A CordRepBtreeNavigator instance is by default empty. Callers initialize a
0032 // navigator instance by calling one of `InitFirst()`, `InitLast()` or
0033 // `InitOffset()`, which establishes a current position. Callers can then
0034 // navigate using the `Next`, `Previous`, `Skip` and `Seek` methods.
0035 //
0036 // The navigator instance does not take or adopt a reference on the provided
0037 // `tree` on any of the initialization calls. Callers are responsible for
0038 // guaranteeing the lifecycle of the provided tree. A navigator instance can
0039 // be reset to the empty state by calling `Reset`.
0040 //
0041 // A navigator only keeps positional state on the 'current data edge', it does
0042 // explicitly not keep any 'offset' state. The class does accept and return
0043 // offsets in the `Read()`, `Skip()` and 'Seek()` methods as these would
0044 // otherwise put a big burden on callers. Callers are expected to maintain
0045 // (returned) offset info if they require such granular state.
0046 class CordRepBtreeNavigator {
0047  public:
0048   // The logical position as returned by the Seek() and Skip() functions.
0049   // Returns the current leaf edge for the desired seek or skip position and
0050   // the offset of that position inside that edge.
0051   struct Position {
0052     CordRep* edge;
0053     size_t offset;
0054   };
0055 
0056   // The read result as returned by the Read() function.
0057   // `tree` contains the resulting tree which is identical to the result
0058   // of calling CordRepBtree::SubTree(...) on the tree being navigated.
0059   // `n` contains the number of bytes used from the last navigated to
0060   // edge of the tree.
0061   struct ReadResult {
0062     CordRep* tree;
0063     size_t n;
0064   };
0065 
0066   // Returns true if this instance is not empty.
0067   explicit operator bool() const;
0068 
0069   // Returns the tree for this instance or nullptr if empty.
0070   CordRepBtree* btree() const;
0071 
0072   // Returns the data edge of the current position.
0073   // Requires this instance to not be empty.
0074   CordRep* Current() const;
0075 
0076   // Resets this navigator to `tree`, returning the first data edge in the tree.
0077   CordRep* InitFirst(CordRepBtree* tree);
0078 
0079   // Resets this navigator to `tree`, returning the last data edge in the tree.
0080   CordRep* InitLast(CordRepBtree* tree);
0081 
0082   // Resets this navigator to `tree` returning the data edge at position
0083   // `offset` and the relative offset of `offset` into that data edge.
0084   // Returns `Position.edge = nullptr` if the provided offset is greater
0085   // than or equal to the length of the tree, in which case the state of
0086   // the navigator instance remains unchanged.
0087   Position InitOffset(CordRepBtree* tree, size_t offset);
0088 
0089   // Navigates to the next data edge.
0090   // Returns the next data edge or nullptr if there is no next data edge, in
0091   // which case the current position remains unchanged.
0092   CordRep* Next();
0093 
0094   // Navigates to the previous data edge.
0095   // Returns the previous data edge or nullptr if there is no previous data
0096   // edge, in which case the current position remains unchanged.
0097   CordRep* Previous();
0098 
0099   // Navigates to the data edge at position `offset`. Returns the navigated to
0100   // data edge in `Position.edge` and the relative offset of `offset` into that
0101   // data edge in `Position.offset`. Returns `Position.edge = nullptr` if the
0102   // provide offset is greater than or equal to the tree's length.
0103   Position Seek(size_t offset);
0104 
0105   // Reads `n` bytes of data starting at offset `edge_offset` of the current
0106   // data edge, and returns the result in `ReadResult.tree`. `ReadResult.n`
0107   // contains the 'bytes used` from the last / current data edge in the tree.
0108   // This allows users that mix regular navigation (using string views) and
0109   // 'read into cord' navigation to keep track of the current state, and which
0110   // bytes have been consumed from a navigator.
0111   // This function returns `ReadResult.tree = nullptr` if the requested length
0112   // exceeds the length of the tree starting at the current data edge.
0113   ReadResult Read(size_t edge_offset, size_t n);
0114 
0115   // Skips `n` bytes forward from the current data edge, returning the navigated
0116   // to data edge in `Position.edge` and `Position.offset` containing the offset
0117   // inside that data edge. Note that the state of the navigator is left
0118   // unchanged if `n` is smaller than the length of the current data edge.
0119   Position Skip(size_t n);
0120 
0121   // Resets this instance to the default / empty state.
0122   void Reset();
0123 
0124  private:
0125   // Slow path for Next() if Next() reached the end of a leaf node. Backtracks
0126   // up the stack until it finds a node that has a 'next' position available,
0127   // and then does a 'front dive' towards the next leaf node.
0128   CordRep* NextUp();
0129 
0130   // Slow path for Previous() if Previous() reached the beginning of a leaf
0131   // node. Backtracks up the stack until it finds a node that has a 'previous'
0132   // position available, and then does a 'back dive' towards the previous leaf
0133   // node.
0134   CordRep* PreviousUp();
0135 
0136   // Generic implementation of InitFirst() and InitLast().
0137   template <CordRepBtree::EdgeType edge_type>
0138   CordRep* Init(CordRepBtree* tree);
0139 
0140   // `height_` contains the height of the current tree, or -1 if empty.
0141   int height_ = -1;
0142 
0143   // `index_` and `node_` contain the navigation state as the 'path' to the
0144   // current data edge which is at `node_[0]->Edge(index_[0])`. The contents
0145   // of these are undefined until the instance is initialized (`height_ >= 0`).
0146   uint8_t index_[CordRepBtree::kMaxDepth];
0147   CordRepBtree* node_[CordRepBtree::kMaxDepth];
0148 };
0149 
0150 // Returns true if this instance is not empty.
0151 inline CordRepBtreeNavigator::operator bool() const { return height_ >= 0; }
0152 
0153 inline CordRepBtree* CordRepBtreeNavigator::btree() const {
0154   return height_ >= 0 ? node_[height_] : nullptr;
0155 }
0156 
0157 inline CordRep* CordRepBtreeNavigator::Current() const {
0158   assert(height_ >= 0);
0159   return node_[0]->Edge(index_[0]);
0160 }
0161 
0162 inline void CordRepBtreeNavigator::Reset() { height_ = -1; }
0163 
0164 inline CordRep* CordRepBtreeNavigator::InitFirst(CordRepBtree* tree) {
0165   return Init<CordRepBtree::kFront>(tree);
0166 }
0167 
0168 inline CordRep* CordRepBtreeNavigator::InitLast(CordRepBtree* tree) {
0169   return Init<CordRepBtree::kBack>(tree);
0170 }
0171 
0172 template <CordRepBtree::EdgeType edge_type>
0173 inline CordRep* CordRepBtreeNavigator::Init(CordRepBtree* tree) {
0174   assert(tree != nullptr);
0175   assert(tree->size() > 0);
0176   assert(tree->height() <= CordRepBtree::kMaxHeight);
0177   int height = height_ = tree->height();
0178   size_t index = tree->index(edge_type);
0179   node_[height] = tree;
0180   index_[height] = static_cast<uint8_t>(index);
0181   while (--height >= 0) {
0182     tree = tree->Edge(index)->btree();
0183     node_[height] = tree;
0184     index = tree->index(edge_type);
0185     index_[height] = static_cast<uint8_t>(index);
0186   }
0187   return node_[0]->Edge(index);
0188 }
0189 
0190 inline CordRepBtreeNavigator::Position CordRepBtreeNavigator::Seek(
0191     size_t offset) {
0192   assert(btree() != nullptr);
0193   int height = height_;
0194   CordRepBtree* edge = node_[height];
0195   if (ABSL_PREDICT_FALSE(offset >= edge->length)) return {nullptr, 0};
0196   CordRepBtree::Position index = edge->IndexOf(offset);
0197   index_[height] = static_cast<uint8_t>(index.index);
0198   while (--height >= 0) {
0199     edge = edge->Edge(index.index)->btree();
0200     node_[height] = edge;
0201     index = edge->IndexOf(index.n);
0202     index_[height] = static_cast<uint8_t>(index.index);
0203   }
0204   return {edge->Edge(index.index), index.n};
0205 }
0206 
0207 inline CordRepBtreeNavigator::Position CordRepBtreeNavigator::InitOffset(
0208     CordRepBtree* tree, size_t offset) {
0209   assert(tree != nullptr);
0210   assert(tree->height() <= CordRepBtree::kMaxHeight);
0211   if (ABSL_PREDICT_FALSE(offset >= tree->length)) return {nullptr, 0};
0212   height_ = tree->height();
0213   node_[height_] = tree;
0214   return Seek(offset);
0215 }
0216 
0217 inline CordRep* CordRepBtreeNavigator::Next() {
0218   CordRepBtree* edge = node_[0];
0219   return index_[0] == edge->back() ? NextUp() : edge->Edge(++index_[0]);
0220 }
0221 
0222 inline CordRep* CordRepBtreeNavigator::Previous() {
0223   CordRepBtree* edge = node_[0];
0224   return index_[0] == edge->begin() ? PreviousUp() : edge->Edge(--index_[0]);
0225 }
0226 
0227 inline CordRep* CordRepBtreeNavigator::NextUp() {
0228   assert(index_[0] == node_[0]->back());
0229   CordRepBtree* edge;
0230   size_t index;
0231   int height = 0;
0232   do {
0233     if (++height > height_) return nullptr;
0234     edge = node_[height];
0235     index = index_[height] + 1;
0236   } while (index == edge->end());
0237   index_[height] = static_cast<uint8_t>(index);
0238   do {
0239     node_[--height] = edge = edge->Edge(index)->btree();
0240     index_[height] = static_cast<uint8_t>(index = edge->begin());
0241   } while (height > 0);
0242   return edge->Edge(index);
0243 }
0244 
0245 inline CordRep* CordRepBtreeNavigator::PreviousUp() {
0246   assert(index_[0] == node_[0]->begin());
0247   CordRepBtree* edge;
0248   size_t index;
0249   int height = 0;
0250   do {
0251     if (++height > height_) return nullptr;
0252     edge = node_[height];
0253     index = index_[height];
0254   } while (index == edge->begin());
0255   index_[height] = static_cast<uint8_t>(--index);
0256   do {
0257     node_[--height] = edge = edge->Edge(index)->btree();
0258     index_[height] = static_cast<uint8_t>(index = edge->back());
0259   } while (height > 0);
0260   return edge->Edge(index);
0261 }
0262 
0263 }  // namespace cord_internal
0264 ABSL_NAMESPACE_END
0265 }  // namespace absl
0266 
0267 #endif  // ABSL_STRINGS_INTERNAL_CORD_REP_BTREE_NAVIGATOR_H_