e79aa3c0ed
Former-commit-id: a2155e9bd80020e49e72e86c44da02a8ac0e57a4
87 lines
2.8 KiB
C#
87 lines
2.8 KiB
C#
namespace System.Web.ModelBinding {
|
|
using System;
|
|
using System.Collections.Generic;
|
|
using System.Linq;
|
|
|
|
/// <summary>
|
|
/// This is a container for prefix values. It normalizes all the values into dotted-form and then stores
|
|
/// them in a sorted array. All queries for prefixes are also normalized to dotted-form, and searches
|
|
/// for ContainsPrefix are done with a binary search.
|
|
/// </summary>
|
|
internal sealed class PrefixContainer {
|
|
|
|
private readonly string[] _sortedValues;
|
|
|
|
internal PrefixContainer(IEnumerable<string> values) {
|
|
if (values == null) {
|
|
throw new ArgumentNullException("values");
|
|
}
|
|
|
|
_sortedValues = values.Where(val => val != null).ToArray();
|
|
Array.Sort(_sortedValues, StringComparer.OrdinalIgnoreCase);
|
|
}
|
|
|
|
internal bool ContainsPrefix(string prefix) {
|
|
if (prefix == null) {
|
|
throw new ArgumentNullException("prefix");
|
|
}
|
|
|
|
if (prefix.Length == 0) {
|
|
return _sortedValues.Length > 0; // only match empty string when we have some value
|
|
}
|
|
|
|
return Array.BinarySearch(_sortedValues, prefix, new PrefixComparer(prefix)) > -1;
|
|
}
|
|
|
|
internal static bool IsPrefixMatch(string prefix, string testString) {
|
|
if (testString == null) {
|
|
return false;
|
|
}
|
|
|
|
if (prefix.Length == 0) {
|
|
return true; // shortcut - non-null testString matches empty prefix
|
|
}
|
|
|
|
if (prefix.Length > testString.Length) {
|
|
return false; // not long enough
|
|
}
|
|
|
|
if (!testString.StartsWith(prefix, StringComparison.OrdinalIgnoreCase)) {
|
|
return false; // prefix doesn't match
|
|
}
|
|
|
|
if (testString.Length == prefix.Length) {
|
|
return true; // exact match
|
|
}
|
|
|
|
// invariant: testString.Length > prefix.Length
|
|
switch (testString[prefix.Length]) {
|
|
case '.':
|
|
case '[':
|
|
return true; // known delimiters
|
|
|
|
default:
|
|
return false; // not known delimiter
|
|
}
|
|
}
|
|
|
|
private sealed class PrefixComparer : IComparer<String> {
|
|
private string _prefix;
|
|
|
|
public PrefixComparer(string prefix) {
|
|
_prefix = prefix;
|
|
}
|
|
|
|
public int Compare(string x, string y) {
|
|
string testString = Object.ReferenceEquals(x, _prefix) ? y : x;
|
|
if (IsPrefixMatch(_prefix, testString)) {
|
|
return 0;
|
|
}
|
|
|
|
return StringComparer.OrdinalIgnoreCase.Compare(x, y);
|
|
}
|
|
}
|
|
|
|
}
|
|
}
|