#include "llvm/Support/Casting.h"
-//#define USE_ROPE_VECTOR
-
namespace clang {
struct RopeRefCountString {
-#ifndef USE_ROPE_VECTOR
using llvm::dyn_cast;
using llvm::cast;
};
-#endif // ifndef USE_ROPE_VECTOR
-
-#ifdef USE_ROPE_VECTOR
- class RewriteRope;
-
-template <typename CharType, typename PieceIterType>
-class RewriteRopeIterator :
- public bidirectional_iterator<CharType, ptrdiff_t> {
- PieceIterType CurPiece;
- unsigned CurChar;
- friend class RewriteRope;
-public:
- RewriteRopeIterator(const PieceIterType &curPiece, unsigned curChar)
- : CurPiece(curPiece), CurChar(curChar) {}
-
- CharType &operator*() const {
- return (*CurPiece)[CurChar];
- }
-
- bool operator==(const RewriteRopeIterator &RHS) const {
- return CurPiece == RHS.CurPiece && CurChar == RHS.CurChar;
- }
- bool operator!=(const RewriteRopeIterator &RHS) const {
- return !operator==(RHS);
- }
-
- inline RewriteRopeIterator& operator++() { // Preincrement
- if (CurChar+1 < CurPiece->size())
- ++CurChar;
- else {
- CurChar = 0;
- ++CurPiece;
- }
- return *this;
- }
-
- RewriteRopeIterator operator+(int Offset) const {
- assert(Offset >= 0 && "FIXME: Only handle forward case so far!");
-
- PieceIterType Piece = CurPiece;
- unsigned Char = CurChar;
- while (Char+Offset >= Piece->size()) {
- Offset -= Piece->size()-Char;
- ++Piece;
- Char = 0;
- }
- Char += Offset;
- return RewriteRopeIterator(Piece, Char);
- }
-
- inline RewriteRopeIterator operator++(int) { // Postincrement
- RewriteRopeIterator tmp = *this; ++*this; return tmp;
- }
-};
-#endif
-
-
/// RewriteRope - A powerful string class, todo generalize this.
class RewriteRope {
-#ifdef USE_ROPE_VECTOR
- // FIXME: This could be significantly faster by using a balanced binary tree
- // instead of a list.
- std::list<RopePiece> Chunks;
- unsigned CurSize;
-#else
RopePieceBTree Chunks;
-#endif
/// We allocate space for string data out of a buffer of size AllocChunkSize.
/// This keeps track of how much space is left.
enum { AllocChunkSize = 4080 };
public:
- RewriteRope() :
-#ifdef USE_ROPE_VECTOR
- CurSize(0),
-#endif
- AllocBuffer(0), AllocOffs(AllocChunkSize) {}
- RewriteRope(const RewriteRope &RHS) : Chunks(RHS.Chunks),
-#ifdef USE_ROPE_VECTOR
- CurSize(RHS.CurSize),
-#endif
- AllocBuffer(0), AllocOffs(AllocChunkSize) {
+ RewriteRope() : AllocBuffer(0), AllocOffs(AllocChunkSize) {}
+ RewriteRope(const RewriteRope &RHS)
+ : Chunks(RHS.Chunks), AllocBuffer(0), AllocOffs(AllocChunkSize) {
}
~RewriteRope() {
AllocBuffer->dropRef();
}
-#ifdef USE_ROPE_VECTOR
- typedef RewriteRopeIterator<char, std::list<RopePiece>::iterator> iterator;
- typedef RewriteRopeIterator<const char,
- std::list<RopePiece>::const_iterator> const_iterator;
-
- iterator begin() { return iterator(Chunks.begin(), 0); }
- iterator end() { return iterator(Chunks.end(), 0); }
- const_iterator begin() const { return const_iterator(Chunks.begin(), 0); }
- const_iterator end() const { return const_iterator(Chunks.end(), 0); }
-
- unsigned size() const { return CurSize; }
-#else
typedef RopePieceBTree::iterator iterator;
typedef RopePieceBTree::iterator const_iterator;
iterator begin() const { return Chunks.begin(); }
iterator end() const { return Chunks.end(); }
unsigned size() const { return Chunks.size(); }
-#endif
void clear() {
Chunks.clear();
-#ifdef USE_ROPE_VECTOR
- CurSize = 0;
-#endif
}
-#ifndef USE_ROPE_VECTOR
void assign(const char *Start, const char *End) {
clear();
Chunks.insert(0, MakeRopeString(Start, End));
if (NumBytes == 0) return;
Chunks.erase(Offset, NumBytes);
}
-#endif
-
-#ifdef USE_ROPE_VECTOR
- void assign(const char *Start, const char *End) {
- clear();
- Chunks.push_back(MakeRopeString(Start, End));
- CurSize = End-Start;
- }
-
- iterator getAtOffset(unsigned Offset) {
- assert(Offset <= CurSize && "Offset out of range!");
- if (Offset == CurSize) return iterator(Chunks.end(), 0);
- std::list<RopePiece>::iterator Piece = Chunks.begin();
- while (Offset >= Piece->size()) {
- Offset -= Piece->size();
- ++Piece;
- }
- return iterator(Piece, Offset);
- }
-
- const_iterator getAtOffset(unsigned Offset) const {
- assert(Offset <= CurSize && "Offset out of range!");
- if (Offset == CurSize) return const_iterator(Chunks.end(), 0);
- std::list<RopePiece>::const_iterator Piece = Chunks.begin();
- while (Offset >= Piece->size()) {
- Offset -= Piece->size();
- ++Piece;
- }
- return const_iterator(Piece, Offset);
- }
-
-
- void insert(iterator Loc, const char *Start, const char *End) {
- if (Start == End) return;
- Chunks.insert(SplitAt(Loc), MakeRopeString(Start, End));
- CurSize += End-Start;
- }
-
- void erase(iterator Start, iterator End) {
- if (Start == End) return;
-
- // If erase is localized within the same chunk, this is a degenerate case.
- if (Start.CurPiece == End.CurPiece) {
- RopePiece &Chunk = *Start.CurPiece;
- unsigned NumDel = End.CurChar-Start.CurChar;
- CurSize -= NumDel;
-
- // If deleting from start of chunk, just adjust range.
- if (Start.CurChar == 0) {
- if (Chunk.EndOffs != End.CurChar)
- Chunk.StartOffs += NumDel;
- else // Deleting entire chunk.
- Chunks.erase(End.CurPiece);
- return;
- }
-
- // If deleting to the end of chunk, just adjust range.
- if (End.CurChar == Chunk.size()) {
- Chunk.EndOffs -= NumDel;
- return;
- }
-
- // If deleting the middle of a chunk, split this chunk and adjust the end
- // piece.
- SplitAt(Start)->StartOffs += NumDel;
- return;
- }
-
- // Otherwise, the start chunk and the end chunk are different.
- std::list<RopePiece>::iterator CurPiece = Start.CurPiece;
-
- // Delete the end of the start chunk. If it is the whole thing, remove it.
- {
- RopePiece &StartChunk = *CurPiece;
- unsigned NumDel = StartChunk.size()-Start.CurChar;
- CurSize -= NumDel;
- if (Start.CurChar == 0) {
- // Delete the whole chunk.
- Chunks.erase(CurPiece++);
- } else {
- // Otherwise, just move the end of chunk marker up.
- StartChunk.EndOffs -= NumDel;
- ++CurPiece;
- }
- }
-
- // If deleting a span of chunks, nuke them all now.
- while (CurPiece != End.CurPiece) {
- CurSize -= CurPiece->size();
- Chunks.erase(CurPiece++);
- }
-
- // Finally, erase the start of the end chunk if appropriate.
- if (End.CurChar != 0) {
- End.CurPiece->StartOffs += End.CurChar;
- CurSize -= End.CurChar;
- }
- }
-#endif
private:
RopePiece MakeRopeString(const char *Start, const char *End) {
AllocBuffer->addRef();
return RopePiece(AllocBuffer, 0, Len);
}
-
-#ifdef USE_ROPE_VECTOR
-
- /// SplitAt - If the specified iterator position has a non-zero character
- /// number, split the specified buffer up. This guarantees that the specified
- /// iterator is at the start of a chunk. Return the chunk it is at the start
- /// of.
- std::list<RopePiece>::iterator SplitAt(iterator Loc) {
- std::list<RopePiece>::iterator Chunk = Loc.CurPiece;
-
- // If the specified position is at the start of a piece, return it.
- if (Loc.CurChar == 0)
- return Chunk;
-
- // Otherwise, we have to split the specified piece in half, inserting the
- // new piece into the list of pieces.
-
- // Make a new piece for the prefix part.
- Chunks.insert(Chunk, RopePiece(Chunk->StrData, Chunk->StartOffs,
- Chunk->StartOffs+Loc.CurChar));
-
- // Make the current piece refer the suffix part.
- Chunk->StartOffs += Loc.CurChar;
-
- // Return the old chunk, which is the suffix.
- return Chunk;
- }
-#endif
};
} // end namespace clang
assert(RealOffset+Size < Buffer.size() && "Invalid location");
// Remove the dead characters.
-#ifdef USE_ROPE_VECTOR
- RewriteRope::iterator I = Buffer.getAtOffset(RealOffset);
- Buffer.erase(I, I+Size);
-#else
Buffer.erase(RealOffset, Size);
-#endif
// Add a delta so that future changes are offset correctly.
AddDelta(OrigOffset, -Size);
if (StrLen == 0) return;
unsigned RealOffset = getMappedOffset(OrigOffset, InsertAfter);
-
-#ifdef USE_ROPE_VECTOR
- assert(RealOffset <= Buffer.size() && "Invalid location");
-
- // Insert the new characters.
- Buffer.insert(Buffer.getAtOffset(RealOffset), StrData, StrData+StrLen);
-#else
Buffer.insert(RealOffset, StrData, StrData+StrLen);
-#endif
// Add a delta so that future changes are offset correctly.
AddDelta(OrigOffset, StrLen);
void RewriteBuffer::ReplaceText(unsigned OrigOffset, unsigned OrigLength,
const char *NewStr, unsigned NewLength) {
unsigned RealOffset = getMappedOffset(OrigOffset, true);
-#ifdef USE_ROPE_VECTOR
- assert(RealOffset+OrigLength <= Buffer.size() && "Invalid location");
-
- // Overwrite the common piece.
- unsigned CommonLength = std::min(OrigLength, NewLength);
- std::copy(NewStr, NewStr+CommonLength, Buffer.getAtOffset(RealOffset));
-
- // If replacing without shifting around, just overwrite the text.
- if (OrigLength == NewLength)
- return;
-
- // If inserting more than existed before, this is like an insertion.
- if (NewLength > OrigLength) {
- Buffer.insert(Buffer.getAtOffset(RealOffset+OrigLength),
- NewStr+OrigLength, NewStr+NewLength);
- } else {
- // If inserting less than existed before, this is like a removal.
- RewriteRope::iterator I = Buffer.getAtOffset(RealOffset+NewLength);
- Buffer.erase(I, I+(OrigLength-NewLength));
- }
-#else
Buffer.erase(RealOffset, OrigLength);
Buffer.insert(RealOffset, NewStr, NewStr+NewLength);
-#endif
if (OrigLength != NewLength)
AddDelta(OrigOffset, NewLength-OrigLength);
}