Last active
May 13, 2016 22:15
-
-
Save bbowyersmyth/96a4bf0c82708b7b96d8c725031c6ff9 to your computer and use it in GitHub Desktop.
This file contains hidden or 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.Attributes; | |
using System; | |
namespace ConsoleApplication2 | |
{ | |
[Config("jobs=RyuJitX64")] | |
public class Pad | |
{ | |
[Params(1, 10, 50, 90, 100)] | |
public int length = 0; | |
[Params(100)] | |
public int padLength = 0; | |
public string _string; | |
[Setup] | |
public void Setup() | |
{ | |
_string = new string('a', length); | |
} | |
[Benchmark] | |
public string ClrPadLeft() | |
{ | |
return _string.PadLeft(padLength, '-'); | |
} | |
[Benchmark] | |
public string RtPadLeft() | |
{ | |
return RTPadLeft(padLength, '-'); | |
} | |
[Benchmark] | |
public string ClrPadRight() | |
{ | |
return _string.PadRight(padLength, '-'); | |
} | |
[Benchmark] | |
public string RtPadRight() | |
{ | |
return RTPadRight(padLength, '-'); | |
} | |
public string RTPadLeft(int totalWidth, char paddingChar) | |
{ | |
if (totalWidth < 0) | |
throw new ArgumentOutOfRangeException("totalWidth", "ArgumentOutOfRange_NeedNonNegNum"); | |
int oldLength = _string.Length; | |
int count = totalWidth - oldLength; | |
if (count <= 0) | |
return _string; | |
String result = new string('\0', totalWidth); | |
unsafe | |
{ | |
fixed (char* dst = result) | |
{ | |
for (int i = 0; i < count; i++) | |
dst[i] = paddingChar; | |
fixed (char* src = _string) | |
{ | |
wstrcpy(dst + count, src, oldLength); | |
} | |
} | |
} | |
return result; | |
} | |
public string RTPadRight(int totalWidth, char paddingChar) | |
{ | |
if (totalWidth < 0) | |
throw new ArgumentOutOfRangeException("totalWidth", "ArgumentOutOfRange_NeedNonNegNum"); | |
int oldLength = _string.Length; | |
int count = totalWidth - oldLength; | |
if (count <= 0) | |
return _string; | |
String result = new string('\0', totalWidth); | |
unsafe | |
{ | |
fixed (char* dst = result) | |
{ | |
fixed (char* src = _string) | |
{ | |
wstrcpy(dst, src, oldLength); | |
} | |
for (int i = 0; i < count; i++) | |
dst[oldLength + i] = paddingChar; | |
} | |
} | |
return result; | |
} | |
internal static unsafe void wstrcpy(char* dmem, char* smem, int charCount) | |
{ | |
Memmove((byte*)dmem, (byte*)smem, ((uint)charCount) * 2); | |
} | |
internal unsafe static void Memmove(byte* dest, byte* src, uint len) | |
{ | |
// P/Invoke into the native version when the buffers are overlapping and the copy needs to be performed backwards | |
// This check can produce false positives for lengths greater than Int32.MaxInt. It is fine because we want to use PInvoke path for the large lengths anyway. | |
if ((uint)dest - (uint)src < len) | |
{ | |
Buffer.MemoryCopy(src, dest, len, len); | |
return; | |
} | |
// | |
// This is portable version of memcpy. It mirrors what the hand optimized assembly versions of memcpy typically do. | |
// | |
#if ALIGN_ACCESS | |
#error Needs porting for ALIGN_ACCESS (https://github.com/dotnet/corert/issues/430) | |
#else // ALIGN_ACCESS | |
switch (len) | |
{ | |
case 0: | |
return; | |
case 1: | |
*dest = *src; | |
return; | |
case 2: | |
*(short*)dest = *(short*)src; | |
return; | |
case 3: | |
*(short*)dest = *(short*)src; | |
*(dest + 2) = *(src + 2); | |
return; | |
case 4: | |
*(int*)dest = *(int*)src; | |
return; | |
case 5: | |
*(int*)dest = *(int*)src; | |
*(dest + 4) = *(src + 4); | |
return; | |
case 6: | |
*(int*)dest = *(int*)src; | |
*(short*)(dest + 4) = *(short*)(src + 4); | |
return; | |
case 7: | |
*(int*)dest = *(int*)src; | |
*(short*)(dest + 4) = *(short*)(src + 4); | |
*(dest + 6) = *(src + 6); | |
return; | |
case 8: | |
#if BIT64 | |
*(long*)dest = *(long*)src; | |
#else | |
*(int*)dest = *(int*)src; | |
*(int*)(dest + 4) = *(int*)(src + 4); | |
#endif | |
return; | |
case 9: | |
#if BIT64 | |
*(long*)dest = *(long*)src; | |
#else | |
*(int*)dest = *(int*)src; | |
*(int*)(dest + 4) = *(int*)(src + 4); | |
#endif | |
*(dest + 8) = *(src + 8); | |
return; | |
case 10: | |
#if BIT64 | |
*(long*)dest = *(long*)src; | |
#else | |
*(int*)dest = *(int*)src; | |
*(int*)(dest + 4) = *(int*)(src + 4); | |
#endif | |
*(short*)(dest + 8) = *(short*)(src + 8); | |
return; | |
case 11: | |
#if BIT64 | |
*(long*)dest = *(long*)src; | |
#else | |
*(int*)dest = *(int*)src; | |
*(int*)(dest + 4) = *(int*)(src + 4); | |
#endif | |
*(short*)(dest + 8) = *(short*)(src + 8); | |
*(dest + 10) = *(src + 10); | |
return; | |
case 12: | |
#if BIT64 | |
*(long*)dest = *(long*)src; | |
#else | |
*(int*)dest = *(int*)src; | |
*(int*)(dest + 4) = *(int*)(src + 4); | |
#endif | |
*(int*)(dest + 8) = *(int*)(src + 8); | |
return; | |
case 13: | |
#if BIT64 | |
*(long*)dest = *(long*)src; | |
#else | |
*(int*)dest = *(int*)src; | |
*(int*)(dest + 4) = *(int*)(src + 4); | |
#endif | |
*(int*)(dest + 8) = *(int*)(src + 8); | |
*(dest + 12) = *(src + 12); | |
return; | |
case 14: | |
#if BIT64 | |
*(long*)dest = *(long*)src; | |
#else | |
*(int*)dest = *(int*)src; | |
*(int*)(dest + 4) = *(int*)(src + 4); | |
#endif | |
*(int*)(dest + 8) = *(int*)(src + 8); | |
*(short*)(dest + 12) = *(short*)(src + 12); | |
return; | |
case 15: | |
#if BIT64 | |
*(long*)dest = *(long*)src; | |
#else | |
*(int*)dest = *(int*)src; | |
*(int*)(dest + 4) = *(int*)(src + 4); | |
#endif | |
*(int*)(dest + 8) = *(int*)(src + 8); | |
*(short*)(dest + 12) = *(short*)(src + 12); | |
*(dest + 14) = *(src + 14); | |
return; | |
case 16: | |
#if BIT64 | |
*(long*)dest = *(long*)src; | |
*(long*)(dest + 8) = *(long*)(src + 8); | |
#else | |
*(int*)dest = *(int*)src; | |
*(int*)(dest + 4) = *(int*)(src + 4); | |
*(int*)(dest + 8) = *(int*)(src + 8); | |
*(int*)(dest + 12) = *(int*)(src + 12); | |
#endif | |
return; | |
default: | |
break; | |
} | |
// P/Invoke into the native version for large lengths. | |
if (len >= 200) | |
{ | |
Buffer.MemoryCopy(src, dest, len, len); | |
return; | |
} | |
if (((int)dest & 3) != 0) | |
{ | |
if (((int)dest & 1) != 0) | |
{ | |
*dest = *src; | |
src++; | |
dest++; | |
len--; | |
if (((int)dest & 2) == 0) | |
goto Aligned; | |
} | |
*(short*)dest = *(short*)src; | |
src += 2; | |
dest += 2; | |
len -= 2; | |
Aligned:; | |
} | |
#if BIT64 | |
if (((int)dest & 4) != 0) | |
{ | |
*(int*)dest = *(int*)src; | |
src += 4; | |
dest += 4; | |
len -= 4; | |
} | |
#endif | |
uint count = len / 16; | |
while (count > 0) | |
{ | |
#if BIT64 | |
((long*)dest)[0] = ((long*)src)[0]; | |
((long*)dest)[1] = ((long*)src)[1]; | |
#else | |
((int*)dest)[0] = ((int*)src)[0]; | |
((int*)dest)[1] = ((int*)src)[1]; | |
((int*)dest)[2] = ((int*)src)[2]; | |
((int*)dest)[3] = ((int*)src)[3]; | |
#endif | |
dest += 16; | |
src += 16; | |
count--; | |
} | |
if ((len & 8) != 0) | |
{ | |
#if BIT64 | |
((long*)dest)[0] = ((long*)src)[0]; | |
#else | |
((int*)dest)[0] = ((int*)src)[0]; | |
((int*)dest)[1] = ((int*)src)[1]; | |
#endif | |
dest += 8; | |
src += 8; | |
} | |
if ((len & 4) != 0) | |
{ | |
((int*)dest)[0] = ((int*)src)[0]; | |
dest += 4; | |
src += 4; | |
} | |
if ((len & 2) != 0) | |
{ | |
((short*)dest)[0] = ((short*)src)[0]; | |
dest += 2; | |
src += 2; | |
} | |
if ((len & 1) != 0) | |
*dest = *src; | |
#endif // ALIGN_ACCESS | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment