clang API Documentation

RewriteRope.h
Go to the documentation of this file.
00001 //===--- RewriteRope.h - Rope specialized for rewriter ----------*- C++ -*-===//
00002 //
00003 //                     The LLVM Compiler Infrastructure
00004 //
00005 // This file is distributed under the University of Illinois Open Source
00006 // License. See LICENSE.TXT for details.
00007 //
00008 //===----------------------------------------------------------------------===//
00009 //
00010 //  This file defines the RewriteRope class, which is a powerful string class.
00011 //
00012 //===----------------------------------------------------------------------===//
00013 
00014 #ifndef LLVM_CLANG_REWRITE_CORE_REWRITEROPE_H
00015 #define LLVM_CLANG_REWRITE_CORE_REWRITEROPE_H
00016 
00017 #include "llvm/ADT/IntrusiveRefCntPtr.h"
00018 #include "llvm/ADT/StringRef.h"
00019 #include "llvm/Support/Compiler.h"
00020 #include <cassert>
00021 #include <cstddef>
00022 #include <cstring>
00023 #include <iterator>
00024 
00025 namespace clang {
00026   //===--------------------------------------------------------------------===//
00027   // RopeRefCountString Class
00028   //===--------------------------------------------------------------------===//
00029 
00030   /// RopeRefCountString - This struct is allocated with 'new char[]' from the
00031   /// heap, and represents a reference counted chunk of string data.  When its
00032   /// ref count drops to zero, it is delete[]'d.  This is primarily managed
00033   /// through the RopePiece class below.
00034   struct RopeRefCountString {
00035     unsigned RefCount;
00036     char Data[1];  //  Variable sized.
00037 
00038     void Retain() { ++RefCount; }
00039 
00040     void Release() {
00041       assert(RefCount > 0 && "Reference count is already zero.");
00042       if (--RefCount == 0)
00043         delete [] (char*)this;
00044     }
00045   };
00046 
00047   //===--------------------------------------------------------------------===//
00048   // RopePiece Class
00049   //===--------------------------------------------------------------------===//
00050 
00051   /// RopePiece - This class represents a view into a RopeRefCountString object.
00052   /// This allows references to string data to be efficiently chopped up and
00053   /// moved around without having to push around the string data itself.
00054   ///
00055   /// For example, we could have a 1M RopePiece and want to insert something
00056   /// into the middle of it.  To do this, we split it into two RopePiece objects
00057   /// that both refer to the same underlying RopeRefCountString (just with
00058   /// different offsets) which is a nice constant time operation.
00059   struct RopePiece {
00060     llvm::IntrusiveRefCntPtr<RopeRefCountString> StrData;
00061     unsigned StartOffs;
00062     unsigned EndOffs;
00063 
00064     RopePiece() : StrData(nullptr), StartOffs(0), EndOffs(0) {}
00065 
00066     RopePiece(llvm::IntrusiveRefCntPtr<RopeRefCountString> Str, unsigned Start,
00067               unsigned End)
00068         : StrData(std::move(Str)), StartOffs(Start), EndOffs(End) {}
00069 
00070     const char &operator[](unsigned Offset) const {
00071       return StrData->Data[Offset+StartOffs];
00072     }
00073     char &operator[](unsigned Offset) {
00074       return StrData->Data[Offset+StartOffs];
00075     }
00076 
00077     unsigned size() const { return EndOffs-StartOffs; }
00078   };
00079 
00080   //===--------------------------------------------------------------------===//
00081   // RopePieceBTreeIterator Class
00082   //===--------------------------------------------------------------------===//
00083 
00084   /// RopePieceBTreeIterator - This class provides read-only forward iteration
00085   /// over bytes that are in a RopePieceBTree.  This first iterates over bytes
00086   /// in a RopePiece, then iterates over RopePiece's in a RopePieceBTreeLeaf,
00087   /// then iterates over RopePieceBTreeLeaf's in a RopePieceBTree.
00088   class RopePieceBTreeIterator :
00089       public std::iterator<std::forward_iterator_tag, const char, ptrdiff_t> {
00090     /// CurNode - The current B+Tree node that we are inspecting.
00091     const void /*RopePieceBTreeLeaf*/ *CurNode;
00092     /// CurPiece - The current RopePiece in the B+Tree node that we're
00093     /// inspecting.
00094     const RopePiece *CurPiece;
00095     /// CurChar - The current byte in the RopePiece we are pointing to.
00096     unsigned CurChar;
00097   public:
00098     // begin iterator.
00099     RopePieceBTreeIterator(const void /*RopePieceBTreeNode*/ *N);
00100     // end iterator
00101     RopePieceBTreeIterator()
00102       : CurNode(nullptr), CurPiece(nullptr), CurChar(0) {}
00103 
00104     char operator*() const {
00105       return (*CurPiece)[CurChar];
00106     }
00107 
00108     bool operator==(const RopePieceBTreeIterator &RHS) const {
00109       return CurPiece == RHS.CurPiece && CurChar == RHS.CurChar;
00110     }
00111     bool operator!=(const RopePieceBTreeIterator &RHS) const {
00112       return !operator==(RHS);
00113     }
00114 
00115     RopePieceBTreeIterator& operator++() {   // Preincrement
00116       if (CurChar+1 < CurPiece->size())
00117         ++CurChar;
00118       else
00119         MoveToNextPiece();
00120       return *this;
00121     }
00122     inline RopePieceBTreeIterator operator++(int) { // Postincrement
00123       RopePieceBTreeIterator tmp = *this; ++*this; return tmp;
00124     }
00125 
00126     llvm::StringRef piece() const {
00127       return llvm::StringRef(&(*CurPiece)[0], CurPiece->size());
00128     }
00129 
00130     void MoveToNextPiece();
00131   };
00132 
00133   //===--------------------------------------------------------------------===//
00134   // RopePieceBTree Class
00135   //===--------------------------------------------------------------------===//
00136 
00137   class RopePieceBTree {
00138     void /*RopePieceBTreeNode*/ *Root;
00139     void operator=(const RopePieceBTree &) LLVM_DELETED_FUNCTION;
00140   public:
00141     RopePieceBTree();
00142     RopePieceBTree(const RopePieceBTree &RHS);
00143     ~RopePieceBTree();
00144 
00145     typedef RopePieceBTreeIterator iterator;
00146     iterator begin() const { return iterator(Root); }
00147     iterator end() const { return iterator(); }
00148     unsigned size() const;
00149     unsigned empty() const { return size() == 0; }
00150 
00151     void clear();
00152 
00153     void insert(unsigned Offset, const RopePiece &R);
00154 
00155     void erase(unsigned Offset, unsigned NumBytes);
00156   };
00157 
00158   //===--------------------------------------------------------------------===//
00159   // RewriteRope Class
00160   //===--------------------------------------------------------------------===//
00161 
00162 /// RewriteRope - A powerful string class.  This class supports extremely
00163 /// efficient insertions and deletions into the middle of it, even for
00164 /// ridiculously long strings.
00165 class RewriteRope {
00166   RopePieceBTree Chunks;
00167 
00168   /// We allocate space for string data out of a buffer of size AllocChunkSize.
00169   /// This keeps track of how much space is left.
00170   llvm::IntrusiveRefCntPtr<RopeRefCountString> AllocBuffer;
00171   unsigned AllocOffs;
00172   enum { AllocChunkSize = 4080 };
00173 
00174 public:
00175   RewriteRope() :  AllocBuffer(nullptr), AllocOffs(AllocChunkSize) {}
00176   RewriteRope(const RewriteRope &RHS)
00177     : Chunks(RHS.Chunks), AllocBuffer(nullptr), AllocOffs(AllocChunkSize) {
00178   }
00179 
00180   typedef RopePieceBTree::iterator iterator;
00181   typedef RopePieceBTree::iterator const_iterator;
00182   iterator begin() const { return Chunks.begin(); }
00183   iterator end() const  { return Chunks.end(); }
00184   unsigned size() const { return Chunks.size(); }
00185 
00186   void clear() {
00187     Chunks.clear();
00188   }
00189 
00190   void assign(const char *Start, const char *End) {
00191     clear();
00192     if (Start != End)
00193       Chunks.insert(0, MakeRopeString(Start, End));
00194   }
00195 
00196   void insert(unsigned Offset, const char *Start, const char *End) {
00197     assert(Offset <= size() && "Invalid position to insert!");
00198     if (Start == End) return;
00199     Chunks.insert(Offset, MakeRopeString(Start, End));
00200   }
00201 
00202   void erase(unsigned Offset, unsigned NumBytes) {
00203     assert(Offset+NumBytes <= size() && "Invalid region to erase!");
00204     if (NumBytes == 0) return;
00205     Chunks.erase(Offset, NumBytes);
00206   }
00207 
00208 private:
00209   RopePiece MakeRopeString(const char *Start, const char *End);
00210 };
00211 
00212 } // end namespace clang
00213 
00214 #endif