internal List<UnchangedSegment> GetReuseMapTo(ITextSourceVersion newVersion)
		{
			ITextSourceVersion oldVersion = this.Version;
			if (oldVersion == null || newVersion == null)
				return null;
			if (!oldVersion.BelongsToSameDocumentAs(newVersion))
				return null;
			List<UnchangedSegment> reuseMap = new List<UnchangedSegment>();
			reuseMap.Add(new UnchangedSegment(0, 0, this.TextLength));
			foreach (var change in oldVersion.GetChangesTo(newVersion)) {
				bool needsSegmentRemoval = false;
				for (int i = 0; i < reuseMap.Count; i++) {
					UnchangedSegment segment = reuseMap[i];
					if (segment.NewOffset + segment.Length <= change.Offset) {
						// change is completely after this segment
						continue;
					}
					if (change.Offset + change.RemovalLength <= segment.NewOffset) {
						// change is completely before this segment
						segment.NewOffset += change.InsertionLength - change.RemovalLength;
						reuseMap[i] = segment;
						continue;
					}
					// Change is overlapping segment.
					// Split segment into two parts: the part before change, and the part after change.
					var segmentBefore = new UnchangedSegment(segment.OldOffset, segment.NewOffset, change.Offset - segment.NewOffset);
					Debug.Assert(segmentBefore.Length < segment.Length);
					
					int lengthAtEnd = segment.NewOffset + segment.Length - (change.Offset + change.RemovalLength);
					var segmentAfter = new UnchangedSegment(
						segment.OldOffset + segment.Length - lengthAtEnd,
						change.Offset + change.InsertionLength,
						lengthAtEnd);
					Debug.Assert(segmentAfter.Length < segment.Length);
					Debug.Assert(segmentBefore.Length + segmentAfter.Length <= segment.Length);
					Debug.Assert(segmentBefore.NewOffset + segmentBefore.Length <= segmentAfter.NewOffset);
					Debug.Assert(segmentBefore.OldOffset + segmentBefore.Length <= segmentAfter.OldOffset);
					if (segmentBefore.Length > 0 && segmentAfter.Length > 0) {
						reuseMap[i] = segmentBefore;
						reuseMap.Insert(++i, segmentAfter);
					} else if (segmentBefore.Length > 0) {
						reuseMap[i] = segmentBefore;
					} else {
						reuseMap[i] = segmentAfter;
						if (segmentAfter.Length <= 0)
							needsSegmentRemoval = true;
					}
				}
				if (needsSegmentRemoval)
					reuseMap.RemoveAll(s => s.Length <= 0);
			}
			return reuseMap;
		}
Beispiel #2
0
        internal List <UnchangedSegment> GetReuseMapTo(ITextSourceVersion newVersion)
        {
            ITextSourceVersion oldVersion = this.Version;

            if (oldVersion == null || newVersion == null)
            {
                return(null);
            }
            if (!oldVersion.BelongsToSameDocumentAs(newVersion))
            {
                return(null);
            }
            List <UnchangedSegment> reuseMap = new List <UnchangedSegment>();

            reuseMap.Add(new UnchangedSegment(0, 0, this.TextLength));
            foreach (var change in oldVersion.GetChangesTo(newVersion))
            {
                bool needsSegmentRemoval = false;
                for (int i = 0; i < reuseMap.Count; i++)
                {
                    UnchangedSegment segment = reuseMap[i];
                    if (segment.NewOffset + segment.Length <= change.Offset)
                    {
                        // change is completely after this segment
                        continue;
                    }
                    if (change.Offset + change.RemovalLength <= segment.NewOffset)
                    {
                        // change is completely before this segment
                        segment.NewOffset += change.InsertionLength - change.RemovalLength;
                        reuseMap[i]        = segment;
                        continue;
                    }
                    // Change is overlapping segment.
                    // Split segment into two parts: the part before change, and the part after change.
                    var segmentBefore = new UnchangedSegment(segment.OldOffset, segment.NewOffset, change.Offset - segment.NewOffset);
                    Debug.Assert(segmentBefore.Length < segment.Length);

                    int lengthAtEnd  = segment.NewOffset + segment.Length - (change.Offset + change.RemovalLength);
                    var segmentAfter = new UnchangedSegment(
                        segment.OldOffset + segment.Length - lengthAtEnd,
                        change.Offset + change.InsertionLength,
                        lengthAtEnd);
                    Debug.Assert(segmentAfter.Length < segment.Length);
                    Debug.Assert(segmentBefore.Length + segmentAfter.Length <= segment.Length);
                    Debug.Assert(segmentBefore.NewOffset + segmentBefore.Length <= segmentAfter.NewOffset);
                    Debug.Assert(segmentBefore.OldOffset + segmentBefore.Length <= segmentAfter.OldOffset);
                    if (segmentBefore.Length > 0 && segmentAfter.Length > 0)
                    {
                        reuseMap[i] = segmentBefore;
                        reuseMap.Insert(++i, segmentAfter);
                    }
                    else if (segmentBefore.Length > 0)
                    {
                        reuseMap[i] = segmentBefore;
                    }
                    else
                    {
                        reuseMap[i] = segmentAfter;
                        if (segmentAfter.Length <= 0)
                        {
                            needsSegmentRemoval = true;
                        }
                    }
                }
                if (needsSegmentRemoval)
                {
                    reuseMap.RemoveAll(s => s.Length <= 0);
                }
            }
            return(reuseMap);
        }