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