5
// mkrueger <mkrueger@novell.com>
7
// Copyright (c) 2011 Novell, Inc (http://www.novell.com)
9
// Permission is hereby granted, free of charge, to any person obtaining a copy
10
// of this software and associated documentation files (the "Software"), to deal
11
// in the Software without restriction, including without limitation the rights
12
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
13
// copies of the Software, and to permit persons to whom the Software is
14
// furnished to do so, subject to the following conditions:
16
// The above copyright notice and this permission notice shall be included in
17
// all copies or substantial portions of the Software.
19
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
22
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
23
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
24
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
27
using System.Collections.Generic;
29
using Mono.TextEditor.Utils;
31
namespace Mono.TextEditor
34
/// A segment tree contains overlapping segments and get all segments overlapping a segment. It's implemented as a augmented interval tree
35
/// described in Cormen et al. (2001, Section 14.3: Interval trees, pp. 311ā317).
37
public class SegmentTree<T> : ISegmentTree where T : TreeSegment
39
internal readonly RedBlackTree<T> tree = new RedBlackTree<T> ();
47
public IEnumerable<T> Segments {
52
var node = root.GetOuterLeft ();
53
while (node != null) {
55
node = node.GetNextNode ();
60
public void InstallListener (Document doc)
62
doc.TextReplaced += UpdateOnTextReplace;
65
public void RemoveListener (Document doc)
67
doc.TextReplaced -= UpdateOnTextReplace;
70
void UpdateOnTextReplace (object sender, ReplaceEventArgs e)
73
var length = (e.Value != null ? e.Value.Length : 0);
74
foreach (var segment in GetSegmentsAt (e.Offset).Where (s => s.Offset < e.Offset && e.Offset < s.EndOffset)) {
75
segment.Length += length;
76
segment.UpdateAugmentedData ();
78
var node = SearchFirstSegmentWithStartAfter (e.Offset);
80
node.DistanceToPrevNode += length;
81
node.UpdateAugmentedData ();
85
int delta = (e.Value != null ? e.Value.Length : 0) - e.Count;
86
foreach (var segment in new List<T> (GetSegmentsOverlapping (e.Offset, e.Count))) {
87
if (segment.Offset <= e.Offset) {
88
if (segment.EndOffset >= e.Offset + e.Count) {
89
segment.Length += delta;
91
segment.Length = e.Offset - segment.Offset;
93
segment.UpdateAugmentedData ();
96
int remainingLength = segment.EndOffset - (e.Offset + e.Count);
99
if (remainingLength > 0) {
100
segment.Offset = e.Offset + e.Count;
101
segment.Length = remainingLength;
106
var next = SearchFirstSegmentWithStartAfter (e.Offset + 1);
109
next.DistanceToPrevNode += delta;
110
next.UpdateAugmentedData ();
114
public void Add (TreeSegment node)
117
throw new ArgumentNullException ("node");
118
if (node.segmentTree != null)
119
throw new InvalidOperationException ("Node already attached.");
121
node.segmentTree = this;
124
int insertionOffset = node.Offset;
125
node.DistanceToMaxEnd = node.Length;
127
if (tree.Root == null) {
130
node.TotalLength = node.DistanceToPrevNode;
134
if (insertionOffset < tree.Root.TotalLength) {
135
var n = SearchNode (ref insertionOffset);
136
node.TotalLength = node.DistanceToPrevNode = insertionOffset;
137
n.DistanceToPrevNode -= insertionOffset;
138
tree.InsertBefore (n, node);
142
node.DistanceToPrevNode = node.TotalLength = insertionOffset - tree.Root.TotalLength;
143
tree.InsertRight (tree.Root.GetOuterRight (), node);
146
public void Remove (TreeSegment node)
148
var calculatedOffset = node.Offset;
149
var next = node.GetNextNode ();
151
next.DistanceToPrevNode += node.DistanceToPrevNode;
154
next.UpdateAugmentedData ();
155
node.segmentTree = null;
156
node.parent = node.left = node.right = null;
157
node.DistanceToPrevNode = calculatedOffset;
160
TreeSegment SearchFirstSegmentWithStartAfter (int startOffset)
162
if (tree.Root == null)
164
if (startOffset <= 0)
165
return tree.Root.GetOuterLeft ();
166
var result = SearchNode (ref startOffset);
167
while (startOffset == 0) {
168
var pre = result == null ? tree.Root.GetOuterRight () : result.GetPrevNode ();
169
startOffset += pre.DistanceToPrevNode;
175
TreeSegment SearchNode (ref int offset)
177
TreeSegment n = tree.Root;
179
if (n.left != null) {
180
if (offset < n.left.TotalLength) {
184
offset -= n.left.TotalLength;
186
if (offset < n.DistanceToPrevNode)
188
offset -= n.DistanceToPrevNode;
195
public IEnumerable<T> GetSegmentsAt (int offset)
197
return GetSegmentsOverlapping (offset, 0);
200
public IEnumerable<T> GetSegmentsOverlapping (ISegment segment)
203
return Enumerable.Empty<T> ();
204
return GetSegmentsOverlapping (segment.Offset, segment.Length);
209
internal TreeSegment node;
210
internal int start, end;
212
public Interval (TreeSegment node,int start,int end)
220
public IEnumerable<T> GetSegmentsOverlapping (int offset, int length)
222
if (tree.Root == null)
224
Stack<Interval> intervalStack = new Stack<Interval> ();
225
intervalStack.Push (new Interval (tree.Root, offset, offset + length));
226
while (intervalStack.Count > 0) {
227
var interval = intervalStack.Pop ();
228
if (interval.end < 0)
231
var node = interval.node;
232
int nodeStart = interval.start - node.DistanceToPrevNode;
233
int nodeEnd = interval.end - node.DistanceToPrevNode;
234
if (node.left != null) {
235
nodeStart -= node.left.TotalLength;
236
nodeEnd -= node.left.TotalLength;
239
if (node.DistanceToMaxEnd < nodeStart)
242
if (node.left != null)
243
intervalStack.Push (new Interval (node.left, interval.start, interval.end));
248
if (nodeStart <= node.Length)
249
yield return (T)node;
251
if (node.right != null)
252
intervalStack.Push (new Interval (node.right, nodeStart, nodeEnd));
257
interface ISegmentTree
259
void Add (TreeSegment segment);
260
void Remove (TreeSegment segment);
263
public class TreeSegment : Segment, IRedBlackTreeNode
265
internal ISegmentTree segmentTree;
267
public override int Offset {
269
if (segmentTree == null)
270
return DistanceToPrevNode;
273
int offset = curNode.DistanceToPrevNode;
274
if (curNode.left != null)
275
offset += curNode.left.TotalLength;
276
while (curNode.parent != null) {
277
if (curNode == curNode.parent.right) {
278
if (curNode.parent.left != null)
279
offset += curNode.parent.left.TotalLength;
280
offset += curNode.parent.DistanceToPrevNode;
282
curNode = curNode.parent;
287
if (segmentTree != null)
288
segmentTree.Remove (this);
289
DistanceToPrevNode = value;
290
if (segmentTree != null)
291
segmentTree.Add (this);
295
// TotalLength = DistanceToPrevNode + Left.DistanceToPrevNode + Right.DistanceToPrevNode
296
internal int TotalLength;
298
internal int DistanceToPrevNode;
300
// DistanceToMaxEnd = Max (Length, left.DistanceToMaxEnd + Max (left.Offset, right.Offset) - Offset)
301
internal int DistanceToMaxEnd;
303
protected TreeSegment ()
307
public TreeSegment (int offset, int length) : base (offset, length)
311
public TreeSegment (ISegment segment) : base (segment)
315
#region IRedBlackTreeNode implementation
316
public void UpdateAugmentedData ()
318
int totalLength = DistanceToPrevNode;
319
int distanceToMaxEnd = Length;
322
totalLength += left.TotalLength;
323
int leftdistance = left.DistanceToMaxEnd - DistanceToPrevNode;
324
if (left.right != null)
325
leftdistance -= left.right.TotalLength;
326
if (leftdistance > distanceToMaxEnd)
327
distanceToMaxEnd = leftdistance;
331
totalLength += right.TotalLength;
332
int rightdistance = right.DistanceToMaxEnd + right.DistanceToPrevNode;
333
if (right.left != null)
334
rightdistance += right.left.TotalLength;
335
if (rightdistance > distanceToMaxEnd)
336
distanceToMaxEnd = rightdistance;
339
if (TotalLength != totalLength || DistanceToMaxEnd != distanceToMaxEnd) {
340
TotalLength = totalLength;
341
DistanceToMaxEnd = distanceToMaxEnd;
343
parent.UpdateAugmentedData ();
347
internal TreeSegment parent, left, right;
349
Mono.TextEditor.Utils.IRedBlackTreeNode Mono.TextEditor.Utils.IRedBlackTreeNode.Parent {
354
parent = (TreeSegment)value;
358
Mono.TextEditor.Utils.IRedBlackTreeNode Mono.TextEditor.Utils.IRedBlackTreeNode.Left {
363
left = (TreeSegment)value;
368
IRedBlackTreeNode Mono.TextEditor.Utils.IRedBlackTreeNode.Right {
373
right = (TreeSegment)value;
377
RedBlackColor Mono.TextEditor.Utils.IRedBlackTreeNode.Color {