Copy 2d array of structs to byte[] - c#

I have something like that:
[StructLayout(LayoutKind.Explicit)]
public struct PixelColorRGBA
{
[FieldOffset(0)]
public UInt32 ColorBGRA;
[FieldOffset(0)]
public byte Blue;
[FieldOffset(1)]
public byte Green;
[FieldOffset(2)]
public byte Red;
[FieldOffset(3)]
public byte Alpha;
}
What is the fastest way to copy PixelColorRGBA[w, h] to byte[w * h * 4] and vise versa?

I end up with the following code:
var source = new PixelColorRGBA[1000, 1000];
var destination = new byte[4000000];
{
var start = DateTime.Now;
unsafe
{
for (var q = 0; q < 100; q++)
fixed (PixelColorRGBA* tmpSourcePtr = &source[0, 0])
{
var sourcePtr = (IntPtr) tmpSourcePtr;
Marshal.Copy(sourcePtr, destination, 0, 4000000);
}
}
Console.WriteLine("MS: " + DateTime.Now.Subtract(start).TotalMilliseconds);
}
It takes 62 ms on my computer.

Try the following
PixelColorRGBA[,] source = ...;
byte[] dest = source
.Cast<PixelColorRGBA>()
.SelectMany(x => new byte[] { x.Blue, x.Green, x.Red, x.Alpha })
.ToArray();

You can use
System.Buffer.BlockCopy(myArray, 0, byteArray, 0, length)
or
System.Runtime.InteropServices.Marshal.Copy(myArray, 0, destPtr, length);

Related

C#/Flatbuffers - How to make a ByteBuffer into byte[] and prefix it with ushort

So basically here is how I do it with C++:
enum ServerOpcode : uint16_t{
SERVER_AUTH_CONNECTION_RESPONSE = 0x001,
SERVER_LOGIN_REQUEST_RESPONSE = 0x002,
SERVER_NUM_MSG_TYPES = 0x003,
};
uint8_t* Vibranium::Packet::PreparePacket(ServerOpcode& serverOpcode, flatbuffers::FlatBufferBuilder& builder) {
size_t size = builder.GetSize();
uint8_t *buf = builder.GetBufferPointer();
uint8_t *actualBuffer = new uint8_t[size + 2];
actualBuffer[1] = (serverOpcode >> 8);
actualBuffer[0] = (serverOpcode&0xFF);
memcpy(actualBuffer + 2, buf, size);
return actualBuffer;
}
I know that uint16_t is exactly 2 bytes and that is why i add +2.
Can someone give example in C# of how can I cast the ByteBuffer to byte[] and than prefix it with:
public enum ServerOpcode : ushort
{
SERVER_AUTH_CONNECTION_RESPONSE = 0x001,
SERVER_LOGIN_REQUEST_RESPONSE = 0x002,
SERVER_NUM_MSG_TYPES = 0x003,
}
In C# I found out that the equivalent of uint16_t is ushort.
So my question is how can I convert ByteBuffer into byte[] and prefix it with ushort?
Can anyone make an answer showing and equivalent of PreparePacket in C# ?
P.S.
Note that I am familiar with the file_identifier but I would like to do that manually. Hope someone can provide an example in C#
Following is the solution:
public static Byte[] PrependServerOpcode(ByteBuffer byteBuffer, ServerOpcode code)
{
var originalArray = byteBuffer.ToArray(0, byteBuffer.Length);
byte[] buffer = new byte[originalArray.Length + 2];
buffer[0] = (byte)((ushort)code / 0x0100);
buffer[1] = (byte)code;
Array.Copy(originalArray, 0, buffer, 2, originalArray.Length);
return buffer;
}
public enum ServerOpcode : ushort
{
SERVER_AUTH_CONNECTION_RESPONSE = 0x001,
SERVER_LOGIN_REQUEST_RESPONSE = 0x002,
SERVER_NUM_MSG_TYPES = 0x003
}
Or alternative:
public static ByteBuffer PrependServerOpcode(ByteBuffer byteBuffer, ServerOpcode code)
{
var originalArray = byteBuffer.ToArray(0, byteBuffer.Length);
byte[] buffer = new byte[originalArray.Length + 2];
buffer[0] = (byte)((ushort)code / 0x0100);
buffer[1] = (byte)code;
Array.Copy(originalArray, 0, buffer, 2, originalArray.Length);
return new ByteBuffer(buffer);
}
Usage:
static void Main(string[] args)
{
var bb = new ByteBuffer(new byte[] { 0x01 });
var result = PrependServerOpcode(bb, ServerOpcode.SERVER_NUM_MSG_TYPES);
}

Convert Guid to 2 longs and 2 longs to Guid in c#

Guid is a 128bits structure, long is a Int64 so 64 bits structure, therefore Guid can be used to represent two long and two long can be stored in a Guid.
I have been searching several times for a reliable way to perform the transformation of a Guid to 2 longs and the way around, mainly to get a simple way to provide a tracking id to external services.
The objective is to get a reversable way to pass in a single parameter 2 longs, and decode it back later (of course it is not intended to be used "decoded" on the other side). It is like a session id for the external service.
Warning: these solutions do not take endianness into consideration, and the result may therefore differ from one platform to another
Taking advantage of new features of C# 7, I came out with the following tools class, which transforms long, ulong, int, uint to Guid and reverse:
public static class GuidTools
{
public static Guid GuidFromLongs(long a, long b)
{
byte[] guidData = new byte[16];
Array.Copy(BitConverter.GetBytes(a), guidData, 8);
Array.Copy(BitConverter.GetBytes(b), 0, guidData, 8, 8);
return new Guid(guidData);
}
public static (long, long) ToLongs(this Guid guid)
{
var bytes = guid.ToByteArray();
var long1 = BitConverter.ToInt64(bytes, 0);
var long2 = BitConverter.ToInt64(bytes, 8);
return (long1, long2);
}
public static Guid GuidFromULongs(ulong a, ulong b)
{
byte[] guidData = new byte[16];
Array.Copy(BitConverter.GetBytes(a), guidData, 8);
Array.Copy(BitConverter.GetBytes(b), 0, guidData, 8, 8);
return new Guid(guidData);
}
public static (ulong, ulong) ToULongs(this Guid guid)
{
var bytes = guid.ToByteArray();
var ulong1 = BitConverter.ToUInt64(bytes, 0);
var ulong2 = BitConverter.ToUInt64(bytes, 8);
return (ulong1, ulong2);
}
public static Guid GuidFromInts(int a, int b, int c, int d)
{
byte[] guidData = new byte[16];
Array.Copy(BitConverter.GetBytes(a), guidData, 4);
Array.Copy(BitConverter.GetBytes(b), 0, guidData, 4, 4);
Array.Copy(BitConverter.GetBytes(c), 0, guidData, 8, 4);
Array.Copy(BitConverter.GetBytes(d), 0, guidData, 12, 4);
return new Guid(guidData);
}
public static (int, int , int, int) ToInts(this Guid guid)
{
var bytes = guid.ToByteArray();
var a = BitConverter.ToInt32(bytes, 0);
var b = BitConverter.ToInt32(bytes, 4);
var c = BitConverter.ToInt32(bytes, 8);
var d = BitConverter.ToInt32(bytes, 12);
return (a, b, c, d);
}
public static Guid GuidFromUInts(uint a, uint b, uint c, uint d)
{
byte[] guidData = new byte[16];
Array.Copy(BitConverter.GetBytes(a), guidData, 4);
Array.Copy(BitConverter.GetBytes(b), 0, guidData, 4, 4);
Array.Copy(BitConverter.GetBytes(c), 0, guidData, 8, 4);
Array.Copy(BitConverter.GetBytes(d), 0, guidData, 12, 4);
return new Guid(guidData);
}
public static (uint, uint, uint, uint) ToUInts(this Guid guid)
{
var bytes = guid.ToByteArray();
var a = BitConverter.ToUInt32(bytes, 0);
var b = BitConverter.ToUInt32(bytes, 4);
var c = BitConverter.ToUInt32(bytes, 8);
var d = BitConverter.ToUInt32(bytes, 12);
return (a, b, c, d);
}
}
Also found another solution inspired from there: Converting System.Decimal to System.Guid
[StructLayout(LayoutKind.Explicit)]
struct GuidConverter
{
[FieldOffset(0)]
public decimal Decimal;
[FieldOffset(0)]
public Guid Guid;
[FieldOffset(0)]
public long Long1;
[FieldOffset(8)]
public long Long2;
}
private static GuidConverter _converter;
public static (long, long) FastGuidToLongs(this Guid guid)
{
_converter.Guid = guid;
return (_converter.Long1, _converter.Long2);
}
public static Guid FastLongsToGuid(long a, long b)
{
_converter.Long1 = a;
_converter.Long2 = b;
return _converter.Guid;
}
As an unsafe but very efficient version (no byte[] allocations, via BitConverter):
static void Main()
{
var g = Guid.NewGuid();
Console.WriteLine(g);
GuidToInt64(g, out var x, out var y);
Console.WriteLine(x);
Console.WriteLine(y);
var g2 = GuidFromInt64(x, y);
Console.WriteLine(g2);
}
public static unsafe void GuidToInt64(Guid value, out long x, out long y)
{
long* ptr = (long*)&value;
x = *ptr++;
y = *ptr;
}
public static unsafe Guid GuidFromInt64(long x, long y)
{
long* ptr = stackalloc long[2];
ptr[0] = x;
ptr[1] = y;
return *(Guid*)ptr;
}
You could actually do the same thing with a union struct, if you don't like using the unsafe keyword, but: it is more code, and a union struct is still fundamentally unverifiable, so this doesn't gain you much at the IL level (it just means you don't need the "allow unsafe code" flag):
static void Main()
{
var g = Guid.NewGuid();
Console.WriteLine(g);
var val = new GuidInt64(g);
var x = val.X;
var y = val.Y;
Console.WriteLine(x);
Console.WriteLine(y);
var val2 = new GuidInt64(x, y);
var g2 = val2.Guid;
Console.WriteLine(g2);
}
[StructLayout(LayoutKind.Explicit)]
struct GuidInt64
{
[FieldOffset(0)]
private Guid _guid;
[FieldOffset(0)]
private long _x;
[FieldOffset(8)]
private long _y;
public Guid Guid => _guid;
public long X => _x;
public long Y => _y;
public GuidInt64(Guid guid)
{
_x = _y = 0; // to make the compiler happy
_guid = guid;
}
public GuidInt64(long x, long y)
{
_guid = Guid.Empty;// to make the compiler happy
_x = x;
_y = y;
}
}
Following pair of methods could do what you need:
public static void GuidToInt16(Guid guidToConvert, out long guidAsLong1, out long guidAsLong2)
{
byte[] guidByteArray = guidToConvert.ToByteArray();
var segment1 = new ArraySegment<byte>(guidByteArray, 0, 8);
var segment2 = new ArraySegment<byte>(guidByteArray, 8, 8);
guidAsLong1 = BitConverter.ToInt64(segment1.ToArray(), 0);
guidAsLong2 = BitConverter.ToInt64(segment2.ToArray(), 0);
}
public static Guid Int16ToGuid(long guidAsLong1, long guidAsLong2)
{
var segment1 = BitConverter.GetBytes(guidAsLong1);
var segment2 = BitConverter.GetBytes(guidAsLong2);
return new Guid(segment1.Concat(segment2).ToArray());
}
And possible usage:
Guid guidToConvert = new Guid("cbd5bb87-a249-49ac-8b06-87c124205b99");
long guidAsLong1, guidAsLong2;
GuidToInt16(guidToConvert, out guidAsLong1, out guidAsLong2);
Console.WriteLine(guidAsLong1 + " " + guidAsLong2);
Guid guidConvertedBack = Int16ToGuid(guidAsLong1, guidAsLong2);
Console.WriteLine(guidConvertedBack);
Console.ReadKey();
My solution should help understand whole process with binary operations:
class Program
{
public static Guid LongsToGuid(long l1, long l2)
{
var a = (int)l1;
var b = (short)(l1 >> 32);
var c = (short)(l1 >> 48);
var d = (byte)l2;
var e = (byte)(l2 >> 8);
var f = (byte)(l2 >> 16);
var g = (byte)(l2 >> 24);
var h = (byte)(l2 >> 32);
var i = (byte)(l2 >> 40);
var j = (byte)(l2 >> 48);
var k = (byte)(l2 >> 56);
return new Guid(a, b, c, d, e, f, g, h, i, j, k);
}
public static long BytesToLong(byte[] bytes, int start, int end)
{
long toReturn = 0;
for (var i = start; i < end; i++)
{
toReturn |= ((long)bytes[i]) << (8 * i);
}
return toReturn;
}
static void Main(string[] args)
{
var l1 = long.MinValue;
var l2 = long.MaxValue;
var guid = LongsToGuid(l1, l2);
var guidBytes = guid.ToByteArray();
var readL1 = BytesToLong(guidBytes, 0, 8);
var readL2 = BytesToLong(guidBytes, 8, 16);
Console.WriteLine(l1 == readL1);
Console.WriteLine(l2 == readL2);
Console.ReadKey();
}
}

create byte array from set of integers

Given these integers:
public uint ServerSequenceNumber;
public uint Reserved1;
public uint Reserved2;
public byte Reserved3;
public byte TotalPlayers;
What's the best way to create a byte[] array from them? If all their values are 1 the resulting array would be:
00000000000000000000000000000001 00000000000000000000000000000001 00000000000000000000000000000001 00000001 00000001
This should do what your looking for. BitConverter returns a byte array in the order of endianness of the processor being used. For x86 processors it is little-endian. This places the least significant byte first.
int value;
byte[] byte = BitConverter.GetBytes(value);
Array.Reverse(byte);
byte[] result = byte;
If you don't know the processor your going to be using the app on I suggest using:
int value;
byte[] bytes = BitConverter.GetBytes(value);
if (BitConverter.IsLittleEndian){
Array.Reverse(bytes);
}
byte[] result = bytes;
How's this?
byte[] bytes = new byte[14];
int i = 0;
foreach(uint num in new uint[]{SecureSequenceNumber, Reserved1, Reserved2})
{
bytes[i] = (byte)(num >> 24);
bytes[i + 1] = (byte)(num >> 16);
bytes[i + 2] = (byte)(num >> 8);
bytes[i + 3] = (byte)num;
i += 4;
}
bytes[12] = Reserved3;
bytes[13] = TotalPlayers;
Expanding on #Robert's answer I created a simple class that makes things neater when you're doing lots of concatanations:
class ByteJoiner
{
private int i;
public byte[] Bytes { get; private set; }
public ByteJoiner(int totalBytes)
{
i = 0;
Bytes = new byte[totalBytes];
}
public void Add(byte input)
{
Add(BitConverter.GetBytes(input));
}
public void Add(uint input)
{
Add(BitConverter.GetBytes(input));
}
public void Add(ushort input)
{
Add(BitConverter.GetBytes(input));
}
public void Add(byte[] input)
{
System.Buffer.BlockCopy(input, 0, Bytes, i, input.Length);
i += input.Length;
}
}

Read or convert to Int32 from TWO byte arrays

I have the 4 bytes that represent an integer stored in 2 separate byte arrays. I would like to convert these into an Int32 WITHOUT copying to a third byte array and reading that using memorystream.
The reason the data is split across two byte arrays is because this is a simplified example of my issue which involves huge amounts of data that cannot fit into a single bytearray.
Is there any way to achieve this? I do not wish to concatenate the two byte arrays into a thrid because of the performance implications which are critical to me.
Moon
You can use a struct layout like this
[StructLayout(LayoutKind.Explicit, Size=4)]
struct UnionInt32Value
{
[FieldOffset(0)] public byte byte1;
[FieldOffset(1)] public byte byte2;
[FieldOffset(2)] public byte byte3;
[FieldOffset(3)] public byte byte4;
[FieldOffset(0)] public Int32 iVal;
}
Assign your bytes in the correct order then read your Int32 from iVal;
EDIT: Sample code
using System;
using System.Runtime.InteropServices;
namespace Test
{
class Program
{
[StructLayout(LayoutKind.Explicit, Size=4)]
struct UnionInt32Value
{
[FieldOffset(0)] public byte byte1;
[FieldOffset(1)] public byte byte2;
[FieldOffset(2)] public byte byte3;
[FieldOffset(3)] public byte byte4;
[FieldOffset(0)] public Int32 iVal;
}
public static void Main(string[] args)
{
UnionInt32Value v = new UnionInt32Value();
v.byte1=1;
v.byte2=0;
v.byte3=0;
v.byte4=0;
Console.WriteLine("this is one " + v.iVal);
v.byte1=0xff;
v.byte2=0xff;
v.byte3=0xff;
v.byte4=0xff;
Console.WriteLine("this is minus one " + v.iVal);
Console.Write("Press any key to continue . . . ");
Console.ReadKey(true);
}
}
}
Something like this?
int x = (array1[index] << 16) + array2[index];
Of course, you didn't specify a language, but that's the gist of it.
The BitConverter class is intended for this:
byte[] parts = { byte1, byte2, byte3, byte4 };
int value = BitConverter.ToInt32(parts, 0);
You can use BitConverter twice, like:
byte[] bytes0 = new byte[] { 255, 255 };
byte[] bytes1 = new byte[] { 0, 0 };
int res = BitConverter.ToInt16(bytes0, 0) << 16;
res |= BitConverter.ToUInt16(bytes1, 0);
Which yields -65536 (0b11111111 11111111 00000000 00000000)
If your integer parts isn't at position 0 in the array, you just replace the 0 in ToUint16 to change the position.
Little extension method:
public static class BitConverterExt
{
public static int ToInt32(byte[] arr0, int index0, byte[] arr1, int index1)
{
int partRes = BitConverter.ToInt16(arr1, index1) << 16;
return partRes | BitConverter.ToUInt16(arr0, index0);
}
}
Usage:
byte[] bytes0 = new byte[] { 0x0, 0xA };
byte[] bytes1 = new byte[] { 0x64, 0xFF };
int res = BitConverterExt.ToInt32(bytes0, 0, bytes1, 0);
//Res -10221056 (0xFF640A00)
If I understand correctly, you are having a problem whilst reading across the boundary of the two arrays. If that is so, this routine will read an integer anywhere in the two arrays, even if it is across the two of them.
int ReadInteger(byte[] array1, byte[] array2, int offset)
{
if (offset < 0 || (offset + 4) > (array1.Length + array2.Length))
throw new ArgumentOutOfRangeException();
if (offset <= (array1.Length - 4))
return BitConverter.ToInt32(array1, offset);
else if (offset >= array1.Length)
return BitConverter.ToInt32(array2, offset - array1.Length);
else
{
var buffer = new byte[4];
var numFirst = array1.Length - offset;
Array.Copy(array1, offset, buffer, 0, numFirst);
Array.Copy(array2, 0, buffer, numFirst, 4 - numFirst);
return BitConverter.ToInt32(buffer, 0);
}
}
Note: depending on how your integers are stored, you might want to change the order in which bytes are copied.

C# unsafe value type array to byte array conversions

I use an extension method to convert float arrays into byte arrays:
public static unsafe byte[] ToByteArray(this float[] floatArray, int count)
{
int arrayLength = floatArray.Length > count ? count : floatArray.Length;
byte[] byteArray = new byte[4 * arrayLength];
fixed (float* floatPointer = floatArray)
{
fixed (byte* bytePointer = byteArray)
{
float* read = floatPointer;
float* write = (float*)bytePointer;
for (int i = 0; i < arrayLength; i++)
{
*write++ = *read++;
}
}
}
return byteArray;
}
I understand that an array is a pointer to memory associated with information on the type and number of elements. Also, it seems to me that there is no way of doing a conversion from and to a byte array without copying the data as above.
Have I understood this? Would it even be impossible to write IL to create an array from a pointer, type and length without copying data?
EDIT: Thanks for the answers, I learned some fundamentals and got to try out new tricks!
After initially accepting Davy Landman's answer I found out that while his brilliant StructLayout hack does convert byte arrays into float arrays, it does not work the other way around. To demonstrate:
[StructLayout(LayoutKind.Explicit)]
struct UnionArray
{
[FieldOffset(0)]
public Byte[] Bytes;
[FieldOffset(0)]
public float[] Floats;
}
static void Main(string[] args)
{
// From bytes to floats - works
byte[] bytes = { 0, 1, 2, 4, 8, 16, 32, 64 };
UnionArray arry = new UnionArray { Bytes = bytes };
for (int i = 0; i < arry.Bytes.Length / 4; i++)
Console.WriteLine(arry.Floats[i]);
// From floats to bytes - index out of range
float[] floats = { 0.1f, 0.2f, 0.3f };
arry = new UnionArray { Floats = floats };
for (int i = 0; i < arry.Floats.Length * 4; i++)
Console.WriteLine(arry.Bytes[i]);
}
It seems that the CLR sees both arrays as having the same length. If the struct is created from float data, the byte array's length is just too short.
You can use a really ugly hack to temporary change your array to byte[] using memory manipulation.
This is really fast and efficient as it doesn't require cloning the data and iterating on it.
I tested this hack in both 32 & 64 bit OS, so it should be portable.
The source + sample usage is maintained at https://gist.github.com/1050703 , but for your convenience I'll paste it here as well:
public static unsafe class FastArraySerializer
{
[StructLayout(LayoutKind.Explicit)]
private struct Union
{
[FieldOffset(0)] public byte[] bytes;
[FieldOffset(0)] public float[] floats;
}
[StructLayout(LayoutKind.Sequential, Pack = 1)]
private struct ArrayHeader
{
public UIntPtr type;
public UIntPtr length;
}
private static readonly UIntPtr BYTE_ARRAY_TYPE;
private static readonly UIntPtr FLOAT_ARRAY_TYPE;
static FastArraySerializer()
{
fixed (void* pBytes = new byte[1])
fixed (void* pFloats = new float[1])
{
BYTE_ARRAY_TYPE = getHeader(pBytes)->type;
FLOAT_ARRAY_TYPE = getHeader(pFloats)->type;
}
}
public static void AsByteArray(this float[] floats, Action<byte[]> action)
{
if (floats.handleNullOrEmptyArray(action))
return;
var union = new Union {floats = floats};
union.floats.toByteArray();
try
{
action(union.bytes);
}
finally
{
union.bytes.toFloatArray();
}
}
public static void AsFloatArray(this byte[] bytes, Action<float[]> action)
{
if (bytes.handleNullOrEmptyArray(action))
return;
var union = new Union {bytes = bytes};
union.bytes.toFloatArray();
try
{
action(union.floats);
}
finally
{
union.floats.toByteArray();
}
}
public static bool handleNullOrEmptyArray<TSrc,TDst>(this TSrc[] array, Action<TDst[]> action)
{
if (array == null)
{
action(null);
return true;
}
if (array.Length == 0)
{
action(new TDst[0]);
return true;
}
return false;
}
private static ArrayHeader* getHeader(void* pBytes)
{
return (ArrayHeader*)pBytes - 1;
}
private static void toFloatArray(this byte[] bytes)
{
fixed (void* pArray = bytes)
{
var pHeader = getHeader(pArray);
pHeader->type = FLOAT_ARRAY_TYPE;
pHeader->length = (UIntPtr)(bytes.Length / sizeof(float));
}
}
private static void toByteArray(this float[] floats)
{
fixed(void* pArray = floats)
{
var pHeader = getHeader(pArray);
pHeader->type = BYTE_ARRAY_TYPE;
pHeader->length = (UIntPtr)(floats.Length * sizeof(float));
}
}
}
And the usage is:
var floats = new float[] {0, 1, 0, 1};
floats.AsByteArray(bytes =>
{
foreach (var b in bytes)
{
Console.WriteLine(b);
}
});
Yes, the type information and data is in the same memory block, so that is impossible unless you overwrite the type information in a float array to fool the system that it's byte array. That would be a really ugly hack, and could easily blow up...
Here's how you can convert the floats without unsafe code if you like:
public static byte[] ToByteArray(this float[] floatArray) {
int len = floatArray.Length * 4;
byte[] byteArray = new byte[len];
int pos = 0;
foreach (float f in floatArray) {
byte[] data = BitConverter.GetBytes(f);
Array.Copy(data, 0, byteArray, pos, 4);
pos += 4;
}
return byteArray;
}
This question is the reverse of What is the fastest way to convert a float[] to a byte[]?.
I've answered with a union kind of hack to skip the whole copying of the data. You could easily reverse this (length = length *sizeof(Double).
I've written something similar for quick conversion between arrays. It's basically an ugly proof-of-concept more than a handsome solution. ;)
public static TDest[] ConvertArray<TSource, TDest>(TSource[] source)
where TSource : struct
where TDest : struct {
if (source == null)
throw new ArgumentNullException("source");
var sourceType = typeof(TSource);
var destType = typeof(TDest);
if (sourceType == typeof(char) || destType == typeof(char))
throw new NotSupportedException(
"Can not convert from/to a char array. Char is special " +
"in a somewhat unknown way (like enums can't be based on " +
"char either), and Marshal.SizeOf returns 1 even when the " +
"values held by a char can be above 255."
);
var sourceByteSize = Buffer.ByteLength(source);
var destTypeSize = Marshal.SizeOf(destType);
if (sourceByteSize % destTypeSize != 0)
throw new Exception(
"The source array is " + sourceByteSize + " bytes, which can " +
"not be transfered to chunks of " + destTypeSize + ", the size " +
"of type " + typeof(TDest).Name + ". Change destination type or " +
"pad the source array with additional values."
);
var destCount = sourceByteSize / destTypeSize;
var destArray = new TDest[destCount];
Buffer.BlockCopy(source, 0, destArray, 0, sourceByteSize);
return destArray;
}
}
public byte[] ToByteArray(object o)
{
int size = Marshal.SizeOf(o);
byte[] buffer = new byte[size];
IntPtr p = Marshal.AllocHGlobal(size);
try
{
Marshal.StructureToPtr(o, p, false);
Marshal.Copy(p, buffer, 0, size);
}
finally
{
Marshal.FreeHGlobal(p);
}
return buffer;
}
this may help you to convert an object to a byte array.
You should check my answer to a similar question: What is the fastest way to convert a float[] to a byte[]?.
In it you'll find portable code (32/64 bit compatible) to let you view a float array as a byte array or vice-versa, without copying the data. It's the fastest way that I know of to do such thing.
If you're just interested in the code, it's maintained at https://gist.github.com/1050703 .
Well - if you still interested in that hack - check out this modified code - it works like a charm and costs ~0 time, but it may not work in future since it's a hack allowing to gain full access to the whole process address space without trust requirements and unsafe marks.
[StructLayout(LayoutKind.Explicit)]
struct ArrayConvert
{
public static byte[] GetBytes(float[] floats)
{
ArrayConvert ar = new ArrayConvert();
ar.floats = floats;
ar.length.val = floats.Length * 4;
return ar.bytes;
}
public static float[] GetFloats(byte[] bytes)
{
ArrayConvert ar = new ArrayConvert();
ar.bytes = bytes;
ar.length.val = bytes.Length / 4;
return ar.floats;
}
public static byte[] GetTop4BytesFrom(object obj)
{
ArrayConvert ar = new ArrayConvert();
ar.obj = obj;
return new byte[]
{
ar.top4bytes.b0,
ar.top4bytes.b1,
ar.top4bytes.b2,
ar.top4bytes.b3
};
}
public static byte[] GetBytesFrom(object obj, int size)
{
ArrayConvert ar = new ArrayConvert();
ar.obj = obj;
ar.length.val = size;
return ar.bytes;
}
class ArrayLength
{
public int val;
}
class Top4Bytes
{
public byte b0;
public byte b1;
public byte b2;
public byte b3;
}
[FieldOffset(0)]
private Byte[] bytes;
[FieldOffset(0)]
private object obj;
[FieldOffset(0)]
private float[] floats;
[FieldOffset(0)]
private ArrayLength length;
[FieldOffset(0)]
private Top4Bytes top4bytes;
}

Categories