Skip to content

Instantly share code, notes, and snippets.

@bbowyersmyth
Last active May 13, 2016 22:15
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save bbowyersmyth/96a4bf0c82708b7b96d8c725031c6ff9 to your computer and use it in GitHub Desktop.
Save bbowyersmyth/96a4bf0c82708b7b96d8c725031c6ff9 to your computer and use it in GitHub Desktop.
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