[clang] [llvm] [llvm][clang] Move RewriterBuffer to ADT. (PR #99770)
Jacques Pienaar via cfe-commits
cfe-commits at lists.llvm.org
Sat Jul 20 10:06:12 PDT 2024
https://github.com/jpienaar created https://github.com/llvm/llvm-project/pull/99770
These classes are not specific to clang and useful for other rewriter tools (flagged in previous review).
>From 451a4c61066c4a433bc100ebc511dc6447f83ab0 Mon Sep 17 00:00:00 2001
From: Jacques Pienaar <jpienaar at google.com>
Date: Sat, 20 Jul 2024 16:25:14 +0000
Subject: [PATCH] [llvm][clang] Move RewriterBuffer to ADT.
These classes are not specific to clang and useful for other rewriter tools.
---
clang/include/clang/Rewrite/Core/DeltaTree.h | 50 --
.../include/clang/Rewrite/Core/HTMLRewrite.h | 11 +-
.../include/clang/Rewrite/Core/RewriteRope.h | 223 --------
clang/include/clang/Rewrite/Core/Rewriter.h | 19 +-
clang/lib/ARCMigrate/ARCMT.cpp | 2 +-
clang/lib/ARCMigrate/ObjCMT.cpp | 1 +
clang/lib/Frontend/Rewrite/FixItRewriter.cpp | 3 +-
clang/lib/Frontend/Rewrite/HTMLPrint.cpp | 2 +
clang/lib/Frontend/Rewrite/RewriteMacros.cpp | 4 +-
.../Frontend/Rewrite/RewriteModernObjC.cpp | 3 +-
clang/lib/Frontend/Rewrite/RewriteObjC.cpp | 1 +
clang/lib/Rewrite/CMakeLists.txt | 2 -
clang/lib/Rewrite/HTMLRewrite.cpp | 1 +
clang/lib/Rewrite/Rewriter.cpp | 109 +---
.../StaticAnalyzer/Core/HTMLDiagnostics.cpp | 2 +
clang/lib/Tooling/Core/Replacement.cpp | 2 +-
clang/unittests/Rewrite/CMakeLists.txt | 1 -
llvm/include/llvm/ADT/DeltaTree.h | 50 ++
.../include/llvm/ADT}/RewriteBuffer.h | 40 +-
llvm/include/llvm/ADT/RewriteRope.h | 223 ++++++++
llvm/lib/Support/CMakeLists.txt | 3 +
.../lib/Support}/DeltaTree.cpp | 265 +++++----
llvm/lib/Support/RewriteBuffer.cpp | 107 ++++
.../lib/Support}/RewriteRope.cpp | 507 +++++++++---------
llvm/unittests/ADT/CMakeLists.txt | 1 +
.../unittests/ADT}/RewriteBufferTest.cpp | 5 +-
26 files changed, 825 insertions(+), 812 deletions(-)
delete mode 100644 clang/include/clang/Rewrite/Core/DeltaTree.h
delete mode 100644 clang/include/clang/Rewrite/Core/RewriteRope.h
create mode 100644 llvm/include/llvm/ADT/DeltaTree.h
rename {clang/include/clang/Rewrite/Core => llvm/include/llvm/ADT}/RewriteBuffer.h (82%)
create mode 100644 llvm/include/llvm/ADT/RewriteRope.h
rename {clang/lib/Rewrite => llvm/lib/Support}/DeltaTree.cpp (68%)
create mode 100644 llvm/lib/Support/RewriteBuffer.cpp
rename {clang/lib/Rewrite => llvm/lib/Support}/RewriteRope.cpp (63%)
rename {clang/unittests/Rewrite => llvm/unittests/ADT}/RewriteBufferTest.cpp (96%)
diff --git a/clang/include/clang/Rewrite/Core/DeltaTree.h b/clang/include/clang/Rewrite/Core/DeltaTree.h
deleted file mode 100644
index e566c92aaff91..0000000000000
--- a/clang/include/clang/Rewrite/Core/DeltaTree.h
+++ /dev/null
@@ -1,50 +0,0 @@
-//===- DeltaTree.h - B-Tree for Rewrite Delta tracking ----------*- C++ -*-===//
-//
-// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
-// See https://llvm.org/LICENSE.txt for license information.
-// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
-//
-//===----------------------------------------------------------------------===//
-//
-// This file defines the DeltaTree class.
-//
-//===----------------------------------------------------------------------===//
-
-#ifndef LLVM_CLANG_REWRITE_CORE_DELTATREE_H
-#define LLVM_CLANG_REWRITE_CORE_DELTATREE_H
-
-namespace clang {
-
- /// DeltaTree - a multiway search tree (BTree) structure with some fancy
- /// features. B-Trees are generally more memory and cache efficient than
- /// binary trees, because they store multiple keys/values in each node. This
- /// implements a key/value mapping from index to delta, and allows fast lookup
- /// on index. However, an added (important) bonus is that it can also
- /// efficiently tell us the full accumulated delta for a specific file offset
- /// as well, without traversing the whole tree.
- class DeltaTree {
- void *Root; // "DeltaTreeNode *"
-
- public:
- DeltaTree();
-
- // Note: Currently we only support copying when the RHS is empty.
- DeltaTree(const DeltaTree &RHS);
-
- DeltaTree &operator=(const DeltaTree &) = delete;
- ~DeltaTree();
-
- /// getDeltaAt - Return the accumulated delta at the specified file offset.
- /// This includes all insertions or delections that occurred *before* the
- /// specified file index.
- int getDeltaAt(unsigned FileIndex) const;
-
- /// AddDelta - When a change is made that shifts around the text buffer,
- /// this method is used to record that info. It inserts a delta of 'Delta'
- /// into the current DeltaTree at offset FileIndex.
- void AddDelta(unsigned FileIndex, int Delta);
- };
-
-} // namespace clang
-
-#endif // LLVM_CLANG_REWRITE_CORE_DELTATREE_H
diff --git a/clang/include/clang/Rewrite/Core/HTMLRewrite.h b/clang/include/clang/Rewrite/Core/HTMLRewrite.h
index eecf589632746..9edb514d566b9 100644
--- a/clang/include/clang/Rewrite/Core/HTMLRewrite.h
+++ b/clang/include/clang/Rewrite/Core/HTMLRewrite.h
@@ -17,10 +17,13 @@
#include "clang/Basic/SourceLocation.h"
#include <string>
+namespace llvm {
+class RewriteBuffer;
+} // namespace llvm
+
namespace clang {
class Rewriter;
-class RewriteBuffer;
class Preprocessor;
namespace html {
@@ -53,9 +56,9 @@ namespace html {
/// HighlightRange - This is the same as the above method, but takes
/// decomposed file locations.
- void HighlightRange(RewriteBuffer &RB, unsigned B, unsigned E,
- const char *BufferStart,
- const char *StartTag, const char *EndTag);
+ void HighlightRange(llvm::RewriteBuffer &RB, unsigned B, unsigned E,
+ const char *BufferStart, const char *StartTag,
+ const char *EndTag);
/// EscapeText - HTMLize a specified file so that special characters are
/// are translated so that they are not interpreted as HTML tags.
diff --git a/clang/include/clang/Rewrite/Core/RewriteRope.h b/clang/include/clang/Rewrite/Core/RewriteRope.h
deleted file mode 100644
index 73e66e111f574..0000000000000
--- a/clang/include/clang/Rewrite/Core/RewriteRope.h
+++ /dev/null
@@ -1,223 +0,0 @@
-//===- RewriteRope.h - Rope specialized for rewriter ------------*- C++ -*-===//
-//
-// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
-// See https://llvm.org/LICENSE.txt for license information.
-// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
-//
-//===----------------------------------------------------------------------===//
-//
-// This file defines the RewriteRope class, which is a powerful string class.
-//
-//===----------------------------------------------------------------------===//
-
-#ifndef LLVM_CLANG_REWRITE_CORE_REWRITEROPE_H
-#define LLVM_CLANG_REWRITE_CORE_REWRITEROPE_H
-
-#include "llvm/ADT/IntrusiveRefCntPtr.h"
-#include "llvm/ADT/StringRef.h"
-#include <cassert>
-#include <cstddef>
-#include <iterator>
-#include <utility>
-
-namespace clang {
-
- //===--------------------------------------------------------------------===//
- // RopeRefCountString Class
- //===--------------------------------------------------------------------===//
-
- /// RopeRefCountString - This struct is allocated with 'new char[]' from the
- /// heap, and represents a reference counted chunk of string data. When its
- /// ref count drops to zero, it is delete[]'d. This is primarily managed
- /// through the RopePiece class below.
- struct RopeRefCountString {
- unsigned RefCount;
- char Data[1]; // Variable sized.
-
- void Retain() { ++RefCount; }
-
- void Release() {
- assert(RefCount > 0 && "Reference count is already zero.");
- if (--RefCount == 0)
- delete [] (char*)this;
- }
- };
-
- //===--------------------------------------------------------------------===//
- // RopePiece Class
- //===--------------------------------------------------------------------===//
-
- /// RopePiece - This class represents a view into a RopeRefCountString object.
- /// This allows references to string data to be efficiently chopped up and
- /// moved around without having to push around the string data itself.
- ///
- /// For example, we could have a 1M RopePiece and want to insert something
- /// into the middle of it. To do this, we split it into two RopePiece objects
- /// that both refer to the same underlying RopeRefCountString (just with
- /// different offsets) which is a nice constant time operation.
- struct RopePiece {
- llvm::IntrusiveRefCntPtr<RopeRefCountString> StrData;
- unsigned StartOffs = 0;
- unsigned EndOffs = 0;
-
- RopePiece() = default;
- RopePiece(llvm::IntrusiveRefCntPtr<RopeRefCountString> Str, unsigned Start,
- unsigned End)
- : StrData(std::move(Str)), StartOffs(Start), EndOffs(End) {}
-
- const char &operator[](unsigned Offset) const {
- return StrData->Data[Offset+StartOffs];
- }
- char &operator[](unsigned Offset) {
- return StrData->Data[Offset+StartOffs];
- }
-
- unsigned size() const { return EndOffs-StartOffs; }
- };
-
- //===--------------------------------------------------------------------===//
- // RopePieceBTreeIterator Class
- //===--------------------------------------------------------------------===//
-
- /// RopePieceBTreeIterator - This class provides read-only forward iteration
- /// over bytes that are in a RopePieceBTree. This first iterates over bytes
- /// in a RopePiece, then iterates over RopePiece's in a RopePieceBTreeLeaf,
- /// then iterates over RopePieceBTreeLeaf's in a RopePieceBTree.
- class RopePieceBTreeIterator {
- /// CurNode - The current B+Tree node that we are inspecting.
- const void /*RopePieceBTreeLeaf*/ *CurNode = nullptr;
-
- /// CurPiece - The current RopePiece in the B+Tree node that we're
- /// inspecting.
- const RopePiece *CurPiece = nullptr;
-
- /// CurChar - The current byte in the RopePiece we are pointing to.
- unsigned CurChar = 0;
-
- public:
- using iterator_category = std::forward_iterator_tag;
- using value_type = const char;
- using difference_type = std::ptrdiff_t;
- using pointer = value_type *;
- using reference = value_type &;
-
- RopePieceBTreeIterator() = default;
- RopePieceBTreeIterator(const void /*RopePieceBTreeNode*/ *N);
-
- char operator*() const {
- return (*CurPiece)[CurChar];
- }
-
- bool operator==(const RopePieceBTreeIterator &RHS) const {
- return CurPiece == RHS.CurPiece && CurChar == RHS.CurChar;
- }
- bool operator!=(const RopePieceBTreeIterator &RHS) const {
- return !operator==(RHS);
- }
-
- RopePieceBTreeIterator& operator++() { // Preincrement
- if (CurChar+1 < CurPiece->size())
- ++CurChar;
- else
- MoveToNextPiece();
- return *this;
- }
-
- RopePieceBTreeIterator operator++(int) { // Postincrement
- RopePieceBTreeIterator tmp = *this; ++*this; return tmp;
- }
-
- llvm::StringRef piece() const {
- return llvm::StringRef(&(*CurPiece)[0], CurPiece->size());
- }
-
- void MoveToNextPiece();
- };
-
- //===--------------------------------------------------------------------===//
- // RopePieceBTree Class
- //===--------------------------------------------------------------------===//
-
- class RopePieceBTree {
- void /*RopePieceBTreeNode*/ *Root;
-
- public:
- RopePieceBTree();
- RopePieceBTree(const RopePieceBTree &RHS);
- RopePieceBTree &operator=(const RopePieceBTree &) = delete;
- ~RopePieceBTree();
-
- using iterator = RopePieceBTreeIterator;
-
- iterator begin() const { return iterator(Root); }
- iterator end() const { return iterator(); }
- unsigned size() const;
- unsigned empty() const { return size() == 0; }
-
- void clear();
-
- void insert(unsigned Offset, const RopePiece &R);
-
- void erase(unsigned Offset, unsigned NumBytes);
- };
-
- //===--------------------------------------------------------------------===//
- // RewriteRope Class
- //===--------------------------------------------------------------------===//
-
-/// RewriteRope - A powerful string class. This class supports extremely
-/// efficient insertions and deletions into the middle of it, even for
-/// ridiculously long strings.
-class RewriteRope {
- RopePieceBTree Chunks;
-
- /// We allocate space for string data out of a buffer of size AllocChunkSize.
- /// This keeps track of how much space is left.
- llvm::IntrusiveRefCntPtr<RopeRefCountString> AllocBuffer;
- enum { AllocChunkSize = 4080 };
- unsigned AllocOffs = AllocChunkSize;
-
-public:
- RewriteRope() = default;
- RewriteRope(const RewriteRope &RHS) : Chunks(RHS.Chunks) {}
-
- // The copy assignment operator is defined as deleted pending further
- // motivation.
- RewriteRope &operator=(const RewriteRope &) = delete;
-
- using iterator = RopePieceBTree::iterator;
- using const_iterator = RopePieceBTree::iterator;
-
- iterator begin() const { return Chunks.begin(); }
- iterator end() const { return Chunks.end(); }
- unsigned size() const { return Chunks.size(); }
-
- void clear() {
- Chunks.clear();
- }
-
- void assign(const char *Start, const char *End) {
- clear();
- if (Start != End)
- Chunks.insert(0, MakeRopeString(Start, End));
- }
-
- void insert(unsigned Offset, const char *Start, const char *End) {
- assert(Offset <= size() && "Invalid position to insert!");
- if (Start == End) return;
- Chunks.insert(Offset, MakeRopeString(Start, End));
- }
-
- void erase(unsigned Offset, unsigned NumBytes) {
- assert(Offset+NumBytes <= size() && "Invalid region to erase!");
- if (NumBytes == 0) return;
- Chunks.erase(Offset, NumBytes);
- }
-
-private:
- RopePiece MakeRopeString(const char *Start, const char *End);
-};
-
-} // namespace clang
-
-#endif // LLVM_CLANG_REWRITE_CORE_REWRITEROPE_H
diff --git a/clang/include/clang/Rewrite/Core/Rewriter.h b/clang/include/clang/Rewrite/Core/Rewriter.h
index c89015e405582..4e96f6fcca919 100644
--- a/clang/include/clang/Rewrite/Core/Rewriter.h
+++ b/clang/include/clang/Rewrite/Core/Rewriter.h
@@ -16,7 +16,7 @@
#include "clang/Basic/LLVM.h"
#include "clang/Basic/SourceLocation.h"
-#include "clang/Rewrite/Core/RewriteBuffer.h"
+#include "llvm/ADT/RewriteBuffer.h"
#include "llvm/ADT/StringRef.h"
#include <map>
#include <string>
@@ -32,7 +32,7 @@ class SourceManager;
class Rewriter {
SourceManager *SourceMgr = nullptr;
const LangOptions *LangOpts = nullptr;
- std::map<FileID, RewriteBuffer> RewriteBuffers;
+ std::map<FileID, llvm::RewriteBuffer> RewriteBuffers;
public:
struct RewriteOptions {
@@ -49,7 +49,7 @@ class Rewriter {
///
/// FIXME: This sometimes corrupts the file's rewrite buffer due to
/// incorrect indexing in the implementation (see the FIXME in
- /// clang::RewriteBuffer::RemoveText). Moreover, it's inefficient because
+ /// llvm::RewriteBuffer::RemoveText). Moreover, it's inefficient because
/// it must scan the buffer from the beginning to find the start of the
/// line. When feasible, it's better for the caller to check for a blank
/// line and then, if found, expand the removal range to include it.
@@ -62,8 +62,9 @@ class Rewriter {
RewriteOptions() {}
};
- using buffer_iterator = std::map<FileID, RewriteBuffer>::iterator;
- using const_buffer_iterator = std::map<FileID, RewriteBuffer>::const_iterator;
+ using buffer_iterator = std::map<FileID, llvm::RewriteBuffer>::iterator;
+ using const_buffer_iterator =
+ std::map<FileID, llvm::RewriteBuffer>::const_iterator;
explicit Rewriter() = default;
explicit Rewriter(SourceManager &SM, const LangOptions &LO)
@@ -191,13 +192,13 @@ class Rewriter {
/// buffer, and allows you to write on it directly. This is useful if you
/// want efficient low-level access to apis for scribbling on one specific
/// FileID's buffer.
- RewriteBuffer &getEditBuffer(FileID FID);
+ llvm::RewriteBuffer &getEditBuffer(FileID FID);
/// getRewriteBufferFor - Return the rewrite buffer for the specified FileID.
/// If no modification has been made to it, return null.
- const RewriteBuffer *getRewriteBufferFor(FileID FID) const {
- std::map<FileID, RewriteBuffer>::const_iterator I =
- RewriteBuffers.find(FID);
+ const llvm::RewriteBuffer *getRewriteBufferFor(FileID FID) const {
+ std::map<FileID, llvm::RewriteBuffer>::const_iterator I =
+ RewriteBuffers.find(FID);
return I == RewriteBuffers.end() ? nullptr : &I->second;
}
diff --git a/clang/lib/ARCMigrate/ARCMT.cpp b/clang/lib/ARCMigrate/ARCMT.cpp
index 5835559bff6b7..1a8a200f2fc19 100644
--- a/clang/lib/ARCMigrate/ARCMT.cpp
+++ b/clang/lib/ARCMigrate/ARCMT.cpp
@@ -596,7 +596,7 @@ bool MigrationProcess::applyTransform(TransformFn trans,
for (Rewriter::buffer_iterator
I = rewriter.buffer_begin(), E = rewriter.buffer_end(); I != E; ++I) {
FileID FID = I->first;
- RewriteBuffer &buf = I->second;
+ llvm::RewriteBuffer &buf = I->second;
OptionalFileEntryRef file =
Ctx.getSourceManager().getFileEntryRefForID(FID);
assert(file);
diff --git a/clang/lib/ARCMigrate/ObjCMT.cpp b/clang/lib/ARCMigrate/ObjCMT.cpp
index 4357c8e3f09a5..c1bc7c762088f 100644
--- a/clang/lib/ARCMigrate/ObjCMT.cpp
+++ b/clang/lib/ARCMigrate/ObjCMT.cpp
@@ -36,6 +36,7 @@
using namespace clang;
using namespace arcmt;
using namespace ento;
+using llvm::RewriteBuffer;
namespace {
diff --git a/clang/lib/Frontend/Rewrite/FixItRewriter.cpp b/clang/lib/Frontend/Rewrite/FixItRewriter.cpp
index 567bac576adb4..44dfaf20eae73 100644
--- a/clang/lib/Frontend/Rewrite/FixItRewriter.cpp
+++ b/clang/lib/Frontend/Rewrite/FixItRewriter.cpp
@@ -21,8 +21,8 @@
#include "clang/Edit/Commit.h"
#include "clang/Edit/EditsReceiver.h"
#include "clang/Frontend/FrontendDiagnostic.h"
-#include "clang/Rewrite/Core/RewriteBuffer.h"
#include "clang/Rewrite/Core/Rewriter.h"
+#include "llvm/ADT/RewriteBuffer.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/Support/FileSystem.h"
#include "llvm/Support/raw_ostream.h"
@@ -33,6 +33,7 @@
#include <utility>
using namespace clang;
+using llvm::RewriteBuffer;
FixItRewriter::FixItRewriter(DiagnosticsEngine &Diags, SourceManager &SourceMgr,
const LangOptions &LangOpts,
diff --git a/clang/lib/Frontend/Rewrite/HTMLPrint.cpp b/clang/lib/Frontend/Rewrite/HTMLPrint.cpp
index 69baa8f591088..5cce193ed1c4f 100644
--- a/clang/lib/Frontend/Rewrite/HTMLPrint.cpp
+++ b/clang/lib/Frontend/Rewrite/HTMLPrint.cpp
@@ -20,8 +20,10 @@
#include "clang/Rewrite/Core/HTMLRewrite.h"
#include "clang/Rewrite/Core/Rewriter.h"
#include "clang/Rewrite/Frontend/ASTConsumers.h"
+#include "llvm/ADT/RewriteBuffer.h"
#include "llvm/Support/raw_ostream.h"
using namespace clang;
+using llvm::RewriteBuffer;
//===----------------------------------------------------------------------===//
// Functional HTML pretty-printing.
diff --git a/clang/lib/Frontend/Rewrite/RewriteMacros.cpp b/clang/lib/Frontend/Rewrite/RewriteMacros.cpp
index 5701b271aff10..b533cabe97f5e 100644
--- a/clang/lib/Frontend/Rewrite/RewriteMacros.cpp
+++ b/clang/lib/Frontend/Rewrite/RewriteMacros.cpp
@@ -11,16 +11,18 @@
//
//===----------------------------------------------------------------------===//
-#include "clang/Rewrite/Frontend/Rewriters.h"
#include "clang/Basic/SourceManager.h"
#include "clang/Lex/Preprocessor.h"
#include "clang/Rewrite/Core/Rewriter.h"
+#include "clang/Rewrite/Frontend/Rewriters.h"
+#include "llvm/ADT/RewriteBuffer.h"
#include "llvm/Support/Path.h"
#include "llvm/Support/raw_ostream.h"
#include <cstdio>
#include <memory>
using namespace clang;
+using llvm::RewriteBuffer;
/// isSameToken - Return true if the two specified tokens start have the same
/// content.
diff --git a/clang/lib/Frontend/Rewrite/RewriteModernObjC.cpp b/clang/lib/Frontend/Rewrite/RewriteModernObjC.cpp
index 3849e4040b53a..f618c536b5f3c 100644
--- a/clang/lib/Frontend/Rewrite/RewriteModernObjC.cpp
+++ b/clang/lib/Frontend/Rewrite/RewriteModernObjC.cpp
@@ -10,7 +10,6 @@
//
//===----------------------------------------------------------------------===//
-#include "clang/Rewrite/Frontend/ASTConsumers.h"
#include "clang/AST/AST.h"
#include "clang/AST/ASTConsumer.h"
#include "clang/AST/Attr.h"
@@ -23,6 +22,7 @@
#include "clang/Config/config.h"
#include "clang/Lex/Lexer.h"
#include "clang/Rewrite/Core/Rewriter.h"
+#include "clang/Rewrite/Frontend/ASTConsumers.h"
#include "llvm/ADT/DenseSet.h"
#include "llvm/ADT/SetVector.h"
#include "llvm/ADT/SmallPtrSet.h"
@@ -34,6 +34,7 @@
#if CLANG_ENABLE_OBJC_REWRITER
using namespace clang;
+using llvm::RewriteBuffer;
using llvm::utostr;
namespace {
diff --git a/clang/lib/Frontend/Rewrite/RewriteObjC.cpp b/clang/lib/Frontend/Rewrite/RewriteObjC.cpp
index bf5176a2b6fb2..9db6ddbf0b890 100644
--- a/clang/lib/Frontend/Rewrite/RewriteObjC.cpp
+++ b/clang/lib/Frontend/Rewrite/RewriteObjC.cpp
@@ -32,6 +32,7 @@
#if CLANG_ENABLE_OBJC_REWRITER
using namespace clang;
+using llvm::RewriteBuffer;
using llvm::utostr;
namespace {
diff --git a/clang/lib/Rewrite/CMakeLists.txt b/clang/lib/Rewrite/CMakeLists.txt
index 16550b1b710ef..93ecb3c835260 100644
--- a/clang/lib/Rewrite/CMakeLists.txt
+++ b/clang/lib/Rewrite/CMakeLists.txt
@@ -3,9 +3,7 @@ set(LLVM_LINK_COMPONENTS
)
add_clang_library(clangRewrite
- DeltaTree.cpp
HTMLRewrite.cpp
- RewriteRope.cpp
Rewriter.cpp
TokenRewriter.cpp
diff --git a/clang/lib/Rewrite/HTMLRewrite.cpp b/clang/lib/Rewrite/HTMLRewrite.cpp
index a96ca0764ae73..c75835df2c98e 100644
--- a/clang/lib/Rewrite/HTMLRewrite.cpp
+++ b/clang/lib/Rewrite/HTMLRewrite.cpp
@@ -16,6 +16,7 @@
#include "clang/Lex/Preprocessor.h"
#include "clang/Lex/TokenConcatenation.h"
#include "clang/Rewrite/Core/Rewriter.h"
+#include "llvm/ADT/RewriteBuffer.h"
#include "llvm/ADT/SmallString.h"
#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/MemoryBuffer.h"
diff --git a/clang/lib/Rewrite/Rewriter.cpp b/clang/lib/Rewrite/Rewriter.cpp
index 0e6ae36506446..68cf797f97905 100644
--- a/clang/lib/Rewrite/Rewriter.cpp
+++ b/clang/lib/Rewrite/Rewriter.cpp
@@ -17,8 +17,8 @@
#include "clang/Basic/SourceLocation.h"
#include "clang/Basic/SourceManager.h"
#include "clang/Lex/Lexer.h"
-#include "clang/Rewrite/Core/RewriteBuffer.h"
-#include "clang/Rewrite/Core/RewriteRope.h"
+#include "llvm/ADT/RewriteBuffer.h"
+#include "llvm/ADT/RewriteRope.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/Support/Error.h"
@@ -29,113 +29,18 @@
#include <utility>
using namespace clang;
+using llvm::RewriteBuffer;
-raw_ostream &RewriteBuffer::write(raw_ostream &os) const {
- // Walk RewriteRope chunks efficiently using MoveToNextPiece() instead of the
- // character iterator.
- for (RopePieceBTreeIterator I = begin(), E = end(); I != E;
- I.MoveToNextPiece())
- os << I.piece();
- return os;
-}
+//===----------------------------------------------------------------------===//
+// Rewriter class
+//===----------------------------------------------------------------------===//
/// Return true if this character is non-new-line whitespace:
/// ' ', '\\t', '\\f', '\\v', '\\r'.
static inline bool isWhitespaceExceptNL(unsigned char c) {
- switch (c) {
- case ' ':
- case '\t':
- case '\f':
- case '\v':
- case '\r':
- return true;
- default:
- return false;
- }
+ return c == ' ' || c == '\t' || c == '\f' || c == '\v' || c == '\r';
}
-void RewriteBuffer::RemoveText(unsigned OrigOffset, unsigned Size,
- bool removeLineIfEmpty) {
- // Nothing to remove, exit early.
- if (Size == 0) return;
-
- unsigned RealOffset = getMappedOffset(OrigOffset, true);
- assert(RealOffset+Size <= Buffer.size() && "Invalid location");
-
- // Remove the dead characters.
- Buffer.erase(RealOffset, Size);
-
- // Add a delta so that future changes are offset correctly.
- AddReplaceDelta(OrigOffset, -Size);
-
- if (removeLineIfEmpty) {
- // Find the line that the remove occurred and if it is completely empty
- // remove the line as well.
-
- iterator curLineStart = begin();
- unsigned curLineStartOffs = 0;
- iterator posI = begin();
- for (unsigned i = 0; i != RealOffset; ++i) {
- if (*posI == '\n') {
- curLineStart = posI;
- ++curLineStart;
- curLineStartOffs = i + 1;
- }
- ++posI;
- }
-
- unsigned lineSize = 0;
- posI = curLineStart;
- while (posI != end() && isWhitespaceExceptNL(*posI)) {
- ++posI;
- ++lineSize;
- }
- if (posI != end() && *posI == '\n') {
- Buffer.erase(curLineStartOffs, lineSize + 1/* + '\n'*/);
- // FIXME: Here, the offset of the start of the line is supposed to be
- // expressed in terms of the original input not the "real" rewrite
- // buffer. How do we compute that reliably? It might be tempting to use
- // curLineStartOffs + OrigOffset - RealOffset, but that assumes the
- // difference between the original and real offset is the same at the
- // removed text and at the start of the line, but that's not true if
- // edits were previously made earlier on the line. This bug is also
- // documented by a FIXME on the definition of
- // clang::Rewriter::RewriteOptions::RemoveLineIfEmpty. A reproducer for
- // the implementation below is the test RemoveLineIfEmpty in
- // clang/unittests/Rewrite/RewriteBufferTest.cpp.
- AddReplaceDelta(curLineStartOffs, -(lineSize + 1/* + '\n'*/));
- }
- }
-}
-
-void RewriteBuffer::InsertText(unsigned OrigOffset, StringRef Str,
- bool InsertAfter) {
- // Nothing to insert, exit early.
- if (Str.empty()) return;
-
- unsigned RealOffset = getMappedOffset(OrigOffset, InsertAfter);
- Buffer.insert(RealOffset, Str.begin(), Str.end());
-
- // Add a delta so that future changes are offset correctly.
- AddInsertDelta(OrigOffset, Str.size());
-}
-
-/// ReplaceText - This method replaces a range of characters in the input
-/// buffer with a new string. This is effectively a combined "remove+insert"
-/// operation.
-void RewriteBuffer::ReplaceText(unsigned OrigOffset, unsigned OrigLength,
- StringRef NewStr) {
- unsigned RealOffset = getMappedOffset(OrigOffset, true);
- Buffer.erase(RealOffset, OrigLength);
- Buffer.insert(RealOffset, NewStr.begin(), NewStr.end());
- if (OrigLength != NewStr.size())
- AddReplaceDelta(OrigOffset, NewStr.size() - OrigLength);
-}
-
-//===----------------------------------------------------------------------===//
-// Rewriter class
-//===----------------------------------------------------------------------===//
-
/// getRangeSize - Return the size in bytes of the specified range if they
/// are in the same file. If not, this returns -1.
int Rewriter::getRangeSize(const CharSourceRange &Range,
diff --git a/clang/lib/StaticAnalyzer/Core/HTMLDiagnostics.cpp b/clang/lib/StaticAnalyzer/Core/HTMLDiagnostics.cpp
index fb5030d373c2f..28d9de2973b01 100644
--- a/clang/lib/StaticAnalyzer/Core/HTMLDiagnostics.cpp
+++ b/clang/lib/StaticAnalyzer/Core/HTMLDiagnostics.cpp
@@ -27,6 +27,7 @@
#include "clang/Rewrite/Core/Rewriter.h"
#include "clang/StaticAnalyzer/Core/PathDiagnosticConsumers.h"
#include "llvm/ADT/ArrayRef.h"
+#include "llvm/ADT/RewriteBuffer.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/Sequence.h"
#include "llvm/ADT/SmallString.h"
@@ -52,6 +53,7 @@
using namespace clang;
using namespace ento;
+using llvm::RewriteBuffer;
//===----------------------------------------------------------------------===//
// Boilerplate.
diff --git a/clang/lib/Tooling/Core/Replacement.cpp b/clang/lib/Tooling/Core/Replacement.cpp
index 269f17a6db4cf..9acf00263b5a8 100644
--- a/clang/lib/Tooling/Core/Replacement.cpp
+++ b/clang/lib/Tooling/Core/Replacement.cpp
@@ -19,9 +19,9 @@
#include "clang/Basic/SourceLocation.h"
#include "clang/Basic/SourceManager.h"
#include "clang/Lex/Lexer.h"
-#include "clang/Rewrite/Core/RewriteBuffer.h"
#include "clang/Rewrite/Core/Rewriter.h"
#include "llvm/ADT/IntrusiveRefCntPtr.h"
+#include "llvm/ADT/RewriteBuffer.h"
#include "llvm/ADT/SmallPtrSet.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/Support/Error.h"
diff --git a/clang/unittests/Rewrite/CMakeLists.txt b/clang/unittests/Rewrite/CMakeLists.txt
index 6594d8cc5897f..3c5e2f8e5354b 100644
--- a/clang/unittests/Rewrite/CMakeLists.txt
+++ b/clang/unittests/Rewrite/CMakeLists.txt
@@ -3,7 +3,6 @@ set(LLVM_LINK_COMPONENTS
)
add_clang_unittest(RewriteTests
- RewriteBufferTest.cpp
RewriterTest.cpp
)
clang_target_link_libraries(RewriteTests
diff --git a/llvm/include/llvm/ADT/DeltaTree.h b/llvm/include/llvm/ADT/DeltaTree.h
new file mode 100644
index 0000000000000..5db9d74d9d529
--- /dev/null
+++ b/llvm/include/llvm/ADT/DeltaTree.h
@@ -0,0 +1,50 @@
+//===- DeltaTree.h - B-Tree for Rewrite Delta tracking ----------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file defines the DeltaTree class.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_ADT_DELTATREE_H
+#define LLVM_ADT_DELTATREE_H
+
+namespace llvm {
+
+/// DeltaTree - a multiway search tree (BTree) structure with some fancy
+/// features. B-Trees are generally more memory and cache efficient than
+/// binary trees, because they store multiple keys/values in each node. This
+/// implements a key/value mapping from index to delta, and allows fast lookup
+/// on index. However, an added (important) bonus is that it can also
+/// efficiently tell us the full accumulated delta for a specific file offset
+/// as well, without traversing the whole tree.
+class DeltaTree {
+ void *Root; // "DeltaTreeNode *"
+
+public:
+ DeltaTree();
+
+ // Note: Currently we only support copying when the RHS is empty.
+ DeltaTree(const DeltaTree &RHS);
+
+ DeltaTree &operator=(const DeltaTree &) = delete;
+ ~DeltaTree();
+
+ /// getDeltaAt - Return the accumulated delta at the specified file offset.
+ /// This includes all insertions or delections that occurred *before* the
+ /// specified file index.
+ int getDeltaAt(unsigned FileIndex) const;
+
+ /// AddDelta - When a change is made that shifts around the text buffer,
+ /// this method is used to record that info. It inserts a delta of 'Delta'
+ /// into the current DeltaTree at offset FileIndex.
+ void AddDelta(unsigned FileIndex, int Delta);
+};
+
+} // namespace llvm
+
+#endif // LLVM_ADT_DELTATREE_H
diff --git a/clang/include/clang/Rewrite/Core/RewriteBuffer.h b/llvm/include/llvm/ADT/RewriteBuffer.h
similarity index 82%
rename from clang/include/clang/Rewrite/Core/RewriteBuffer.h
rename to llvm/include/llvm/ADT/RewriteBuffer.h
index b8f34174b7156..8197a06f882c1 100644
--- a/clang/include/clang/Rewrite/Core/RewriteBuffer.h
+++ b/llvm/include/llvm/ADT/RewriteBuffer.h
@@ -6,15 +6,20 @@
//
//===----------------------------------------------------------------------===//
-#ifndef LLVM_CLANG_REWRITE_CORE_REWRITEBUFFER_H
-#define LLVM_CLANG_REWRITE_CORE_REWRITEBUFFER_H
+#ifndef LLVM_ADT_REWRITEBUFFER_H
+#define LLVM_ADT_REWRITEBUFFER_H
-#include "clang/Basic/LLVM.h"
-#include "clang/Rewrite/Core/DeltaTree.h"
-#include "clang/Rewrite/Core/RewriteRope.h"
+#include "llvm/ADT/DeltaTree.h"
+#include "llvm/ADT/RewriteRope.h"
#include "llvm/ADT/StringRef.h"
namespace clang {
+class Rewriter;
+} // namespace clang
+
+namespace llvm {
+
+class raw_ostream;
/// RewriteBuffer - As code is rewritten, SourceBuffer's from the original
/// input with modifications get a new RewriteBuffer associated with them. The
@@ -23,7 +28,7 @@ namespace clang {
/// RewriteBuffer. For example, if text is inserted into the buffer, any
/// locations after the insertion point have to be mapped.
class RewriteBuffer {
- friend class Rewriter;
+ friend class clang::Rewriter;
/// Deltas - Keep track of all the deltas in the source code due to insertions
/// and deletions.
@@ -43,9 +48,7 @@ class RewriteBuffer {
void Initialize(const char *BufStart, const char *BufEnd) {
Buffer.assign(BufStart, BufEnd);
}
- void Initialize(StringRef Input) {
- Initialize(Input.begin(), Input.end());
- }
+ void Initialize(StringRef Input) { Initialize(Input.begin(), Input.end()); }
/// Write to \p Stream the result of applying all changes to the
/// original buffer.
@@ -63,9 +66,7 @@ class RewriteBuffer {
/// InsertText - Insert some text at the specified point, where the offset in
/// the buffer is specified relative to the original SourceBuffer. The
/// text is inserted after the specified location.
- void InsertText(unsigned OrigOffset, StringRef Str,
- bool InsertAfter = true);
-
+ void InsertText(unsigned OrigOffset, StringRef Str, bool InsertAfter = true);
/// InsertTextBefore - Insert some text before the specified point, where the
/// offset in the buffer is specified relative to the original
@@ -85,8 +86,7 @@ class RewriteBuffer {
/// ReplaceText - This method replaces a range of characters in the input
/// buffer with a new string. This is effectively a combined "remove/insert"
/// operation.
- void ReplaceText(unsigned OrigOffset, unsigned OrigLength,
- StringRef NewStr);
+ void ReplaceText(unsigned OrigOffset, unsigned OrigLength, StringRef NewStr);
private:
/// getMappedOffset - Given an offset into the original SourceBuffer that this
@@ -95,23 +95,23 @@ class RewriteBuffer {
/// position where text is inserted, the location returned will be after any
/// inserted text at the position.
unsigned getMappedOffset(unsigned OrigOffset,
- bool AfterInserts = false) const{
- return Deltas.getDeltaAt(2*OrigOffset+AfterInserts)+OrigOffset;
+ bool AfterInserts = false) const {
+ return Deltas.getDeltaAt(2 * OrigOffset + AfterInserts) + OrigOffset;
}
/// AddInsertDelta - When an insertion is made at a position, this
/// method is used to record that information.
void AddInsertDelta(unsigned OrigOffset, int Change) {
- return Deltas.AddDelta(2*OrigOffset, Change);
+ return Deltas.AddDelta(2 * OrigOffset, Change);
}
/// AddReplaceDelta - When a replacement/deletion is made at a position, this
/// method is used to record that information.
void AddReplaceDelta(unsigned OrigOffset, int Change) {
- return Deltas.AddDelta(2*OrigOffset+1, Change);
+ return Deltas.AddDelta(2 * OrigOffset + 1, Change);
}
};
-} // namespace clang
+} // namespace llvm
-#endif // LLVM_CLANG_REWRITE_CORE_REWRITEBUFFER_H
+#endif // LLVM_ADT_REWRITEBUFFER_H
diff --git a/llvm/include/llvm/ADT/RewriteRope.h b/llvm/include/llvm/ADT/RewriteRope.h
new file mode 100644
index 0000000000000..784f3c07eaa62
--- /dev/null
+++ b/llvm/include/llvm/ADT/RewriteRope.h
@@ -0,0 +1,223 @@
+//===- RewriteRope.h - Rope specialized for rewriter ------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file defines the RewriteRope class, which is a powerful string class.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_ADT_REWRITEROPE_H
+#define LLVM_ADT_REWRITEROPE_H
+
+#include "llvm/ADT/IntrusiveRefCntPtr.h"
+#include "llvm/ADT/StringRef.h"
+#include <cassert>
+#include <cstddef>
+#include <iterator>
+#include <utility>
+
+namespace llvm {
+
+//===--------------------------------------------------------------------===//
+// RopeRefCountString Class
+//===--------------------------------------------------------------------===//
+
+/// RopeRefCountString - This struct is allocated with 'new char[]' from the
+/// heap, and represents a reference counted chunk of string data. When its
+/// ref count drops to zero, it is delete[]'d. This is primarily managed
+/// through the RopePiece class below.
+struct RopeRefCountString {
+ unsigned RefCount;
+ char Data[1]; // Variable sized.
+
+ void Retain() { ++RefCount; }
+
+ void Release() {
+ assert(RefCount > 0 && "Reference count is already zero.");
+ if (--RefCount == 0)
+ delete[] (char *)this;
+ }
+};
+
+//===--------------------------------------------------------------------===//
+// RopePiece Class
+//===--------------------------------------------------------------------===//
+
+/// RopePiece - This class represents a view into a RopeRefCountString object.
+/// This allows references to string data to be efficiently chopped up and
+/// moved around without having to push around the string data itself.
+///
+/// For example, we could have a 1M RopePiece and want to insert something
+/// into the middle of it. To do this, we split it into two RopePiece objects
+/// that both refer to the same underlying RopeRefCountString (just with
+/// different offsets) which is a nice constant time operation.
+struct RopePiece {
+ llvm::IntrusiveRefCntPtr<RopeRefCountString> StrData;
+ unsigned StartOffs = 0;
+ unsigned EndOffs = 0;
+
+ RopePiece() = default;
+ RopePiece(llvm::IntrusiveRefCntPtr<RopeRefCountString> Str, unsigned Start,
+ unsigned End)
+ : StrData(std::move(Str)), StartOffs(Start), EndOffs(End) {}
+
+ const char &operator[](unsigned Offset) const {
+ return StrData->Data[Offset + StartOffs];
+ }
+ char &operator[](unsigned Offset) {
+ return StrData->Data[Offset + StartOffs];
+ }
+
+ unsigned size() const { return EndOffs - StartOffs; }
+};
+
+//===--------------------------------------------------------------------===//
+// RopePieceBTreeIterator Class
+//===--------------------------------------------------------------------===//
+
+/// RopePieceBTreeIterator - This class provides read-only forward iteration
+/// over bytes that are in a RopePieceBTree. This first iterates over bytes
+/// in a RopePiece, then iterates over RopePiece's in a RopePieceBTreeLeaf,
+/// then iterates over RopePieceBTreeLeaf's in a RopePieceBTree.
+class RopePieceBTreeIterator {
+ /// CurNode - The current B+Tree node that we are inspecting.
+ const void /*RopePieceBTreeLeaf*/ *CurNode = nullptr;
+
+ /// CurPiece - The current RopePiece in the B+Tree node that we're
+ /// inspecting.
+ const RopePiece *CurPiece = nullptr;
+
+ /// CurChar - The current byte in the RopePiece we are pointing to.
+ unsigned CurChar = 0;
+
+public:
+ using iterator_category = std::forward_iterator_tag;
+ using value_type = const char;
+ using difference_type = std::ptrdiff_t;
+ using pointer = value_type *;
+ using reference = value_type &;
+
+ RopePieceBTreeIterator() = default;
+ RopePieceBTreeIterator(const void /*RopePieceBTreeNode*/ *N);
+
+ char operator*() const { return (*CurPiece)[CurChar]; }
+
+ bool operator==(const RopePieceBTreeIterator &RHS) const {
+ return CurPiece == RHS.CurPiece && CurChar == RHS.CurChar;
+ }
+ bool operator!=(const RopePieceBTreeIterator &RHS) const {
+ return !operator==(RHS);
+ }
+
+ RopePieceBTreeIterator &operator++() { // Preincrement
+ if (CurChar + 1 < CurPiece->size())
+ ++CurChar;
+ else
+ MoveToNextPiece();
+ return *this;
+ }
+
+ RopePieceBTreeIterator operator++(int) { // Postincrement
+ RopePieceBTreeIterator tmp = *this;
+ ++*this;
+ return tmp;
+ }
+
+ llvm::StringRef piece() const {
+ return llvm::StringRef(&(*CurPiece)[0], CurPiece->size());
+ }
+
+ void MoveToNextPiece();
+};
+
+//===--------------------------------------------------------------------===//
+// RopePieceBTree Class
+//===--------------------------------------------------------------------===//
+
+class RopePieceBTree {
+ void /*RopePieceBTreeNode*/ *Root;
+
+public:
+ RopePieceBTree();
+ RopePieceBTree(const RopePieceBTree &RHS);
+ RopePieceBTree &operator=(const RopePieceBTree &) = delete;
+ ~RopePieceBTree();
+
+ using iterator = RopePieceBTreeIterator;
+
+ iterator begin() const { return iterator(Root); }
+ iterator end() const { return iterator(); }
+ unsigned size() const;
+ unsigned empty() const { return size() == 0; }
+
+ void clear();
+
+ void insert(unsigned Offset, const RopePiece &R);
+
+ void erase(unsigned Offset, unsigned NumBytes);
+};
+
+//===--------------------------------------------------------------------===//
+// RewriteRope Class
+//===--------------------------------------------------------------------===//
+
+/// RewriteRope - A powerful string class. This class supports extremely
+/// efficient insertions and deletions into the middle of it, even for
+/// ridiculously long strings.
+class RewriteRope {
+ RopePieceBTree Chunks;
+
+ /// We allocate space for string data out of a buffer of size AllocChunkSize.
+ /// This keeps track of how much space is left.
+ llvm::IntrusiveRefCntPtr<RopeRefCountString> AllocBuffer;
+ enum { AllocChunkSize = 4080 };
+ unsigned AllocOffs = AllocChunkSize;
+
+public:
+ RewriteRope() = default;
+ RewriteRope(const RewriteRope &RHS) : Chunks(RHS.Chunks) {}
+
+ // The copy assignment operator is defined as deleted pending further
+ // motivation.
+ RewriteRope &operator=(const RewriteRope &) = delete;
+
+ using iterator = RopePieceBTree::iterator;
+ using const_iterator = RopePieceBTree::iterator;
+
+ iterator begin() const { return Chunks.begin(); }
+ iterator end() const { return Chunks.end(); }
+ unsigned size() const { return Chunks.size(); }
+
+ void clear() { Chunks.clear(); }
+
+ void assign(const char *Start, const char *End) {
+ clear();
+ if (Start != End)
+ Chunks.insert(0, MakeRopeString(Start, End));
+ }
+
+ void insert(unsigned Offset, const char *Start, const char *End) {
+ assert(Offset <= size() && "Invalid position to insert!");
+ if (Start == End)
+ return;
+ Chunks.insert(Offset, MakeRopeString(Start, End));
+ }
+
+ void erase(unsigned Offset, unsigned NumBytes) {
+ assert(Offset + NumBytes <= size() && "Invalid region to erase!");
+ if (NumBytes == 0)
+ return;
+ Chunks.erase(Offset, NumBytes);
+ }
+
+private:
+ RopePiece MakeRopeString(const char *Start, const char *End);
+};
+
+} // namespace llvm
+
+#endif // LLVM_ADT_REWRITEROPE_H
diff --git a/llvm/lib/Support/CMakeLists.txt b/llvm/lib/Support/CMakeLists.txt
index f653379e30334..a73ac54a01c5a 100644
--- a/llvm/lib/Support/CMakeLists.txt
+++ b/llvm/lib/Support/CMakeLists.txt
@@ -168,6 +168,7 @@ add_llvm_component_library(LLVMSupport
Debug.cpp
DebugCounter.cpp
DeltaAlgorithm.cpp
+ DeltaTree.cpp
DivisionByConstantInfo.cpp
DAGDeltaAlgorithm.cpp
DJB.cpp
@@ -216,6 +217,8 @@ add_llvm_component_library(LLVMSupport
PrettyStackTrace.cpp
RandomNumberGenerator.cpp
Regex.cpp
+ RewriteBuffer.cpp
+ RewriteRope.cpp
RISCVAttributes.cpp
RISCVAttributeParser.cpp
RISCVISAUtils.cpp
diff --git a/clang/lib/Rewrite/DeltaTree.cpp b/llvm/lib/Support/DeltaTree.cpp
similarity index 68%
rename from clang/lib/Rewrite/DeltaTree.cpp
rename to llvm/lib/Support/DeltaTree.cpp
index 61467f84928f2..2eb642ffd1df6 100644
--- a/clang/lib/Rewrite/DeltaTree.cpp
+++ b/llvm/lib/Support/DeltaTree.cpp
@@ -10,13 +10,12 @@
//
//===----------------------------------------------------------------------===//
-#include "clang/Rewrite/Core/DeltaTree.h"
-#include "clang/Basic/LLVM.h"
+#include "llvm/ADT/DeltaTree.h"
#include "llvm/Support/Casting.h"
#include <cassert>
#include <cstring>
-using namespace clang;
+using namespace llvm;
/// The DeltaTree class is a multiway search tree (BTree) structure with some
/// fancy features. B-Trees are generally more memory and cache efficient
@@ -35,125 +34,125 @@ using namespace clang;
namespace {
- /// SourceDelta - As code in the original input buffer is added and deleted,
- /// SourceDelta records are used to keep track of how the input SourceLocation
- /// object is mapped into the output buffer.
- struct SourceDelta {
- unsigned FileLoc;
- int Delta;
-
- static SourceDelta get(unsigned Loc, int D) {
- SourceDelta Delta;
- Delta.FileLoc = Loc;
- Delta.Delta = D;
- return Delta;
- }
+/// SourceDelta - As code in the original input buffer is added and deleted,
+/// SourceDelta records are used to keep track of how the input SourceLocation
+/// object is mapped into the output buffer.
+struct SourceDelta {
+ unsigned FileLoc;
+ int Delta;
+
+ static SourceDelta get(unsigned Loc, int D) {
+ SourceDelta Delta;
+ Delta.FileLoc = Loc;
+ Delta.Delta = D;
+ return Delta;
+ }
+};
+
+/// DeltaTreeNode - The common part of all nodes.
+///
+class DeltaTreeNode {
+public:
+ struct InsertResult {
+ DeltaTreeNode *LHS, *RHS;
+ SourceDelta Split;
};
- /// DeltaTreeNode - The common part of all nodes.
- ///
- class DeltaTreeNode {
- public:
- struct InsertResult {
- DeltaTreeNode *LHS, *RHS;
- SourceDelta Split;
- };
-
- private:
- friend class DeltaTreeInteriorNode;
-
- /// WidthFactor - This controls the number of K/V slots held in the BTree:
- /// how wide it is. Each level of the BTree is guaranteed to have at least
- /// WidthFactor-1 K/V pairs (except the root) and may have at most
- /// 2*WidthFactor-1 K/V pairs.
- enum { WidthFactor = 8 };
-
- /// Values - This tracks the SourceDelta's currently in this node.
- SourceDelta Values[2*WidthFactor-1];
-
- /// NumValuesUsed - This tracks the number of values this node currently
- /// holds.
- unsigned char NumValuesUsed = 0;
-
- /// IsLeaf - This is true if this is a leaf of the btree. If false, this is
- /// an interior node, and is actually an instance of DeltaTreeInteriorNode.
- bool IsLeaf;
-
- /// FullDelta - This is the full delta of all the values in this node and
- /// all children nodes.
- int FullDelta = 0;
+private:
+ friend class DeltaTreeInteriorNode;
- public:
- DeltaTreeNode(bool isLeaf = true) : IsLeaf(isLeaf) {}
+ /// WidthFactor - This controls the number of K/V slots held in the BTree:
+ /// how wide it is. Each level of the BTree is guaranteed to have at least
+ /// WidthFactor-1 K/V pairs (except the root) and may have at most
+ /// 2*WidthFactor-1 K/V pairs.
+ enum { WidthFactor = 8 };
- bool isLeaf() const { return IsLeaf; }
- int getFullDelta() const { return FullDelta; }
- bool isFull() const { return NumValuesUsed == 2*WidthFactor-1; }
+ /// Values - This tracks the SourceDelta's currently in this node.
+ SourceDelta Values[2 * WidthFactor - 1];
- unsigned getNumValuesUsed() const { return NumValuesUsed; }
+ /// NumValuesUsed - This tracks the number of values this node currently
+ /// holds.
+ unsigned char NumValuesUsed = 0;
- const SourceDelta &getValue(unsigned i) const {
- assert(i < NumValuesUsed && "Invalid value #");
- return Values[i];
- }
+ /// IsLeaf - This is true if this is a leaf of the btree. If false, this is
+ /// an interior node, and is actually an instance of DeltaTreeInteriorNode.
+ bool IsLeaf;
- SourceDelta &getValue(unsigned i) {
- assert(i < NumValuesUsed && "Invalid value #");
- return Values[i];
- }
+ /// FullDelta - This is the full delta of all the values in this node and
+ /// all children nodes.
+ int FullDelta = 0;
- /// DoInsertion - Do an insertion of the specified FileIndex/Delta pair into
- /// this node. If insertion is easy, do it and return false. Otherwise,
- /// split the node, populate InsertRes with info about the split, and return
- /// true.
- bool DoInsertion(unsigned FileIndex, int Delta, InsertResult *InsertRes);
+public:
+ DeltaTreeNode(bool isLeaf = true) : IsLeaf(isLeaf) {}
- void DoSplit(InsertResult &InsertRes);
+ bool isLeaf() const { return IsLeaf; }
+ int getFullDelta() const { return FullDelta; }
+ bool isFull() const { return NumValuesUsed == 2 * WidthFactor - 1; }
+ unsigned getNumValuesUsed() const { return NumValuesUsed; }
- /// RecomputeFullDeltaLocally - Recompute the FullDelta field by doing a
- /// local walk over our contained deltas.
- void RecomputeFullDeltaLocally();
+ const SourceDelta &getValue(unsigned i) const {
+ assert(i < NumValuesUsed && "Invalid value #");
+ return Values[i];
+ }
- void Destroy();
- };
+ SourceDelta &getValue(unsigned i) {
+ assert(i < NumValuesUsed && "Invalid value #");
+ return Values[i];
+ }
- /// DeltaTreeInteriorNode - When isLeaf = false, a node has child pointers.
- /// This class tracks them.
- class DeltaTreeInteriorNode : public DeltaTreeNode {
- friend class DeltaTreeNode;
+ /// DoInsertion - Do an insertion of the specified FileIndex/Delta pair into
+ /// this node. If insertion is easy, do it and return false. Otherwise,
+ /// split the node, populate InsertRes with info about the split, and return
+ /// true.
+ bool DoInsertion(unsigned FileIndex, int Delta, InsertResult *InsertRes);
- DeltaTreeNode *Children[2*WidthFactor];
+ void DoSplit(InsertResult &InsertRes);
- ~DeltaTreeInteriorNode() {
- for (unsigned i = 0, e = NumValuesUsed+1; i != e; ++i)
- Children[i]->Destroy();
- }
+ /// RecomputeFullDeltaLocally - Recompute the FullDelta field by doing a
+ /// local walk over our contained deltas.
+ void RecomputeFullDeltaLocally();
- public:
- DeltaTreeInteriorNode() : DeltaTreeNode(false /*nonleaf*/) {}
+ void Destroy();
+};
- DeltaTreeInteriorNode(const InsertResult &IR)
- : DeltaTreeNode(false /*nonleaf*/) {
- Children[0] = IR.LHS;
- Children[1] = IR.RHS;
- Values[0] = IR.Split;
- FullDelta = IR.LHS->getFullDelta()+IR.RHS->getFullDelta()+IR.Split.Delta;
- NumValuesUsed = 1;
- }
+/// DeltaTreeInteriorNode - When isLeaf = false, a node has child pointers.
+/// This class tracks them.
+class DeltaTreeInteriorNode : public DeltaTreeNode {
+ friend class DeltaTreeNode;
- const DeltaTreeNode *getChild(unsigned i) const {
- assert(i < getNumValuesUsed()+1 && "Invalid child");
- return Children[i];
- }
+ DeltaTreeNode *Children[2 * WidthFactor];
- DeltaTreeNode *getChild(unsigned i) {
- assert(i < getNumValuesUsed()+1 && "Invalid child");
- return Children[i];
- }
+ ~DeltaTreeInteriorNode() {
+ for (unsigned i = 0, e = NumValuesUsed + 1; i != e; ++i)
+ Children[i]->Destroy();
+ }
- static bool classof(const DeltaTreeNode *N) { return !N->isLeaf(); }
- };
+public:
+ DeltaTreeInteriorNode() : DeltaTreeNode(false /*nonleaf*/) {}
+
+ DeltaTreeInteriorNode(const InsertResult &IR)
+ : DeltaTreeNode(false /*nonleaf*/) {
+ Children[0] = IR.LHS;
+ Children[1] = IR.RHS;
+ Values[0] = IR.Split;
+ FullDelta =
+ IR.LHS->getFullDelta() + IR.RHS->getFullDelta() + IR.Split.Delta;
+ NumValuesUsed = 1;
+ }
+
+ const DeltaTreeNode *getChild(unsigned i) const {
+ assert(i < getNumValuesUsed() + 1 && "Invalid child");
+ return Children[i];
+ }
+
+ DeltaTreeNode *getChild(unsigned i) {
+ assert(i < getNumValuesUsed() + 1 && "Invalid child");
+ return Children[i];
+ }
+
+ static bool classof(const DeltaTreeNode *N) { return !N->isLeaf(); }
+};
} // namespace
@@ -172,7 +171,7 @@ void DeltaTreeNode::RecomputeFullDeltaLocally() {
for (unsigned i = 0, e = getNumValuesUsed(); i != e; ++i)
NewFullDelta += Values[i].Delta;
if (auto *IN = dyn_cast<DeltaTreeInteriorNode>(this))
- for (unsigned i = 0, e = getNumValuesUsed()+1; i != e; ++i)
+ for (unsigned i = 0, e = getNumValuesUsed() + 1; i != e; ++i)
NewFullDelta += IN->getChild(i)->getFullDelta();
FullDelta = NewFullDelta;
}
@@ -209,7 +208,7 @@ bool DeltaTreeNode::DoInsertion(unsigned FileIndex, int Delta,
// For an insertion into a non-full leaf node, just insert the value in
// its sorted position. This requires moving later values over.
if (i != e)
- memmove(&Values[i+1], &Values[i], sizeof(Values[0])*(e-i));
+ memmove(&Values[i + 1], &Values[i], sizeof(Values[0]) * (e - i));
Values[i] = SourceDelta::get(FileIndex, Delta);
++NumValuesUsed;
return false;
@@ -239,13 +238,13 @@ bool DeltaTreeNode::DoInsertion(unsigned FileIndex, int Delta,
// into ourself by moving all the later values/children down, then inserting
// the new one.
if (i != e)
- memmove(&IN->Children[i+2], &IN->Children[i+1],
- (e-i)*sizeof(IN->Children[0]));
+ memmove(&IN->Children[i + 2], &IN->Children[i + 1],
+ (e - i) * sizeof(IN->Children[0]));
IN->Children[i] = InsertRes->LHS;
- IN->Children[i+1] = InsertRes->RHS;
+ IN->Children[i + 1] = InsertRes->RHS;
if (e != i)
- memmove(&Values[i+1], &Values[i], (e-i)*sizeof(Values[0]));
+ memmove(&Values[i + 1], &Values[i], (e - i) * sizeof(Values[0]));
Values[i] = InsertRes->Split;
++NumValuesUsed;
return false;
@@ -272,20 +271,21 @@ bool DeltaTreeNode::DoInsertion(unsigned FileIndex, int Delta,
// SubRHS/SubSplit into. Find out where to insert SubSplit.
// Find the insertion point, the first delta whose index is >SubSplit.FileLoc.
- i = 0; e = InsertSide->getNumValuesUsed();
+ i = 0;
+ e = InsertSide->getNumValuesUsed();
while (i != e && SubSplit.FileLoc > InsertSide->getValue(i).FileLoc)
++i;
// Now we know that i is the place to insert the split value into. Insert it
// and the child right after it.
if (i != e)
- memmove(&InsertSide->Children[i+2], &InsertSide->Children[i+1],
- (e-i)*sizeof(IN->Children[0]));
- InsertSide->Children[i+1] = SubRHS;
+ memmove(&InsertSide->Children[i + 2], &InsertSide->Children[i + 1],
+ (e - i) * sizeof(IN->Children[0]));
+ InsertSide->Children[i + 1] = SubRHS;
if (e != i)
- memmove(&InsertSide->Values[i+1], &InsertSide->Values[i],
- (e-i)*sizeof(Values[0]));
+ memmove(&InsertSide->Values[i + 1], &InsertSide->Values[i],
+ (e - i) * sizeof(Values[0]));
InsertSide->Values[i] = SubSplit;
++InsertSide->NumValuesUsed;
InsertSide->FullDelta += SubSplit.Delta + SubRHS->getFullDelta();
@@ -310,7 +310,7 @@ void DeltaTreeNode::DoSplit(InsertResult &InsertRes) {
// into the new node.
DeltaTreeInteriorNode *New = new DeltaTreeInteriorNode();
memcpy(&New->Children[0], &IN->Children[WidthFactor],
- WidthFactor*sizeof(IN->Children[0]));
+ WidthFactor * sizeof(IN->Children[0]));
NewNode = New;
} else {
// Just create the new leaf node.
@@ -319,10 +319,10 @@ void DeltaTreeNode::DoSplit(InsertResult &InsertRes) {
// Move over the last 'WidthFactor-1' values from here to NewNode.
memcpy(&NewNode->Values[0], &Values[WidthFactor],
- (WidthFactor-1)*sizeof(Values[0]));
+ (WidthFactor - 1) * sizeof(Values[0]));
// Decrease the number of values in the two nodes.
- NewNode->NumValuesUsed = NumValuesUsed = WidthFactor-1;
+ NewNode->NumValuesUsed = NumValuesUsed = WidthFactor - 1;
// Recompute the two nodes' full delta.
NewNode->RecomputeFullDeltaLocally();
@@ -330,14 +330,14 @@ void DeltaTreeNode::DoSplit(InsertResult &InsertRes) {
InsertRes.LHS = this;
InsertRes.RHS = NewNode;
- InsertRes.Split = Values[WidthFactor-1];
+ InsertRes.Split = Values[WidthFactor - 1];
}
//===----------------------------------------------------------------------===//
// DeltaTree Implementation
//===----------------------------------------------------------------------===//
-//#define VERIFY_TREE
+// #define VERIFY_TREE
#ifdef VERIFY_TREE
/// VerifyTree - Walk the btree performing assertions on various properties to
@@ -350,7 +350,7 @@ static void VerifyTree(const DeltaTreeNode *N) {
int FullDelta = 0;
for (unsigned i = 0, e = N->getNumValuesUsed(); i != e; ++i) {
if (i)
- assert(N->getValue(i-1).FileLoc < N->getValue(i).FileLoc);
+ assert(N->getValue(i - 1).FileLoc < N->getValue(i).FileLoc);
FullDelta += N->getValue(i).Delta;
}
assert(FullDelta == N->getFullDelta());
@@ -364,16 +364,16 @@ static void VerifyTree(const DeltaTreeNode *N) {
const SourceDelta &IVal = N->getValue(i);
const DeltaTreeNode *IChild = IN->getChild(i);
if (i)
- assert(IN->getValue(i-1).FileLoc < IVal.FileLoc);
+ assert(IN->getValue(i - 1).FileLoc < IVal.FileLoc);
FullDelta += IVal.Delta;
FullDelta += IChild->getFullDelta();
// The largest value in child #i should be smaller than FileLoc.
- assert(IChild->getValue(IChild->getNumValuesUsed()-1).FileLoc <
+ assert(IChild->getValue(IChild->getNumValuesUsed() - 1).FileLoc <
IVal.FileLoc);
// The smallest value in child #i+1 should be larger than FileLoc.
- assert(IN->getChild(i+1)->getValue(0).FileLoc > IVal.FileLoc);
+ assert(IN->getChild(i + 1)->getValue(0).FileLoc > IVal.FileLoc);
VerifyTree(IChild);
}
@@ -381,15 +381,11 @@ static void VerifyTree(const DeltaTreeNode *N) {
assert(FullDelta == N->getFullDelta());
}
-#endif // VERIFY_TREE
+#endif // VERIFY_TREE
-static DeltaTreeNode *getRoot(void *Root) {
- return (DeltaTreeNode*)Root;
-}
+static DeltaTreeNode *getRoot(void *Root) { return (DeltaTreeNode *)Root; }
-DeltaTree::DeltaTree() {
- Root = new DeltaTreeNode();
-}
+DeltaTree::DeltaTree() { Root = new DeltaTreeNode(); }
DeltaTree::DeltaTree(const DeltaTree &RHS) {
// Currently we only support copying when the RHS is empty.
@@ -398,9 +394,7 @@ DeltaTree::DeltaTree(const DeltaTree &RHS) {
Root = new DeltaTreeNode();
}
-DeltaTree::~DeltaTree() {
- getRoot(Root)->Destroy();
-}
+DeltaTree::~DeltaTree() { getRoot(Root)->Destroy(); }
/// getDeltaAt - Return the accumulated delta at the specified file offset.
/// This includes all insertions or delections that occurred *before* the
@@ -428,7 +422,8 @@ int DeltaTree::getDeltaAt(unsigned FileIndex) const {
// If we have an interior node, include information about children and
// recurse. Otherwise, if we have a leaf, we're done.
const auto *IN = dyn_cast<DeltaTreeInteriorNode>(Node);
- if (!IN) return Result;
+ if (!IN)
+ return Result;
// Include any children to the left of the values we skipped, all of
// their deltas should be included as well.
@@ -440,7 +435,7 @@ int DeltaTree::getDeltaAt(unsigned FileIndex) const {
// partial results.
if (NumValsGreater != Node->getNumValuesUsed() &&
Node->getValue(NumValsGreater).FileLoc == FileIndex)
- return Result+IN->getChild(NumValsGreater)->getFullDelta();
+ return Result + IN->getChild(NumValsGreater)->getFullDelta();
// Otherwise, traverse down the tree. The selected subtree may be
// partially included in the range.
diff --git a/llvm/lib/Support/RewriteBuffer.cpp b/llvm/lib/Support/RewriteBuffer.cpp
new file mode 100644
index 0000000000000..cc6ba7e97b1a7
--- /dev/null
+++ b/llvm/lib/Support/RewriteBuffer.cpp
@@ -0,0 +1,107 @@
+//===- RewriteBuffer.h - Buffer rewriting interface -----------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/ADT/RewriteBuffer.h"
+#include "llvm/Support/raw_ostream.h"
+
+using namespace llvm;
+
+raw_ostream &RewriteBuffer::write(raw_ostream &Stream) const {
+ // Walk RewriteRope chunks efficiently using MoveToNextPiece() instead of the
+ // character iterator.
+ for (RopePieceBTreeIterator I = begin(), E = end(); I != E;
+ I.MoveToNextPiece())
+ Stream << I.piece();
+ return Stream;
+}
+
+/// Return true if this character is non-new-line whitespace:
+/// ' ', '\\t', '\\f', '\\v', '\\r'.
+static inline bool isWhitespaceExceptNL(unsigned char c) {
+ return c == ' ' || c == '\t' || c == '\f' || c == '\v' || c == '\r';
+}
+
+void RewriteBuffer::RemoveText(unsigned OrigOffset, unsigned Size,
+ bool removeLineIfEmpty) {
+ // Nothing to remove, exit early.
+ if (Size == 0)
+ return;
+
+ unsigned RealOffset = getMappedOffset(OrigOffset, true);
+ assert(RealOffset + Size <= Buffer.size() && "Invalid location");
+
+ // Remove the dead characters.
+ Buffer.erase(RealOffset, Size);
+
+ // Add a delta so that future changes are offset correctly.
+ AddReplaceDelta(OrigOffset, -Size);
+
+ if (removeLineIfEmpty) {
+ // Find the line that the remove occurred and if it is completely empty
+ // remove the line as well.
+
+ iterator curLineStart = begin();
+ unsigned curLineStartOffs = 0;
+ iterator posI = begin();
+ for (unsigned i = 0; i != RealOffset; ++i) {
+ if (*posI == '\n') {
+ curLineStart = posI;
+ ++curLineStart;
+ curLineStartOffs = i + 1;
+ }
+ ++posI;
+ }
+
+ unsigned lineSize = 0;
+ posI = curLineStart;
+ while (posI != end() && isWhitespaceExceptNL(*posI)) {
+ ++posI;
+ ++lineSize;
+ }
+ if (posI != end() && *posI == '\n') {
+ Buffer.erase(curLineStartOffs, lineSize + 1 /* + '\n'*/);
+ // FIXME: Here, the offset of the start of the line is supposed to be
+ // expressed in terms of the original input not the "real" rewrite
+ // buffer. How do we compute that reliably? It might be tempting to use
+ // curLineStartOffs + OrigOffset - RealOffset, but that assumes the
+ // difference between the original and real offset is the same at the
+ // removed text and at the start of the line, but that's not true if
+ // edits were previously made earlier on the line. This bug is also
+ // documented by a FIXME on the definition of
+ // clang::Rewriter::RewriteOptions::RemoveLineIfEmpty. A reproducer for
+ // the implementation below is the test RemoveLineIfEmpty in
+ // clang/unittests/Rewrite/RewriteBufferTest.cpp.
+ AddReplaceDelta(curLineStartOffs, -(lineSize + 1 /* + '\n'*/));
+ }
+ }
+}
+
+void RewriteBuffer::InsertText(unsigned OrigOffset, StringRef Str,
+ bool InsertAfter) {
+ // Nothing to insert, exit early.
+ if (Str.empty())
+ return;
+
+ unsigned RealOffset = getMappedOffset(OrigOffset, InsertAfter);
+ Buffer.insert(RealOffset, Str.begin(), Str.end());
+
+ // Add a delta so that future changes are offset correctly.
+ AddInsertDelta(OrigOffset, Str.size());
+}
+
+/// ReplaceText - This method replaces a range of characters in the input
+/// buffer with a new string. This is effectively a combined "remove+insert"
+/// operation.
+void RewriteBuffer::ReplaceText(unsigned OrigOffset, unsigned OrigLength,
+ StringRef NewStr) {
+ unsigned RealOffset = getMappedOffset(OrigOffset, true);
+ Buffer.erase(RealOffset, OrigLength);
+ Buffer.insert(RealOffset, NewStr.begin(), NewStr.end());
+ if (OrigLength != NewStr.size())
+ AddReplaceDelta(OrigOffset, NewStr.size() - OrigLength);
+}
diff --git a/clang/lib/Rewrite/RewriteRope.cpp b/llvm/lib/Support/RewriteRope.cpp
similarity index 63%
rename from clang/lib/Rewrite/RewriteRope.cpp
rename to llvm/lib/Support/RewriteRope.cpp
index 980d0f01e277c..7440aa6ab501e 100644
--- a/clang/lib/Rewrite/RewriteRope.cpp
+++ b/llvm/lib/Support/RewriteRope.cpp
@@ -10,14 +10,13 @@
//
//===----------------------------------------------------------------------===//
-#include "clang/Rewrite/Core/RewriteRope.h"
-#include "clang/Basic/LLVM.h"
+#include "llvm/ADT/RewriteRope.h"
#include "llvm/Support/Casting.h"
#include <algorithm>
#include <cassert>
#include <cstring>
-using namespace clang;
+using namespace llvm;
/// RewriteRope is a "strong" string class, designed to make insertions and
/// deletions in the middle of the string nearly constant time (really, they are
@@ -68,162 +67,160 @@ namespace {
// RopePieceBTreeNode Class
//===----------------------------------------------------------------------===//
- /// RopePieceBTreeNode - Common base class of RopePieceBTreeLeaf and
- /// RopePieceBTreeInterior. This provides some 'virtual' dispatching methods
- /// and a flag that determines which subclass the instance is. Also
- /// important, this node knows the full extend of the node, including any
- /// children that it has. This allows efficient skipping over entire subtrees
- /// when looking for an offset in the BTree.
- class RopePieceBTreeNode {
- protected:
- /// WidthFactor - This controls the number of K/V slots held in the BTree:
- /// how wide it is. Each level of the BTree is guaranteed to have at least
- /// 'WidthFactor' elements in it (either ropepieces or children), (except
- /// the root, which may have less) and may have at most 2*WidthFactor
- /// elements.
- enum { WidthFactor = 8 };
-
- /// Size - This is the number of bytes of file this node (including any
- /// potential children) covers.
- unsigned Size = 0;
-
- /// IsLeaf - True if this is an instance of RopePieceBTreeLeaf, false if it
- /// is an instance of RopePieceBTreeInterior.
- bool IsLeaf;
-
- RopePieceBTreeNode(bool isLeaf) : IsLeaf(isLeaf) {}
- ~RopePieceBTreeNode() = default;
-
- public:
- bool isLeaf() const { return IsLeaf; }
- unsigned size() const { return Size; }
-
- void Destroy();
-
- /// split - Split the range containing the specified offset so that we are
- /// guaranteed that there is a place to do an insertion at the specified
- /// offset. The offset is relative, so "0" is the start of the node.
- ///
- /// If there is no space in this subtree for the extra piece, the extra tree
- /// node is returned and must be inserted into a parent.
- RopePieceBTreeNode *split(unsigned Offset);
-
- /// insert - Insert the specified ropepiece into this tree node at the
- /// specified offset. The offset is relative, so "0" is the start of the
- /// node.
- ///
- /// If there is no space in this subtree for the extra piece, the extra tree
- /// node is returned and must be inserted into a parent.
- RopePieceBTreeNode *insert(unsigned Offset, const RopePiece &R);
-
- /// erase - Remove NumBytes from this node at the specified offset. We are
- /// guaranteed that there is a split at Offset.
- void erase(unsigned Offset, unsigned NumBytes);
- };
+/// RopePieceBTreeNode - Common base class of RopePieceBTreeLeaf and
+/// RopePieceBTreeInterior. This provides some 'virtual' dispatching methods
+/// and a flag that determines which subclass the instance is. Also
+/// important, this node knows the full extend of the node, including any
+/// children that it has. This allows efficient skipping over entire subtrees
+/// when looking for an offset in the BTree.
+class RopePieceBTreeNode {
+protected:
+ /// WidthFactor - This controls the number of K/V slots held in the BTree:
+ /// how wide it is. Each level of the BTree is guaranteed to have at least
+ /// 'WidthFactor' elements in it (either ropepieces or children), (except
+ /// the root, which may have less) and may have at most 2*WidthFactor
+ /// elements.
+ enum { WidthFactor = 8 };
+
+ /// Size - This is the number of bytes of file this node (including any
+ /// potential children) covers.
+ unsigned Size = 0;
+
+ /// IsLeaf - True if this is an instance of RopePieceBTreeLeaf, false if it
+ /// is an instance of RopePieceBTreeInterior.
+ bool IsLeaf;
+
+ RopePieceBTreeNode(bool isLeaf) : IsLeaf(isLeaf) {}
+ ~RopePieceBTreeNode() = default;
+
+public:
+ bool isLeaf() const { return IsLeaf; }
+ unsigned size() const { return Size; }
+
+ void Destroy();
+
+ /// split - Split the range containing the specified offset so that we are
+ /// guaranteed that there is a place to do an insertion at the specified
+ /// offset. The offset is relative, so "0" is the start of the node.
+ ///
+ /// If there is no space in this subtree for the extra piece, the extra tree
+ /// node is returned and must be inserted into a parent.
+ RopePieceBTreeNode *split(unsigned Offset);
+
+ /// insert - Insert the specified ropepiece into this tree node at the
+ /// specified offset. The offset is relative, so "0" is the start of the
+ /// node.
+ ///
+ /// If there is no space in this subtree for the extra piece, the extra tree
+ /// node is returned and must be inserted into a parent.
+ RopePieceBTreeNode *insert(unsigned Offset, const RopePiece &R);
+
+ /// erase - Remove NumBytes from this node at the specified offset. We are
+ /// guaranteed that there is a split at Offset.
+ void erase(unsigned Offset, unsigned NumBytes);
+};
//===----------------------------------------------------------------------===//
// RopePieceBTreeLeaf Class
//===----------------------------------------------------------------------===//
- /// RopePieceBTreeLeaf - Directly manages up to '2*WidthFactor' RopePiece
- /// nodes. This directly represents a chunk of the string with those
- /// RopePieces concatenated. Since this is a B+Tree, all values (in this case
- /// instances of RopePiece) are stored in leaves like this. To make iteration
- /// over the leaves efficient, they maintain a singly linked list through the
- /// NextLeaf field. This allows the B+Tree forward iterator to be constant
- /// time for all increments.
- class RopePieceBTreeLeaf : public RopePieceBTreeNode {
- /// NumPieces - This holds the number of rope pieces currently active in the
- /// Pieces array.
- unsigned char NumPieces = 0;
-
- /// Pieces - This tracks the file chunks currently in this leaf.
- RopePiece Pieces[2*WidthFactor];
-
- /// NextLeaf - This is a pointer to the next leaf in the tree, allowing
- /// efficient in-order forward iteration of the tree without traversal.
- RopePieceBTreeLeaf **PrevLeaf = nullptr;
- RopePieceBTreeLeaf *NextLeaf = nullptr;
-
- public:
- RopePieceBTreeLeaf() : RopePieceBTreeNode(true) {}
-
- ~RopePieceBTreeLeaf() {
- if (PrevLeaf || NextLeaf)
- removeFromLeafInOrder();
- clear();
- }
+/// RopePieceBTreeLeaf - Directly manages up to '2*WidthFactor' RopePiece
+/// nodes. This directly represents a chunk of the string with those
+/// RopePieces concatenated. Since this is a B+Tree, all values (in this case
+/// instances of RopePiece) are stored in leaves like this. To make iteration
+/// over the leaves efficient, they maintain a singly linked list through the
+/// NextLeaf field. This allows the B+Tree forward iterator to be constant
+/// time for all increments.
+class RopePieceBTreeLeaf : public RopePieceBTreeNode {
+ /// NumPieces - This holds the number of rope pieces currently active in the
+ /// Pieces array.
+ unsigned char NumPieces = 0;
+
+ /// Pieces - This tracks the file chunks currently in this leaf.
+ RopePiece Pieces[2 * WidthFactor];
+
+ /// NextLeaf - This is a pointer to the next leaf in the tree, allowing
+ /// efficient in-order forward iteration of the tree without traversal.
+ RopePieceBTreeLeaf **PrevLeaf = nullptr;
+ RopePieceBTreeLeaf *NextLeaf = nullptr;
+
+public:
+ RopePieceBTreeLeaf() : RopePieceBTreeNode(true) {}
+
+ ~RopePieceBTreeLeaf() {
+ if (PrevLeaf || NextLeaf)
+ removeFromLeafInOrder();
+ clear();
+ }
- bool isFull() const { return NumPieces == 2*WidthFactor; }
+ bool isFull() const { return NumPieces == 2 * WidthFactor; }
- /// clear - Remove all rope pieces from this leaf.
- void clear() {
- while (NumPieces)
- Pieces[--NumPieces] = RopePiece();
- Size = 0;
- }
+ /// clear - Remove all rope pieces from this leaf.
+ void clear() {
+ while (NumPieces)
+ Pieces[--NumPieces] = RopePiece();
+ Size = 0;
+ }
- unsigned getNumPieces() const { return NumPieces; }
+ unsigned getNumPieces() const { return NumPieces; }
- const RopePiece &getPiece(unsigned i) const {
- assert(i < getNumPieces() && "Invalid piece ID");
- return Pieces[i];
- }
+ const RopePiece &getPiece(unsigned i) const {
+ assert(i < getNumPieces() && "Invalid piece ID");
+ return Pieces[i];
+ }
- const RopePieceBTreeLeaf *getNextLeafInOrder() const { return NextLeaf; }
+ const RopePieceBTreeLeaf *getNextLeafInOrder() const { return NextLeaf; }
- void insertAfterLeafInOrder(RopePieceBTreeLeaf *Node) {
- assert(!PrevLeaf && !NextLeaf && "Already in ordering");
+ void insertAfterLeafInOrder(RopePieceBTreeLeaf *Node) {
+ assert(!PrevLeaf && !NextLeaf && "Already in ordering");
- NextLeaf = Node->NextLeaf;
- if (NextLeaf)
- NextLeaf->PrevLeaf = &NextLeaf;
- PrevLeaf = &Node->NextLeaf;
- Node->NextLeaf = this;
- }
+ NextLeaf = Node->NextLeaf;
+ if (NextLeaf)
+ NextLeaf->PrevLeaf = &NextLeaf;
+ PrevLeaf = &Node->NextLeaf;
+ Node->NextLeaf = this;
+ }
- void removeFromLeafInOrder() {
- if (PrevLeaf) {
- *PrevLeaf = NextLeaf;
- if (NextLeaf)
- NextLeaf->PrevLeaf = PrevLeaf;
- } else if (NextLeaf) {
- NextLeaf->PrevLeaf = nullptr;
- }
+ void removeFromLeafInOrder() {
+ if (PrevLeaf) {
+ *PrevLeaf = NextLeaf;
+ if (NextLeaf)
+ NextLeaf->PrevLeaf = PrevLeaf;
+ } else if (NextLeaf) {
+ NextLeaf->PrevLeaf = nullptr;
}
+ }
- /// FullRecomputeSizeLocally - This method recomputes the 'Size' field by
- /// summing the size of all RopePieces.
- void FullRecomputeSizeLocally() {
- Size = 0;
- for (unsigned i = 0, e = getNumPieces(); i != e; ++i)
- Size += getPiece(i).size();
- }
+ /// FullRecomputeSizeLocally - This method recomputes the 'Size' field by
+ /// summing the size of all RopePieces.
+ void FullRecomputeSizeLocally() {
+ Size = 0;
+ for (unsigned i = 0, e = getNumPieces(); i != e; ++i)
+ Size += getPiece(i).size();
+ }
- /// split - Split the range containing the specified offset so that we are
- /// guaranteed that there is a place to do an insertion at the specified
- /// offset. The offset is relative, so "0" is the start of the node.
- ///
- /// If there is no space in this subtree for the extra piece, the extra tree
- /// node is returned and must be inserted into a parent.
- RopePieceBTreeNode *split(unsigned Offset);
-
- /// insert - Insert the specified ropepiece into this tree node at the
- /// specified offset. The offset is relative, so "0" is the start of the
- /// node.
- ///
- /// If there is no space in this subtree for the extra piece, the extra tree
- /// node is returned and must be inserted into a parent.
- RopePieceBTreeNode *insert(unsigned Offset, const RopePiece &R);
-
- /// erase - Remove NumBytes from this node at the specified offset. We are
- /// guaranteed that there is a split at Offset.
- void erase(unsigned Offset, unsigned NumBytes);
-
- static bool classof(const RopePieceBTreeNode *N) {
- return N->isLeaf();
- }
- };
+ /// split - Split the range containing the specified offset so that we are
+ /// guaranteed that there is a place to do an insertion at the specified
+ /// offset. The offset is relative, so "0" is the start of the node.
+ ///
+ /// If there is no space in this subtree for the extra piece, the extra tree
+ /// node is returned and must be inserted into a parent.
+ RopePieceBTreeNode *split(unsigned Offset);
+
+ /// insert - Insert the specified ropepiece into this tree node at the
+ /// specified offset. The offset is relative, so "0" is the start of the
+ /// node.
+ ///
+ /// If there is no space in this subtree for the extra piece, the extra tree
+ /// node is returned and must be inserted into a parent.
+ RopePieceBTreeNode *insert(unsigned Offset, const RopePiece &R);
+
+ /// erase - Remove NumBytes from this node at the specified offset. We are
+ /// guaranteed that there is a split at Offset.
+ void erase(unsigned Offset, unsigned NumBytes);
+
+ static bool classof(const RopePieceBTreeNode *N) { return N->isLeaf(); }
+};
} // namespace
@@ -244,7 +241,7 @@ RopePieceBTreeNode *RopePieceBTreeLeaf::split(unsigned Offset) {
// Find the piece that this offset lands in.
unsigned PieceOffs = 0;
unsigned i = 0;
- while (Offset >= PieceOffs+Pieces[i].size()) {
+ while (Offset >= PieceOffs + Pieces[i].size()) {
PieceOffs += Pieces[i].size();
++i;
}
@@ -256,13 +253,13 @@ RopePieceBTreeNode *RopePieceBTreeLeaf::split(unsigned Offset) {
// Otherwise, we need to split piece 'i' at Offset-PieceOffs. Convert Offset
// to being Piece relative.
- unsigned IntraPieceOffset = Offset-PieceOffs;
+ unsigned IntraPieceOffset = Offset - PieceOffs;
// We do this by shrinking the RopePiece and then doing an insert of the tail.
- RopePiece Tail(Pieces[i].StrData, Pieces[i].StartOffs+IntraPieceOffset,
+ RopePiece Tail(Pieces[i].StrData, Pieces[i].StartOffs + IntraPieceOffset,
Pieces[i].EndOffs);
Size -= Pieces[i].size();
- Pieces[i].EndOffs = Pieces[i].StartOffs+IntraPieceOffset;
+ Pieces[i].EndOffs = Pieces[i].StartOffs + IntraPieceOffset;
Size += Pieces[i].size();
return insert(Offset, Tail);
@@ -293,7 +290,7 @@ RopePieceBTreeNode *RopePieceBTreeLeaf::insert(unsigned Offset,
// For an insertion into a non-full leaf node, just insert the value in
// its sorted position. This requires moving later values over.
for (; i != e; --e)
- Pieces[e] = Pieces[e-1];
+ Pieces[e] = Pieces[e - 1];
Pieces[i] = R;
++NumPieces;
Size += R.size();
@@ -309,10 +306,10 @@ RopePieceBTreeNode *RopePieceBTreeLeaf::insert(unsigned Offset,
RopePieceBTreeLeaf *NewNode = new RopePieceBTreeLeaf();
// Move over the last 'WidthFactor' values from here to NewNode.
- std::copy(&Pieces[WidthFactor], &Pieces[2*WidthFactor],
+ std::copy(&Pieces[WidthFactor], &Pieces[2 * WidthFactor],
&NewNode->Pieces[0]);
// Replace old pieces with null RopePieces to drop refcounts.
- std::fill(&Pieces[WidthFactor], &Pieces[2*WidthFactor], RopePiece());
+ std::fill(&Pieces[WidthFactor], &Pieces[2 * WidthFactor], RopePiece());
// Decrease the number of values in the two nodes.
NewNode->NumPieces = NumPieces = WidthFactor;
@@ -347,33 +344,34 @@ void RopePieceBTreeLeaf::erase(unsigned Offset, unsigned NumBytes) {
// Figure out how many pieces completely cover 'NumBytes'. We want to remove
// all of them.
- for (; Offset+NumBytes > PieceOffs+getPiece(i).size(); ++i)
+ for (; Offset + NumBytes > PieceOffs + getPiece(i).size(); ++i)
PieceOffs += getPiece(i).size();
// If we exactly include the last one, include it in the region to delete.
- if (Offset+NumBytes == PieceOffs+getPiece(i).size()) {
+ if (Offset + NumBytes == PieceOffs + getPiece(i).size()) {
PieceOffs += getPiece(i).size();
++i;
}
// If we completely cover some RopePieces, erase them now.
if (i != StartPiece) {
- unsigned NumDeleted = i-StartPiece;
+ unsigned NumDeleted = i - StartPiece;
for (; i != getNumPieces(); ++i)
- Pieces[i-NumDeleted] = Pieces[i];
+ Pieces[i - NumDeleted] = Pieces[i];
// Drop references to dead rope pieces.
- std::fill(&Pieces[getNumPieces()-NumDeleted], &Pieces[getNumPieces()],
+ std::fill(&Pieces[getNumPieces() - NumDeleted], &Pieces[getNumPieces()],
RopePiece());
NumPieces -= NumDeleted;
- unsigned CoverBytes = PieceOffs-Offset;
+ unsigned CoverBytes = PieceOffs - Offset;
NumBytes -= CoverBytes;
Size -= CoverBytes;
}
// If we completely removed some stuff, we could be done.
- if (NumBytes == 0) return;
+ if (NumBytes == 0)
+ return;
// Okay, now might be erasing part of some Piece. If this is the case, then
// move the start point of the piece.
@@ -390,81 +388,79 @@ void RopePieceBTreeLeaf::erase(unsigned Offset, unsigned NumBytes) {
namespace {
- /// RopePieceBTreeInterior - This represents an interior node in the B+Tree,
- /// which holds up to 2*WidthFactor pointers to child nodes.
- class RopePieceBTreeInterior : public RopePieceBTreeNode {
- /// NumChildren - This holds the number of children currently active in the
- /// Children array.
- unsigned char NumChildren = 0;
+/// RopePieceBTreeInterior - This represents an interior node in the B+Tree,
+/// which holds up to 2*WidthFactor pointers to child nodes.
+class RopePieceBTreeInterior : public RopePieceBTreeNode {
+ /// NumChildren - This holds the number of children currently active in the
+ /// Children array.
+ unsigned char NumChildren = 0;
- RopePieceBTreeNode *Children[2*WidthFactor];
+ RopePieceBTreeNode *Children[2 * WidthFactor];
- public:
- RopePieceBTreeInterior() : RopePieceBTreeNode(false) {}
+public:
+ RopePieceBTreeInterior() : RopePieceBTreeNode(false) {}
- RopePieceBTreeInterior(RopePieceBTreeNode *LHS, RopePieceBTreeNode *RHS)
- : RopePieceBTreeNode(false) {
- Children[0] = LHS;
- Children[1] = RHS;
- NumChildren = 2;
- Size = LHS->size() + RHS->size();
- }
+ RopePieceBTreeInterior(RopePieceBTreeNode *LHS, RopePieceBTreeNode *RHS)
+ : RopePieceBTreeNode(false) {
+ Children[0] = LHS;
+ Children[1] = RHS;
+ NumChildren = 2;
+ Size = LHS->size() + RHS->size();
+ }
- ~RopePieceBTreeInterior() {
- for (unsigned i = 0, e = getNumChildren(); i != e; ++i)
- Children[i]->Destroy();
- }
+ ~RopePieceBTreeInterior() {
+ for (unsigned i = 0, e = getNumChildren(); i != e; ++i)
+ Children[i]->Destroy();
+ }
- bool isFull() const { return NumChildren == 2*WidthFactor; }
+ bool isFull() const { return NumChildren == 2 * WidthFactor; }
- unsigned getNumChildren() const { return NumChildren; }
+ unsigned getNumChildren() const { return NumChildren; }
- const RopePieceBTreeNode *getChild(unsigned i) const {
- assert(i < NumChildren && "invalid child #");
- return Children[i];
- }
+ const RopePieceBTreeNode *getChild(unsigned i) const {
+ assert(i < NumChildren && "invalid child #");
+ return Children[i];
+ }
- RopePieceBTreeNode *getChild(unsigned i) {
- assert(i < NumChildren && "invalid child #");
- return Children[i];
- }
+ RopePieceBTreeNode *getChild(unsigned i) {
+ assert(i < NumChildren && "invalid child #");
+ return Children[i];
+ }
- /// FullRecomputeSizeLocally - Recompute the Size field of this node by
- /// summing up the sizes of the child nodes.
- void FullRecomputeSizeLocally() {
- Size = 0;
- for (unsigned i = 0, e = getNumChildren(); i != e; ++i)
- Size += getChild(i)->size();
- }
+ /// FullRecomputeSizeLocally - Recompute the Size field of this node by
+ /// summing up the sizes of the child nodes.
+ void FullRecomputeSizeLocally() {
+ Size = 0;
+ for (unsigned i = 0, e = getNumChildren(); i != e; ++i)
+ Size += getChild(i)->size();
+ }
- /// split - Split the range containing the specified offset so that we are
- /// guaranteed that there is a place to do an insertion at the specified
- /// offset. The offset is relative, so "0" is the start of the node.
- ///
- /// If there is no space in this subtree for the extra piece, the extra tree
- /// node is returned and must be inserted into a parent.
- RopePieceBTreeNode *split(unsigned Offset);
-
- /// insert - Insert the specified ropepiece into this tree node at the
- /// specified offset. The offset is relative, so "0" is the start of the
- /// node.
- ///
- /// If there is no space in this subtree for the extra piece, the extra tree
- /// node is returned and must be inserted into a parent.
- RopePieceBTreeNode *insert(unsigned Offset, const RopePiece &R);
-
- /// HandleChildPiece - A child propagated an insertion result up to us.
- /// Insert the new child, and/or propagate the result further up the tree.
- RopePieceBTreeNode *HandleChildPiece(unsigned i, RopePieceBTreeNode *RHS);
-
- /// erase - Remove NumBytes from this node at the specified offset. We are
- /// guaranteed that there is a split at Offset.
- void erase(unsigned Offset, unsigned NumBytes);
-
- static bool classof(const RopePieceBTreeNode *N) {
- return !N->isLeaf();
- }
- };
+ /// split - Split the range containing the specified offset so that we are
+ /// guaranteed that there is a place to do an insertion at the specified
+ /// offset. The offset is relative, so "0" is the start of the node.
+ ///
+ /// If there is no space in this subtree for the extra piece, the extra tree
+ /// node is returned and must be inserted into a parent.
+ RopePieceBTreeNode *split(unsigned Offset);
+
+ /// insert - Insert the specified ropepiece into this tree node at the
+ /// specified offset. The offset is relative, so "0" is the start of the
+ /// node.
+ ///
+ /// If there is no space in this subtree for the extra piece, the extra tree
+ /// node is returned and must be inserted into a parent.
+ RopePieceBTreeNode *insert(unsigned Offset, const RopePiece &R);
+
+ /// HandleChildPiece - A child propagated an insertion result up to us.
+ /// Insert the new child, and/or propagate the result further up the tree.
+ RopePieceBTreeNode *HandleChildPiece(unsigned i, RopePieceBTreeNode *RHS);
+
+ /// erase - Remove NumBytes from this node at the specified offset. We are
+ /// guaranteed that there is a split at Offset.
+ void erase(unsigned Offset, unsigned NumBytes);
+
+ static bool classof(const RopePieceBTreeNode *N) { return !N->isLeaf(); }
+};
} // namespace
@@ -481,7 +477,7 @@ RopePieceBTreeNode *RopePieceBTreeInterior::split(unsigned Offset) {
unsigned ChildOffset = 0;
unsigned i = 0;
- for (; Offset >= ChildOffset+getChild(i)->size(); ++i)
+ for (; Offset >= ChildOffset + getChild(i)->size(); ++i)
ChildOffset += getChild(i)->size();
// If already split there, we're done.
@@ -489,7 +485,7 @@ RopePieceBTreeNode *RopePieceBTreeInterior::split(unsigned Offset) {
return nullptr;
// Otherwise, recursively split the child.
- if (RopePieceBTreeNode *RHS = getChild(i)->split(Offset-ChildOffset))
+ if (RopePieceBTreeNode *RHS = getChild(i)->split(Offset - ChildOffset))
return HandleChildPiece(i, RHS);
return nullptr; // Done!
}
@@ -509,17 +505,17 @@ RopePieceBTreeNode *RopePieceBTreeInterior::insert(unsigned Offset,
unsigned ChildOffs = 0;
if (Offset == size()) {
// Fastpath for a common case. Insert at end of last child.
- i = e-1;
- ChildOffs = size()-getChild(i)->size();
+ i = e - 1;
+ ChildOffs = size() - getChild(i)->size();
} else {
- for (; Offset > ChildOffs+getChild(i)->size(); ++i)
+ for (; Offset > ChildOffs + getChild(i)->size(); ++i)
ChildOffs += getChild(i)->size();
}
Size += R.size();
// Insert at the end of this child.
- if (RopePieceBTreeNode *RHS = getChild(i)->insert(Offset-ChildOffs, R))
+ if (RopePieceBTreeNode *RHS = getChild(i)->insert(Offset - ChildOffs, R))
return HandleChildPiece(i, RHS);
return nullptr;
@@ -534,9 +530,9 @@ RopePieceBTreeInterior::HandleChildPiece(unsigned i, RopePieceBTreeNode *RHS) {
if (!isFull()) {
// Insert RHS after child 'i'.
if (i + 1 != getNumChildren())
- memmove(&Children[i+2], &Children[i+1],
- (getNumChildren()-i-1)*sizeof(Children[0]));
- Children[i+1] = RHS;
+ memmove(&Children[i + 2], &Children[i + 1],
+ (getNumChildren() - i - 1) * sizeof(Children[0]));
+ Children[i + 1] = RHS;
++NumChildren;
return nullptr;
}
@@ -549,7 +545,7 @@ RopePieceBTreeInterior::HandleChildPiece(unsigned i, RopePieceBTreeNode *RHS) {
// Move over the last 'WidthFactor' values from here to NewNode.
memcpy(&NewNode->Children[0], &Children[WidthFactor],
- WidthFactor*sizeof(Children[0]));
+ WidthFactor * sizeof(Children[0]));
// Decrease the number of values in the two nodes.
NewNode->NumChildren = NumChildren = WidthFactor;
@@ -559,7 +555,7 @@ RopePieceBTreeInterior::HandleChildPiece(unsigned i, RopePieceBTreeNode *RHS) {
if (i < WidthFactor)
this->HandleChildPiece(i, RHS);
else
- NewNode->HandleChildPiece(i-WidthFactor, RHS);
+ NewNode->HandleChildPiece(i - WidthFactor, RHS);
// Recompute the two nodes' size.
NewNode->FullRecomputeSizeLocally();
@@ -585,7 +581,7 @@ void RopePieceBTreeInterior::erase(unsigned Offset, unsigned NumBytes) {
// If we are deleting something contained entirely in the child, pass on the
// request.
- if (Offset+NumBytes < CurChild->size()) {
+ if (Offset + NumBytes < CurChild->size()) {
CurChild->erase(Offset, NumBytes);
return;
}
@@ -593,7 +589,7 @@ void RopePieceBTreeInterior::erase(unsigned Offset, unsigned NumBytes) {
// If this deletion request starts somewhere in the middle of the child, it
// must be deleting to the end of the child.
if (Offset) {
- unsigned BytesFromChild = CurChild->size()-Offset;
+ unsigned BytesFromChild = CurChild->size() - Offset;
CurChild->erase(Offset, BytesFromChild);
NumBytes -= BytesFromChild;
// Start at the beginning of the next child.
@@ -608,8 +604,8 @@ void RopePieceBTreeInterior::erase(unsigned Offset, unsigned NumBytes) {
CurChild->Destroy();
--NumChildren;
if (i != getNumChildren())
- memmove(&Children[i], &Children[i+1],
- (getNumChildren()-i)*sizeof(Children[0]));
+ memmove(&Children[i], &Children[i + 1],
+ (getNumChildren() - i) * sizeof(Children[0]));
}
}
@@ -654,7 +650,7 @@ RopePieceBTreeNode *RopePieceBTreeNode::insert(unsigned Offset,
/// erase - Remove NumBytes from this node at the specified offset. We are
/// guaranteed that there is a split at Offset.
void RopePieceBTreeNode::erase(unsigned Offset, unsigned NumBytes) {
- assert(Offset+NumBytes <= size() && "Invalid offset to erase!");
+ assert(Offset + NumBytes <= size() && "Invalid offset to erase!");
if (auto *Leaf = dyn_cast<RopePieceBTreeLeaf>(this))
return Leaf->erase(Offset, NumBytes);
return cast<RopePieceBTreeInterior>(this)->erase(Offset, NumBytes);
@@ -665,7 +661,7 @@ void RopePieceBTreeNode::erase(unsigned Offset, unsigned NumBytes) {
//===----------------------------------------------------------------------===//
static const RopePieceBTreeLeaf *getCN(const void *P) {
- return static_cast<const RopePieceBTreeLeaf*>(P);
+ return static_cast<const RopePieceBTreeLeaf *>(P);
}
// begin iterator.
@@ -686,13 +682,14 @@ RopePieceBTreeIterator::RopePieceBTreeIterator(const void *n) {
if (CurNode)
CurPiece = &getCN(CurNode)->getPiece(0);
- else // Empty tree, this is an end() iterator.
+ else // Empty tree, this is an end() iterator.
CurPiece = nullptr;
CurChar = 0;
}
void RopePieceBTreeIterator::MoveToNextPiece() {
- if (CurPiece != &getCN(CurNode)->getPiece(getCN(CurNode)->getNumPieces()-1)) {
+ if (CurPiece !=
+ &getCN(CurNode)->getPiece(getCN(CurNode)->getNumPieces() - 1)) {
CurChar = 0;
++CurPiece;
return;
@@ -715,25 +712,19 @@ void RopePieceBTreeIterator::MoveToNextPiece() {
//===----------------------------------------------------------------------===//
static RopePieceBTreeNode *getRoot(void *P) {
- return static_cast<RopePieceBTreeNode*>(P);
+ return static_cast<RopePieceBTreeNode *>(P);
}
-RopePieceBTree::RopePieceBTree() {
- Root = new RopePieceBTreeLeaf();
-}
+RopePieceBTree::RopePieceBTree() { Root = new RopePieceBTreeLeaf(); }
RopePieceBTree::RopePieceBTree(const RopePieceBTree &RHS) {
assert(RHS.empty() && "Can't copy non-empty tree yet");
Root = new RopePieceBTreeLeaf();
}
-RopePieceBTree::~RopePieceBTree() {
- getRoot(Root)->Destroy();
-}
+RopePieceBTree::~RopePieceBTree() { getRoot(Root)->Destroy(); }
-unsigned RopePieceBTree::size() const {
- return getRoot(Root)->size();
-}
+unsigned RopePieceBTree::size() const { return getRoot(Root)->size(); }
void RopePieceBTree::clear() {
if (auto *Leaf = dyn_cast<RopePieceBTreeLeaf>(getRoot(Root)))
@@ -772,24 +763,24 @@ void RopePieceBTree::erase(unsigned Offset, unsigned NumBytes) {
/// the AllocBuffer object to aggregate requests for small strings into one
/// allocation instead of doing tons of tiny allocations.
RopePiece RewriteRope::MakeRopeString(const char *Start, const char *End) {
- unsigned Len = End-Start;
+ unsigned Len = End - Start;
assert(Len && "Zero length RopePiece is invalid!");
// If we have space for this string in the current alloc buffer, use it.
- if (AllocOffs+Len <= AllocChunkSize) {
- memcpy(AllocBuffer->Data+AllocOffs, Start, Len);
+ if (AllocOffs + Len <= AllocChunkSize) {
+ memcpy(AllocBuffer->Data + AllocOffs, Start, Len);
AllocOffs += Len;
- return RopePiece(AllocBuffer, AllocOffs-Len, AllocOffs);
+ return RopePiece(AllocBuffer, AllocOffs - Len, AllocOffs);
}
// If we don't have enough room because this specific allocation is huge,
// just allocate a new rope piece for it alone.
if (Len > AllocChunkSize) {
- unsigned Size = End-Start+sizeof(RopeRefCountString)-1;
+ unsigned Size = End - Start + sizeof(RopeRefCountString) - 1;
auto *Res = reinterpret_cast<RopeRefCountString *>(new char[Size]);
Res->RefCount = 0;
- memcpy(Res->Data, Start, End-Start);
- return RopePiece(Res, 0, End-Start);
+ memcpy(Res->Data, Start, End - Start);
+ return RopePiece(Res, 0, End - Start);
}
// Otherwise, this was a small request but we just don't have space for it
diff --git a/llvm/unittests/ADT/CMakeLists.txt b/llvm/unittests/ADT/CMakeLists.txt
index f48d840a10595..745e4d9fb74a4 100644
--- a/llvm/unittests/ADT/CMakeLists.txt
+++ b/llvm/unittests/ADT/CMakeLists.txt
@@ -63,6 +63,7 @@ add_llvm_unittest(ADTTests
PostOrderIteratorTest.cpp
PriorityWorklistTest.cpp
RangeAdapterTest.cpp
+ RewriteBufferTest.cpp
SCCIteratorTest.cpp
STLExtrasTest.cpp
STLForwardCompatTest.cpp
diff --git a/clang/unittests/Rewrite/RewriteBufferTest.cpp b/llvm/unittests/ADT/RewriteBufferTest.cpp
similarity index 96%
rename from clang/unittests/Rewrite/RewriteBufferTest.cpp
rename to llvm/unittests/ADT/RewriteBufferTest.cpp
index bf29c0ff92830..3b367daa7806e 100644
--- a/clang/unittests/Rewrite/RewriteBufferTest.cpp
+++ b/llvm/unittests/ADT/RewriteBufferTest.cpp
@@ -6,11 +6,10 @@
//
//===----------------------------------------------------------------------===//
-#include "clang/Rewrite/Core/RewriteBuffer.h"
+#include "llvm/ADT/RewriteBuffer.h"
#include "gtest/gtest.h"
using namespace llvm;
-using namespace clang;
namespace {
@@ -32,7 +31,7 @@ static void tagRange(unsigned Offset, unsigned Len, StringRef tagName,
raw_string_ostream(EndTag) << "</" << tagName << '>';
Buf.InsertTextAfter(Offset, BeginTag);
- Buf.InsertTextBefore(Offset+Len, EndTag);
+ Buf.InsertTextBefore(Offset + Len, EndTag);
}
TEST(RewriteBuffer, TagRanges) {
More information about the cfe-commits
mailing list