Browse Source

even better BufferPointer.Copy()

pull/126/head
Anton Firszov 9 years ago
parent
commit
20c97ddfcb
  1. 95
      src/ImageSharp/Common/Memory/BufferPointer.cs

95
src/ImageSharp/Common/Memory/BufferPointer.cs

@ -5,6 +5,7 @@
namespace ImageSharp
{
using System.Numerics;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
@ -29,19 +30,17 @@ namespace ImageSharp
public static unsafe void Copy<T>(BufferPointer<T> source, BufferPointer<T> destination, int count)
where T : struct
{
int elementSize = Unsafe.SizeOf<T>();
uint byteCount = (uint) (count * elementSize);
uint byteCount = USizeOf<T>(count);
if (byteCount > ByteCountThreshold && elementSize == sizeof(int))
if (byteCount > ByteCountThreshold)
{
// TODO: Add the optimized path for non int-compatible types
int[] srcArray = Unsafe.As<int[]>(source.Array);
Marshal.Copy(srcArray, source.Offset, destination.PointerAtOffset, count);
}
else
{
Unsafe.CopyBlock((void*)destination.PointerAtOffset, (void*)source.PointerAtOffset, byteCount);
if (TryMarshalCopy(source, destination, count))
{
return;
}
}
Unsafe.CopyBlock((void*)destination.PointerAtOffset, (void*)source.PointerAtOffset, byteCount);
}
/// <summary>
@ -55,19 +54,17 @@ namespace ImageSharp
public static unsafe void Copy<T>(BufferPointer<T> source, BufferPointer<byte> destination, int countInSource)
where T : struct
{
int elementSize = Unsafe.SizeOf<T>();
uint byteCount = (uint)(countInSource * elementSize);
uint byteCount = USizeOf<T>(countInSource);
if (byteCount > ByteCountThreshold && elementSize == sizeof(int))
{
// TODO: Add the optimized path for non int-compatible types
int[] srcArray = Unsafe.As<int[]>(source.Array);
Marshal.Copy(srcArray, source.Offset, destination.PointerAtOffset, countInSource);
}
else
if (byteCount > ByteCountThreshold)
{
Unsafe.CopyBlock((void*)destination.PointerAtOffset, (void*)source.PointerAtOffset, byteCount);
if (TryMarshalCopy(source, destination, countInSource))
{
return;
}
}
Unsafe.CopyBlock((void*)destination.PointerAtOffset, (void*)source.PointerAtOffset, byteCount);
}
/// <summary>
@ -113,5 +110,63 @@ namespace ImageSharp
public static uint USizeOf<T>(int count)
where T : struct
=> (uint)SizeOf<T>(count);
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static bool TryMarshalCopy<TSource, TDest>(BufferPointer<TSource> source, BufferPointer<TDest> destination, int count)
where TSource : struct
where TDest : struct
{
// Pattern Based On:
// https://github.com/dotnet/corefx/blob/master/src/System.Numerics.Vectors/src/System/Numerics/Vector.cs#L12
//
// Note: The following patterns are used throughout the code here and are described here
//
// PATTERN:
// if (typeof(T) == typeof(Int32)) { ... }
// else if (typeof(T) == typeof(Single)) { ... }
// EXPLANATION:
// At runtime, each instantiation of BufferPointer<T> will be type-specific, and each of these typeof blocks will be eliminated,
// as typeof(T) is a (JIT) compile-time constant for each instantiation. This design was chosen to eliminate any overhead from
// delegates and other patterns.
if (typeof(TSource) == typeof(long))
{
long[] srcArray = Unsafe.As<long[]>(source.Array);
Marshal.Copy(srcArray, source.Offset, destination.PointerAtOffset, count);
return true;
}
else if (typeof(TSource) == typeof(int))
{
int[] srcArray = Unsafe.As<int[]>(source.Array);
Marshal.Copy(srcArray, source.Offset, destination.PointerAtOffset, count);
return true;
}
else if (typeof(TSource) == typeof(uint))
{
int[] srcArray = Unsafe.As<int[]>(source.Array);
Marshal.Copy(srcArray, source.Offset, destination.PointerAtOffset, count);
return true;
}
else if (typeof(TSource) == typeof(short))
{
short[] srcArray = Unsafe.As<short[]>(source.Array);
Marshal.Copy(srcArray, source.Offset, destination.PointerAtOffset, count);
return true;
}
else if (typeof(TSource) == typeof(ushort))
{
short[] srcArray = Unsafe.As<short[]>(source.Array);
Marshal.Copy(srcArray, source.Offset, destination.PointerAtOffset, count);
return true;
}
else if (typeof(TSource) == typeof(byte))
{
byte[] srcArray = Unsafe.As<byte[]>(source.Array);
Marshal.Copy(srcArray, source.Offset, destination.PointerAtOffset, count);
return true;
}
return false;
}
}
}
Loading…
Cancel
Save