Last active
January 25, 2016 22:38
-
-
Save bbowyersmyth/6603b5ee69c7037a6404 to your computer and use it in GitHub Desktop.
StartsWithAlignedUnaligned
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using BenchmarkDotNet; | |
using BenchmarkDotNet.Tasks; | |
using System; | |
using System.Globalization; | |
using System.Runtime.CompilerServices; | |
namespace ConsoleApplication2 | |
{ | |
[BenchmarkTask(platform: BenchmarkPlatform.X64, jitVersion: BenchmarkJitVersion.RyuJit)] | |
public class StringCompare | |
{ | |
// Equal comparisons | |
//[Params(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 15, 16, 17, 23, 24, 25, 31, 32, | |
// 33, 39, 40, 41, 47, 48, 49, 55, 56, 57, 63, 64, 65, | |
// 95, 96, 97, 100, 127, 128, 129, 255, 256, 257, 511, 512)] | |
// Not-Equal comparisons | |
//[Params(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14)] | |
[Params(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16)] | |
public int Length = 0; | |
string _string; | |
string _startsWith; | |
string _equals; | |
[Setup] | |
public void Setup() | |
{ | |
_string = new string('a', 512); | |
// Equal comparisons | |
//_startsWith = new string('a', Length); | |
//_equals = new string(_startsWith.ToCharArray()); | |
// Not-Equal comparisons | |
_startsWith = new string('a', 17); | |
var notEquals = _startsWith.ToCharArray(); | |
notEquals[Length] = 'X'; | |
_equals = new string(notEquals); | |
} | |
[Benchmark] | |
public bool StartsWithAligned() | |
{ | |
return StartsWithAligned(_startsWith, StringComparison.Ordinal); | |
} | |
[Benchmark] | |
public bool StartsWithUnaligned() | |
{ | |
return StartsWith(_startsWith, StringComparison.Ordinal); | |
} | |
public Boolean StartsWith(String value, StringComparison comparisonType) | |
{ | |
if ((Object)value == null) | |
{ | |
throw new ArgumentNullException("value"); | |
} | |
if (comparisonType < StringComparison.CurrentCulture || comparisonType > StringComparison.OrdinalIgnoreCase) | |
{ | |
throw new ArgumentException("NotSupported_StringComparison", "comparisonType"); | |
} | |
if ((Object)_string == (Object)value) | |
{ | |
return true; | |
} | |
if (value.Length == 0) | |
{ | |
return true; | |
} | |
switch (comparisonType) | |
{ | |
case StringComparison.CurrentCulture: | |
return CultureInfo.CurrentCulture.CompareInfo.IsPrefix(_string, value, CompareOptions.None); | |
case StringComparison.CurrentCultureIgnoreCase: | |
return CultureInfo.CurrentCulture.CompareInfo.IsPrefix(_string, value, CompareOptions.IgnoreCase); | |
case StringComparison.InvariantCulture: | |
return CultureInfo.InvariantCulture.CompareInfo.IsPrefix(_string, value, CompareOptions.None); | |
case StringComparison.InvariantCultureIgnoreCase: | |
return CultureInfo.InvariantCulture.CompareInfo.IsPrefix(_string, value, CompareOptions.IgnoreCase); | |
case StringComparison.Ordinal: | |
if (_string.Length < value.Length || _string[0] != value[0]) | |
{ | |
return false; | |
} | |
return (value.Length == 1) ? | |
true : // First char is the same and thats all there is to compare | |
StartsWithOrdinalUnaligned(_string, value, value.Length); | |
case StringComparison.OrdinalIgnoreCase: | |
if (_string.Length < value.Length) | |
{ | |
return false; | |
} | |
return true; | |
default: | |
throw new ArgumentException("NotSupported_StringComparison", "comparisonType"); | |
} | |
} | |
public Boolean StartsWithAligned(String value, StringComparison comparisonType) | |
{ | |
if ((Object)value == null) | |
{ | |
throw new ArgumentNullException("value"); | |
} | |
if (comparisonType < StringComparison.CurrentCulture || comparisonType > StringComparison.OrdinalIgnoreCase) | |
{ | |
throw new ArgumentException("NotSupported_StringComparison", "comparisonType"); | |
} | |
if ((Object)_string == (Object)value) | |
{ | |
return true; | |
} | |
if (value.Length == 0) | |
{ | |
return true; | |
} | |
switch (comparisonType) | |
{ | |
case StringComparison.CurrentCulture: | |
return CultureInfo.CurrentCulture.CompareInfo.IsPrefix(_string, value, CompareOptions.None); | |
case StringComparison.CurrentCultureIgnoreCase: | |
return CultureInfo.CurrentCulture.CompareInfo.IsPrefix(_string, value, CompareOptions.IgnoreCase); | |
case StringComparison.InvariantCulture: | |
return CultureInfo.InvariantCulture.CompareInfo.IsPrefix(_string, value, CompareOptions.None); | |
case StringComparison.InvariantCultureIgnoreCase: | |
return CultureInfo.InvariantCulture.CompareInfo.IsPrefix(_string, value, CompareOptions.IgnoreCase); | |
case StringComparison.Ordinal: | |
if (_string.Length < value.Length || _string[0] != value[0]) | |
{ | |
return false; | |
} | |
return (value.Length == 1) ? | |
true : // First char is the same and thats all there is to compare | |
StartsWithOrdinalAligned(_string, value, value.Length); | |
case StringComparison.OrdinalIgnoreCase: | |
if (_string.Length < value.Length) | |
{ | |
return false; | |
} | |
return true; | |
default: | |
throw new ArgumentException("NotSupported_StringComparison", "comparisonType"); | |
} | |
} | |
private unsafe bool StartsWithOrdinalUnaligned(string strA, string strB, int length) | |
{ | |
fixed (char* ap = strA) | |
fixed (char* bp = strB) | |
{ | |
char* a = ap; | |
char* b = bp; | |
while (length >= 12) | |
{ | |
if (*(long*)a != *(long*)b) goto ReturnFalse; | |
if (*(long*)(a + 4) != *(long*)(b + 4)) goto ReturnFalse; | |
if (*(long*)(a + 8) != *(long*)(b + 8)) goto ReturnFalse; | |
length -= 12; a += 12; b += 12; | |
} | |
while (length >= 2) | |
{ | |
if (*(int*)a != *(int*)b) goto ReturnFalse; | |
length -= 2; a += 2; b += 2; | |
} | |
return length == 0 | *a == *b; | |
ReturnFalse: | |
return false; | |
} | |
} | |
private unsafe bool StartsWithOrdinalAligned(string strA, string strB, int length) | |
{ | |
fixed (char* ap = strA) | |
fixed (char* bp = strB) | |
{ | |
char* a = ap; | |
char* b = bp; | |
if (length >= 2) | |
{ | |
if (*(int*)a != *(int*)b) goto ReturnFalse; | |
length -= 2; a += 2; b += 2; | |
} | |
while (length >= 12) | |
{ | |
if (*(long*)a != *(long*)b) goto ReturnFalse; | |
if (*(long*)(a + 4) != *(long*)(b + 4)) goto ReturnFalse; | |
if (*(long*)(a + 8) != *(long*)(b + 8)) goto ReturnFalse; | |
length -= 12; a += 12; b += 12; | |
} | |
while (length >= 2) | |
{ | |
if (*(int*)a != *(int*)b) goto ReturnFalse; | |
length -= 2; a += 2; b += 2; | |
} | |
return length == 0 | *a == *b; | |
ReturnFalse: | |
return false; | |
} | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Two 17 character strings that differ at index n:
Results for when strings match: