//
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License. See License.txt in the project root for license information.
//
// This file contain implementations details that are subject to change without notice.
// Use at your own risk.
//
using System;
using System.Collections.Generic;
using System.Text;
using Microsoft.VisualStudio.Utilities;
namespace Microsoft.VisualStudio.Text.Differencing.Implementation
{
internal interface ITokenizedStringListInternal : ITokenizedStringList
{
string OriginalSubstring(int startIndex, int length);
}
///
/// Tokenizes the string into abutting and non-overlapping segments.
///
///
/// This class implements IList so that it can be used with
/// , which finds the differences between two sequences represented
/// as ILists.
/// Most of the members of the IList interface are unimplemented. The only
/// implemented methods are the array accessor getter (operator []), Count,
/// and IsReadOnly.
///
internal abstract class TokenizedStringList : ITokenizedStringListInternal
{
protected List Tokens = new List();
private readonly string original;
private readonly SnapshotSpan originalSpan;
///
/// Creates a tokenized string list from the original string.
/// Any derived class must initialize the Tokens list in its own constructor.
///
/// The original string.
protected TokenizedStringList(string original)
{
if (original == null)
throw new ArgumentNullException("original");
this.original = original;
}
protected TokenizedStringList(SnapshotSpan originalSpan)
{
this.originalSpan = originalSpan;
}
///
/// The original string that was tokenized.
///
public string Original
{
get
{
// A call to GetText() here could be very expensive in memory. Be careful!
return original ?? originalSpan.GetText();
}
}
internal int OriginalLength
{
get
{
return (original != null) ? original.Length : originalSpan.Length;
}
}
public string OriginalSubstring(int startIndex, int length)
{
if (original != null)
{
return original.Substring(startIndex, length);
}
else
{
ITextSnapshot snap = originalSpan.Snapshot;
return snap.GetText(originalSpan.Start.Position + startIndex, length);
}
}
///
/// Maps the index of an element to its span in the original list.
///
/// The index of the element in the element list.
/// The span of the element.
/// The specified index is either negative or exceeds the list's Count property.
/// This method returns a zero-length span at the end of the string if index
/// is equal to the list's Count property.
public Span GetElementInOriginal(int index)
{
//Pure support for backward compatibility
if (index == this.Count)
{
return new Span(this.OriginalLength, 0);
}
return this.Tokens[index];
}
///
/// Maps a span of elements in this list to the span in the original list.
///
/// The span of elements in the elements list.
/// The span mapped onto the original list.
public Span GetSpanInOriginal(Span span)
{
//Pure support for backward compatibility
if (span.Start == this.Tokens.Count)
{
return new Span(this.OriginalLength, 0);
}
int start = this.Tokens[span.Start].Start;
int end = (span.Length == 0) ? start : this.Tokens[span.End - 1].End;
return Span.FromBounds(start, end);
}
///
/// Gets a string of the given element.
///
/// The index into the list of elements.
/// The element, as a string.
/// The setter of this property throws a NotImplementedException.
public string this[int index]
{
get
{
// The out of range check will happen in GetElementInOriginal
Span span = GetElementInOriginal(index);
return this.OriginalSubstring(span.Start, span.Length);
}
set
{
throw new NotSupportedException();
}
}
internal char CharacterAt(int offset)
{
return (original != null) ? original[offset] : originalSpan.Snapshot[originalSpan.Start.Position + offset];
}
///
/// The number of elements in the list.
///
public int Count
{
get
{
return this.Tokens.Count;
}
}
///
/// Determines whether this list is read-only. It always returnes true.
///
public bool IsReadOnly
{
get { return true; }
}
#region Not Implemented
///
/// Not implemented
///
///
///
public int IndexOf(string item)
{
throw new NotSupportedException();
}
///
/// Not implemented.
///
///
///
public void Insert(int index, string item)
{
throw new NotSupportedException();
}
///
/// Not implemented.
///
///
public void RemoveAt(int index)
{
throw new NotSupportedException();
}
///
/// Not implemented.
///
///
public void Add(string item)
{
throw new NotSupportedException();
}
///
/// Not implemented.
///
public void Clear()
{
throw new NotSupportedException();
}
///
/// Not implemented.
///
public bool Contains(string item)
{
throw new NotSupportedException();
}
///
/// Not implemented.
///
public void CopyTo(string[] array, int arrayIndex)
{
throw new NotSupportedException();
}
///
/// Not implemented.
///
public bool Remove(string item)
{
throw new NotSupportedException();
}
#endregion
#region IEnumerable Members
///
/// Gets the enumerator of type string.
///
/// The enumerator of type string.
public IEnumerator GetEnumerator()
{
for (int i = 0; i < Count; i++)
yield return this[i];
}
#endregion
#region IEnumerable Members
///
/// Gets the untyped enumerator.
///
/// The untyped enumerator.
System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
#endregion
}
}