2015-08-26 07:17:56 -04:00
|
|
|
namespace System
|
|
|
|
{
|
|
|
|
partial class Buffer
|
|
|
|
{
|
|
|
|
public static int ByteLength (Array array)
|
|
|
|
{
|
|
|
|
// note: the other methods in this class also use ByteLength to test for
|
|
|
|
// null and non-primitive arguments as a side-effect.
|
|
|
|
|
|
|
|
if (array == null)
|
|
|
|
throw new ArgumentNullException ("array");
|
|
|
|
|
|
|
|
int length = _ByteLength (array);
|
|
|
|
if (length < 0)
|
|
|
|
throw new ArgumentException (Locale.GetText ("Object must be an array of primitives."));
|
|
|
|
|
|
|
|
return length;
|
|
|
|
}
|
|
|
|
|
|
|
|
public static byte GetByte (Array array, int index)
|
|
|
|
{
|
|
|
|
if (index < 0 || index >= ByteLength (array))
|
|
|
|
throw new ArgumentOutOfRangeException ("index");
|
|
|
|
|
|
|
|
return _GetByte (array, index);
|
|
|
|
}
|
|
|
|
|
|
|
|
public static void SetByte (Array array, int index, byte value)
|
|
|
|
{
|
|
|
|
if (index < 0 || index >= ByteLength (array))
|
|
|
|
throw new ArgumentOutOfRangeException ("index");
|
|
|
|
|
|
|
|
_SetByte (array, index, value);
|
|
|
|
}
|
|
|
|
|
|
|
|
public static void BlockCopy (Array src, int srcOffset, Array dst, int dstOffset, int count)
|
|
|
|
{
|
|
|
|
if (src == null)
|
|
|
|
throw new ArgumentNullException ("src");
|
|
|
|
|
|
|
|
if (dst == null)
|
|
|
|
throw new ArgumentNullException ("dst");
|
|
|
|
|
|
|
|
if (srcOffset < 0)
|
|
|
|
throw new ArgumentOutOfRangeException ("srcOffset", Locale.GetText(
|
|
|
|
"Non-negative number required."));
|
|
|
|
|
|
|
|
if (dstOffset < 0)
|
|
|
|
throw new ArgumentOutOfRangeException ("dstOffset", Locale.GetText (
|
|
|
|
"Non-negative number required."));
|
|
|
|
|
|
|
|
if (count < 0)
|
|
|
|
throw new ArgumentOutOfRangeException ("count", Locale.GetText (
|
|
|
|
"Non-negative number required."));
|
|
|
|
|
|
|
|
// We do the checks in unmanaged code for performance reasons
|
|
|
|
bool res = InternalBlockCopy (src, srcOffset, dst, dstOffset, count);
|
|
|
|
if (!res) {
|
|
|
|
// watch for integer overflow
|
|
|
|
if ((srcOffset > ByteLength (src) - count) || (dstOffset > ByteLength (dst) - count))
|
|
|
|
throw new ArgumentException (Locale.GetText (
|
|
|
|
"Offset and length were out of bounds for the array or count is greater than " +
|
|
|
|
"the number of elements from index to the end of the source collection."));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-02-22 11:00:01 -05:00
|
|
|
[CLSCompliantAttribute (false)]
|
|
|
|
public static unsafe void MemoryCopy (void* source, void* destination, long destinationSizeInBytes, long sourceBytesToCopy)
|
|
|
|
{
|
|
|
|
if (sourceBytesToCopy > destinationSizeInBytes) {
|
|
|
|
ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.sourceBytesToCopy);
|
|
|
|
}
|
|
|
|
|
|
|
|
var src = (byte*)source;
|
|
|
|
var dst = (byte*)destination;
|
|
|
|
while (sourceBytesToCopy > int.MaxValue) {
|
|
|
|
Memcpy (dst, src, int.MaxValue);
|
|
|
|
sourceBytesToCopy -= int.MaxValue;
|
|
|
|
src += int.MaxValue;
|
|
|
|
dst += int.MaxValue;
|
|
|
|
}
|
|
|
|
|
|
|
|
memcpy1 (dst, src, (int) sourceBytesToCopy);
|
|
|
|
}
|
|
|
|
|
|
|
|
[CLSCompliantAttribute (false)]
|
|
|
|
public static unsafe void MemoryCopy (void* source, void* destination, ulong destinationSizeInBytes, ulong sourceBytesToCopy)
|
|
|
|
{
|
|
|
|
if (sourceBytesToCopy > destinationSizeInBytes) {
|
|
|
|
ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.sourceBytesToCopy);
|
|
|
|
}
|
|
|
|
|
|
|
|
var src = (byte*)source;
|
|
|
|
var dst = (byte*)destination;
|
|
|
|
while (sourceBytesToCopy > int.MaxValue) {
|
|
|
|
Memcpy (dst, src, int.MaxValue);
|
|
|
|
sourceBytesToCopy -= int.MaxValue;
|
|
|
|
src += int.MaxValue;
|
|
|
|
dst += int.MaxValue;
|
|
|
|
}
|
|
|
|
|
|
|
|
Memcpy (dst, src, (int) sourceBytesToCopy);
|
|
|
|
}
|
|
|
|
|
2015-08-26 07:17:56 -04:00
|
|
|
internal static unsafe void memcpy4 (byte *dest, byte *src, int size) {
|
|
|
|
/*while (size >= 32) {
|
|
|
|
// using long is better than int and slower than double
|
|
|
|
// FIXME: enable this only on correct alignment or on platforms
|
|
|
|
// that can tolerate unaligned reads/writes of doubles
|
|
|
|
((double*)dest) [0] = ((double*)src) [0];
|
|
|
|
((double*)dest) [1] = ((double*)src) [1];
|
|
|
|
((double*)dest) [2] = ((double*)src) [2];
|
|
|
|
((double*)dest) [3] = ((double*)src) [3];
|
|
|
|
dest += 32;
|
|
|
|
src += 32;
|
|
|
|
size -= 32;
|
|
|
|
}*/
|
|
|
|
while (size >= 16) {
|
|
|
|
((int*)dest) [0] = ((int*)src) [0];
|
|
|
|
((int*)dest) [1] = ((int*)src) [1];
|
|
|
|
((int*)dest) [2] = ((int*)src) [2];
|
|
|
|
((int*)dest) [3] = ((int*)src) [3];
|
|
|
|
dest += 16;
|
|
|
|
src += 16;
|
|
|
|
size -= 16;
|
|
|
|
}
|
|
|
|
while (size >= 4) {
|
|
|
|
((int*)dest) [0] = ((int*)src) [0];
|
|
|
|
dest += 4;
|
|
|
|
src += 4;
|
|
|
|
size -= 4;
|
|
|
|
}
|
|
|
|
while (size > 0) {
|
|
|
|
((byte*)dest) [0] = ((byte*)src) [0];
|
|
|
|
dest += 1;
|
|
|
|
src += 1;
|
|
|
|
--size;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
internal static unsafe void memcpy2 (byte *dest, byte *src, int size) {
|
|
|
|
while (size >= 8) {
|
|
|
|
((short*)dest) [0] = ((short*)src) [0];
|
|
|
|
((short*)dest) [1] = ((short*)src) [1];
|
|
|
|
((short*)dest) [2] = ((short*)src) [2];
|
|
|
|
((short*)dest) [3] = ((short*)src) [3];
|
|
|
|
dest += 8;
|
|
|
|
src += 8;
|
|
|
|
size -= 8;
|
|
|
|
}
|
|
|
|
while (size >= 2) {
|
|
|
|
((short*)dest) [0] = ((short*)src) [0];
|
|
|
|
dest += 2;
|
|
|
|
src += 2;
|
|
|
|
size -= 2;
|
|
|
|
}
|
|
|
|
if (size > 0)
|
|
|
|
((byte*)dest) [0] = ((byte*)src) [0];
|
|
|
|
}
|
|
|
|
static unsafe void memcpy1 (byte *dest, byte *src, int size) {
|
|
|
|
while (size >= 8) {
|
|
|
|
((byte*)dest) [0] = ((byte*)src) [0];
|
|
|
|
((byte*)dest) [1] = ((byte*)src) [1];
|
|
|
|
((byte*)dest) [2] = ((byte*)src) [2];
|
|
|
|
((byte*)dest) [3] = ((byte*)src) [3];
|
|
|
|
((byte*)dest) [4] = ((byte*)src) [4];
|
|
|
|
((byte*)dest) [5] = ((byte*)src) [5];
|
|
|
|
((byte*)dest) [6] = ((byte*)src) [6];
|
|
|
|
((byte*)dest) [7] = ((byte*)src) [7];
|
|
|
|
dest += 8;
|
|
|
|
src += 8;
|
|
|
|
size -= 8;
|
|
|
|
}
|
|
|
|
while (size >= 2) {
|
|
|
|
((byte*)dest) [0] = ((byte*)src) [0];
|
|
|
|
((byte*)dest) [1] = ((byte*)src) [1];
|
|
|
|
dest += 2;
|
|
|
|
src += 2;
|
|
|
|
size -= 2;
|
|
|
|
}
|
|
|
|
if (size > 0)
|
|
|
|
((byte*)dest) [0] = ((byte*)src) [0];
|
|
|
|
}
|
|
|
|
|
|
|
|
internal static unsafe void Memcpy (byte *dest, byte *src, int size) {
|
|
|
|
// FIXME: if pointers are not aligned, try to align them
|
|
|
|
// so a faster routine can be used. Handle the case where
|
|
|
|
// the pointers can't be reduced to have the same alignment
|
|
|
|
// (just ignore the issue on x86?)
|
|
|
|
if ((((int)dest | (int)src) & 3) != 0) {
|
|
|
|
if (((int)dest & 1) != 0 && ((int)src & 1) != 0 && size >= 1) {
|
|
|
|
dest [0] = src [0];
|
|
|
|
++dest;
|
|
|
|
++src;
|
|
|
|
--size;
|
|
|
|
}
|
|
|
|
if (((int)dest & 2) != 0 && ((int)src & 2) != 0 && size >= 2) {
|
|
|
|
((short*)dest) [0] = ((short*)src) [0];
|
|
|
|
dest += 2;
|
|
|
|
src += 2;
|
|
|
|
size -= 2;
|
|
|
|
}
|
|
|
|
if ((((int)dest | (int)src) & 1) != 0) {
|
|
|
|
memcpy1 (dest, src, size);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
if ((((int)dest | (int)src) & 2) != 0) {
|
|
|
|
memcpy2 (dest, src, size);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
memcpy4 (dest, src, size);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|