提交 155ce00d 编写于 作者: C CyrusNajmabadi

Introduce a string slice abstraction.

上级 1d1725f1
......@@ -240,6 +240,19 @@ internal static int GetFNVHashCode(string text, int start, int length)
return hashCode;
}
internal static int GetFNVHashCodeOrdinalIgnoreCase(string text, int start, int length)
{
int hashCode = Hash.FnvOffsetBias;
int end = start + length;
for (int i = start; i < end; i++)
{
hashCode = unchecked((hashCode ^ char.ToLowerInvariant(text[i])) * Hash.FnvPrime);
}
return hashCode;
}
/// <summary>
/// Compute the hashcode of a sub-string using FNV-1a
/// See http://en.wikipedia.org/wiki/Fowler%E2%80%93Noll%E2%80%93Vo_hash_function
......
......@@ -7,6 +7,7 @@
using System.Linq;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.Text;
using Microsoft.CodeAnalysis.Utilities;
namespace Roslyn.Utilities
{
......@@ -90,9 +91,14 @@ private class Builder
private readonly BuilderNode[] _builderNodes;
public Builder(IEnumerable<string> values)
: this(values.Select(v => new StringSlice(v)))
{
}
public Builder(IEnumerable<StringSlice> values)
{
// TODO(cyrusn): Properly handle unicode normalization here.
var distinctValues = values.Where(v => v.Length > 0).Distinct(CaseInsensitiveComparison.Comparer).ToArray();
var distinctValues = values.Where(v => v.Length > 0).Distinct(StringSliceComparer.OrdinalIgnoreCase).ToArray();
var charCount = values.Sum(v => v.Length);
_concatenatedLowerCaseWords = new char[charCount];
......
// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
using System.Collections.Generic;
using System.Diagnostics;
using Microsoft.CodeAnalysis.Text;
using Roslyn.Utilities;
namespace Microsoft.CodeAnalysis.Utilities
{
internal struct StringSlice : IEquatable<StringSlice>
{
private readonly string _underlyingString;
private readonly TextSpan _span;
public StringSlice(string underlyingString, TextSpan span)
{
this._underlyingString = underlyingString;
this._span = span;
Debug.Assert(span.Start >= 0);
Debug.Assert(span.End <= underlyingString.Length);
}
public StringSlice(string value) : this(value, new TextSpan(0, value.Length))
{
}
private bool IsFullSlice =>
this._span.Start == 0 && this._span.Length == _underlyingString.Length;
public int Length => _span.Length;
public char this[int index] => _underlyingString[_span.Start + index];
public Enumerator GetEnumerator()
{
return new Enumerator(this);
}
public override bool Equals(object obj) =>
Equals((StringSlice)obj);
public bool Equals(StringSlice other)
{
return EqualsOrdinal(other);
}
internal bool EqualsOrdinal(StringSlice other)
{
if (this.IsFullSlice && other.IsFullSlice)
{
return StringComparer.Ordinal.Equals(this._underlyingString, other._underlyingString);
}
if (this._span.Length != other._span.Length)
{
return false;
}
var end = this._span.End;
for (int i = this._span.Start, j = other._span.Start; i < end; i++, j++)
{
if (this._underlyingString[i] != other._underlyingString[j])
{
return false;
}
}
return true;
}
internal bool EqualsOrdinalIgnoreCase(StringSlice other)
{
if (this.IsFullSlice && other.IsFullSlice)
{
return StringComparer.OrdinalIgnoreCase.Equals(this._underlyingString, other._underlyingString);
}
if (this._span.Length != other._span.Length)
{
return false;
}
var end = this._span.End;
for (int i = this._span.Start, j = other._span.Start; i < end; i++, j++)
{
if (char.ToLowerInvariant(this._underlyingString[i]) !=
char.ToLowerInvariant(other._underlyingString[j]))
{
return false;
}
}
return true;
}
public override int GetHashCode()
{
return GetHashCodeOrdinal();
}
internal int GetHashCodeOrdinal()
{
return Hash.GetFNVHashCode(this._underlyingString, this._span.Start, this._span.Length);
}
internal int GetHashCodeOrdinalIgnoreCase()
{
return Hash.GetFNVHashCodeOrdinalIgnoreCase(this._underlyingString, this._span.Start, this._span.Length);
}
internal int CompareToOrdinal(StringSlice other)
{
if (this.IsFullSlice && other.IsFullSlice)
{
return StringComparer.Ordinal.Compare(this._underlyingString, other._underlyingString);
}
var thisEnd = this._span.End;
var otherEnd = other._span.End;
for (int i = this._span.Start, j = other._span.Start;
i < thisEnd && j < otherEnd;
i++, j++)
{
var diff = this._underlyingString[i] - other._underlyingString[j];
if (diff != 0)
{
return diff;
}
}
// Choose the one that is shorter if their prefixes match so far.
return this.Length - other.Length;
}
internal int CompareToOrdinalIgnoreCase(StringSlice other)
{
if (this.IsFullSlice && other.IsFullSlice)
{
return StringComparer.OrdinalIgnoreCase.Compare(this._underlyingString, other._underlyingString);
}
var thisEnd = this._span.End;
var otherEnd = other._span.End;
for (int i = this._span.Start, j = other._span.Start;
i < thisEnd && j < otherEnd;
i++, j++)
{
var diff =
char.ToLowerInvariant(this._underlyingString[i]) -
char.ToLowerInvariant(other._underlyingString[j]);
if (diff != 0)
{
return diff;
}
}
// Choose the one that is shorter if their prefixes match so far.
return this.Length - other.Length;
}
public struct Enumerator
{
private readonly StringSlice _stringSlice;
private int index;
public Enumerator(StringSlice stringSlice)
{
_stringSlice = stringSlice;
index = -1;
}
public bool MoveNext()
{
index++;
return index < _stringSlice.Length;
}
public char Current => _stringSlice[index];
}
}
internal abstract class StringSliceComparer : IComparer<StringSlice>, IEqualityComparer<StringSlice>
{
public static readonly StringSliceComparer Ordinal = new OrdinalComparer();
public static readonly StringSliceComparer OrdinalIgnoreCase = new OrdinalIgnoreCaseComparer();
private class OrdinalComparer : StringSliceComparer
{
public override int Compare(StringSlice x, StringSlice y)
{
return x.CompareToOrdinal(y);
}
public override bool Equals(StringSlice x, StringSlice y)
{
return x.EqualsOrdinal(y);
}
public override int GetHashCode(StringSlice obj)
{
return obj.GetHashCodeOrdinal();
}
}
private class OrdinalIgnoreCaseComparer : StringSliceComparer
{
public override int Compare(StringSlice x, StringSlice y)
{
return x.CompareToOrdinalIgnoreCase(y);
}
public override bool Equals(StringSlice x, StringSlice y)
{
return x.EqualsOrdinalIgnoreCase(y);
}
public override int GetHashCode(StringSlice obj)
{
return obj.GetHashCodeOrdinalIgnoreCase();
}
}
public abstract int Compare(StringSlice x, StringSlice y);
public abstract bool Equals(StringSlice x, StringSlice y);
public abstract int GetHashCode(StringSlice obj);
}
}
\ No newline at end of file
......@@ -542,6 +542,7 @@
<Compile Include="Utilities\ParameterName.cs" />
<Compile Include="Utilities\SpellChecker.cs" />
<Compile Include="Utilities\StringEscapeEncoder.cs" />
<Compile Include="Utilities\StringSlice.cs" />
<Compile Include="Utilities\ValuesSources\CachedWeakValueSource.cs" />
<Compile Include="Utilities\WeakEventHandler.cs" />
<Compile Include="Versions\Extensions.cs" />
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册