Efficiently convert between equivalent structs in C# - c#

I am communicating between two libraries which use equivalent structs. For example:
struct MyVector {
public float x, y, z;
}
struct TheirVector {
public float x, y, z;
}
Currently I am "casting" between these types by copying each of one's members into an instance of the other. Knowing how C# stores structs in memory, isn't there a much more efficient way of doing this with pointers?
Additionally, let's say I have two arrays of these equivalent structs:
MyVector[] array1; // (Length 1000)
TheirVector[] array2; // (Length 1000)
Isn't there a way to copy the whole block of memory from array1 into array2? Or even better, could I treat the entirety of array1 as of type array2 without creating a copy in memory?
I'm sure the answer requires pointers, but I have only used pointers in C++ and have no idea how C# implements them.
Does anyone have any examples on how to achieve something like this?
Thanks in advance!

Yes, if you're absolutely 100% sure that they have the same memory layout, you can coerce between them. The preferred way of doing this (to avoid too much unsafe / pointers) is: spans. For example:
var theirs = MemoryMarshal.Cast<MyVector, TheirVector>(array1);
This gives theirs as a Span<TheirVector>, without copying any of the actual data. Spans have a very similar API to arrays/vectors, so most things you expect to work: should work exactly as you expect. You simply have a typed reference to the same memory, using a different type.

Related

Marshaling fixed-size array of reference type as linear buffer in memory?

I'll try to sum up my initial problem before comes to the actual question of this topic just for a better understanding. If you dont want to read, ignore the summing up section and go straight for the second section when I actually explain the problem.
Suming up the problem
I'm emulating a MMORPG server of a game that already exists (just for study, I already know publishing that in any way is illegal) and I'm facing a lot of trouble when "translating" the raw packets buffer to some structure in code that I can use to avoid having to reference the data in the packets by its offsets in the buffer.
I have some background in reversing and C++. This problem is easily solved in C++ by doing the follow (consider 'packetBuffer' as a 'char*').
MyStructureType* packet = (MyStructureType*)&packetBuffer[0];
The problem starts in the fact that C# offer very much less freedom with user memory management. I can still use pointers, but there are a lot of things I can't do (eg. consider a struct X I use to represent the packet Y, if X have the need to declare a fixed-size array of another structure, even if all the types involved are blittable, I'm in trouble: C# just doesn't allow this). So the solution I took is make these packet structures as classes, format the layout of them (using attributes as StructLayout and MarshalAs) and then use the methods Marshal.PtrToStructure and Marshal.StructureToPtr to convert the raw buffer (byte[]) in some high-level representation and vice-versa. Now we come to my actual problem.
The Actual Question
Well, as stated above, I have POD classes that I use as a higher-level representation of packets data (byte[]). Imagine the packet represents a complex structure which have some nested custom structures. It's all fine until the point I have to declare a fixed size array, represented by a "marshalable" class. Consider I declare an array with 3 elements of the class X inside the class Y, I will end up with 3 references (pointers) to the actual data of X, not the 3 elements "hard-coded" in the buffer of Y. Some code to clarify bellow.
[StructLayout(LayoutKind.Sequential)]
class X
{
int i1;
int i2;
}
[StructLayout(LayoutKind.Sequential)]
class Y
{
X _x1;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 3)]
X[] _x2;
}
Instantiating Y, I will end up with an object which have 20 bytes instead of 32 (8 bytes for _x1 + 12 bytes for 3 pointers (4 bytes each) for each data for the three elements of_x2).
So, finally the question: how can I make _x2 be hard-coded in Y instead of storing the pointers?
Thanks.
You are right that there is a dumb restriction on using primitives in fixed size arrays. I have no idea why they don't just test for blittability.
Anyway, if you know you have 3 Foos in your fixed-size array, why don't you just create a wrapper struct that contains Foo1, Foo2, and Foo3 and make it a member of your struct?
BTW I advise against using classes for this kind of work. Use structs - it's what they're there for. Classes have two machine words of extra metadata in front.
struct Root
{
//fixed Leaf[] Leaves[3]; -- not allowed by C#
Leaf3 Leaves; //this is okay though, for some reason
}
struct Leaf
{
int x1;
int x2;
}
struct Leaf3
{
Leaf Leaf1;
Leaf Leaf2;
Leaf Leaf3;
}
First I would start by using a struct. Then I ask why _x2 can't be a struct as well. Something like this:
struct XArray
{
X _x1;
X _x2;
X _x3;
}
In C# you won't be able to use an indexer on the struct but you can still access the elements as needed.
You could try using a union. This is basically Structure Hack for C#, allowing you to access your Leafs by taking a Leaf* to &Leaf and then accessing it with array or pointer syntax as you please.
[StructLayout(LayoutKind.Explicit)]
unsafe struct Root
{
[FieldOffset(0)]
Leaf Leaf;
[FieldOffset(0)]
fixed byte packing[24]; //reserves size of three Leafs.
}
[StructLayout(LayoutKind.Sequential, Pack = 4)]
unsafe struct Leaf
{
int X1;
int X2;
}

Fast array copy in C#

I have a C# class that contains an int[] array (and a couple of other fields, but the array is the main thing). The code often creates copies of this class and profiling shows that the Array.Copy() call to copy this array takes a lot of time. What can I do to make it faster?
The array size is very small and constant: 12 elements. So ideally I'd like something like a C-style array: a single block of memory that's inside the class itself (not a pointer). Is this possible in C#? (I can use unsafe code if needed.)
I've already tried:
1) Using a UIn64 and bit-shifting instead of the array. (The values of each element are also very small.) This does make the copy fast, but slows down the program overall.
2) Using separate fields for each array element: int element0, int element1, int element2, etc. Again, this is slower overall when I have to access the element at a given index.
I would checkout the System.Buffer.BlockCopy if you are really concerned about speed.
http://msdn.microsoft.com/en-us/library/system.buffer.blockcopy.aspx
Simple Example:
int[] a = new int[] {1,2,3,4,5,6,7,8};
int[] b = new int[a.Length];
int size = sizeof(int);
int length = a.Length * size;
System.Buffer.BlockCopy(a, 0, b, 0, length);
Great discussion on it over here: Array.Copy vs Buffer.BlockCopy
This post is old, but anyone in a similar situation as the OP should have a look at fixed size buffers in structs. They are exactly what OP was asking for: an array of primitive types with a constant size stored directly in the class.
You can create a struct to represent your collection, which will contain the fixed size buffer. The data will be stored directly within the struct, which will be stored directly within your class. You can copy through simple assignment.
They come with a few caveats:
They can only be used with primitive types.
They require the "unsafe" keyword on your struct.
Size must be known at compile time.
It used to be that you had to use the fixed keyword and pointers to access them, but recent changes to C# catering to performance programming have made that unnecessary. You can now work with them just like arrays.
public unsafe struct MyIntContainer
{
private fixed int myIntegers[12];
public int this[int index]
{
get => this.myIntegers[index];
set => this.myIntegers[index] = value;
}
}
There is no built-in bound checking, so it would be best for you to include that yourself on such a property, encapsulating any functionality which skips bound checks inside of a method. I am on mobile, or I would have worked that into my example.
You asked about managed arrays. If you are content to use fixed / unsafe, this can be very fast.
struct is assignable, like any primitive. Almost certainly faster than Buffer.BlockCopy() or any other method, due to the lack of method call overhead:
public unsafe struct MyStruct //the actual struct used, contains all
{
public int a;
public unsafe fixed byte buffer[16];
public ulong b;
//etc.
}
public unsafe struct FixedSizeBufferWrapper //contains _only_ the buffer
{
public unsafe fixed byte buffer[16];
}
unsafe
{
fixed (byte* bufferA = myStructA.buffer, bufferB = myStructB.buffer)
{
*((FixedSizeBufferWrapper*)bufferA) =
*((FixedSizeBufferWrapper*)bufferB);
}
}
We cast fixed-size byte buffers from each of your original structs to the wrapper pointer type and dereference each pointer SO THAT we can assign one to the other by value; assigning fixed buffers directly is not possible, hence the wrapper, which is basically zero overhead (it just affects values used in pointer arithmetic that is done anyway). That wrapper is only ever used for casting.
We have to cast because (at least in my version of C#) we cannot assign anything other than a primitive type (usually byte[]) as the buffer, and we aren't allowed to cast inside fixed(...).
EDIT: This appears get translated into a call to Buffer.Memcpy() (specifically Buffer.memcpy4() in my case, in Unity / Mono) under the hood to do the copy.

How to calculate how big a struct or class is?

I've been told I should only use structs when they are less than 16 bytes. If bigger, it would be more optimal to use a class.
I was wondering, how do I work that out?
Do I just add up all of the fields that are in the struct?
For example, if this struct
public struct Struct1
{
int int1;
}
Then given it's got one integer and one int is 32 bits, is it then four bytes?
What about if I have lots of methods in this struct though? Would the method add to the size of the struct?
Only non-static variables use up space, methods don't. For example, your struct that you made there is four bytes big, because it is the size of an int.
You can also calculate the size using Marshal.SizeOf(GetType((Struct1)).
Unless you have memory critical applications, or have some special reasons you need a struct, I would suggest always using a class.
Use the built-in sizeof keyword.
EDIT: Nevermind, only available when dealing with unsafe code. (also, only really useful then too)
I would not solely think about the 16bytes limit when deciding whether to use a class or struct. I would look at the semantics first. If you need to create an entity, I would use a class. If you need to create a value type, I would first think of a struct.
Your best bet: When should I use a struct instead of a class?
MSDN has the answer: Choosing Between Classes and Structures. Do not define a structure unless the type has all of the following characteristics:
* It logically represents a single value, similar to primitive types (integer, double, and so on).
* It has an instance size smaller than 16 bytes.
* It is immutable.
* It will not have to be boxed frequently.
Make this analysis, and further, the decision, based on any such conclusion at design-time - not runtime, since you can't change the type definition at that point.
In order for you to work out the sizes, I'll just point you forward to a very interesting article (from 2005 MSDN magazine, but still relevant) which discusses the allocation of objects in the CLR, with reference to sizes, offsets et cetera; this will educate you more than enough to be able to determine what you need and also enable you to research further into what you're still unsure of:
http://msdn.microsoft.com/en-us/magazine/cc163791.aspx

What is the underlying reason for not being able to put arrays of pointers in unsafe structs in C#?

If one could put an array of pointers to child structs inside unsafe structs in C# like one could in C, constructing complex data structures without the overhead of having one object per node would be a lot easier and less of a time sink, as well as syntactically cleaner and much more readable.
Is there a deep architectural reason why fixed arrays inside unsafe structs are only allowed to be composed of "value types" and not pointers?
I assume only having explicitly named pointers inside structs must be a deliberate decision to weaken the language, but I can't find any documentation about why this is so, or the reasoning for not allowing pointer arrays inside structs, since I would assume the garbage collector shouldn't care what is going on in structs marked as unsafe.
Digital Mars' D handles structs and pointers elegantly in comparison, and I'm missing not being able to rapidly develop succinct data structures; by making references abstract in C# a lot of power seems to have been removed from the language, even though pointers are still there at least in a marketing sense.
Maybe I'm wrong to expect languages to become more powerful at representing complex data structures efficiently over time.
One very simple reason: dotNET has a compacting garbage collector. It moves things around. So even if you could create arrays like that, you would have to pin every allocated block and you would see the system slow down to a crawl.
But you are trying to optimize based on an assumption. Allocation and cleanup of objects in dotNET is highly optimized. So write a working program first and then use a profiler to find your bottlenecks. It will most likely not be the allocation of your objects.
Edit, to answer the latter part:
Maybe I'm wrong to expect languages to
become more powerful at representing
complex data structures efficiently
over time.
I think C# (or any managed language) is much more powerful at representing
complex data structures (efficiently). By changing from low level pointers to garbage collected references.
I'm just guessing, but it might have to do with different pointer sizes for different target platforms. It seems that the C# compiler is using the size of the elements directly for index calculations (i.e. there is no CLR support for calculating fixed sized buffers indices...)
Anyway you can use an array of ulongs and cast the pointers to it:
unsafe struct s1
{
public int a;
public int b;
}
unsafe struct s
{
public fixed ulong otherStruct[100];
}
unsafe void f() {
var S = new s();
var S1 = new s1();
S.otherStruct[4] = (ulong)&S1;
var S2 = (s1*)S.otherStruct[4];
}
Putting a fixed array of pointers in a struct would quickly make it a bad candidate for a struct. The recommended size limit for a struct is 16 bytes, so on a x64 system you would be able to fit only two pointers in the array, which is pretty pointless.
You should use classes for complex data structures, if you use structures they become very limited in their usage. You wouldn't for example be able to create a data structure in a method and return it, as it would then contain pointers to structs that no longer exists as they were allocated in the stack frame of the method.

C# Generic Arrays and math operations on it

I'm currently involved in a project where I have very large image volumes. This volumes have to processed very fast (adding, subtracting, thresholding, and so on). Additionally most of the volume are so large that they event don't fit into the memory of the system.
For that reason I have created an abstract volume class (VoxelVolume) that host the volume and image data and overloads the operators so that it's possible to perform the regular mathematical operations on volumes. Thereby two more questions opened up which I will put into stackoverflow into two additional threads.
Here is my first question. My volume is implemented in a way that it only can contain float array data, but most of the containing data is from an UInt16 image source. Only operations on the volume can create float array images.
When I started implementing such a volume the class looked like following:
public abstract class VoxelVolume<T>
{
...
}
but then I realized that overloading the operators or return values would get more complicated. An example would be:
public abstract class VoxelVolume<T>
{
...
public static VoxelVolume<T> Import<T>(param string[] files)
{
}
}
also adding two overloading operators would be more complicated:
...
public static VoxelVolume<T> operator+(VoxelVolume<T> A, VoxelVolume<T> B)
{
...
}
Let's assume I can overcome the problems described above, nevertheless I have different types of arrays that contain the image data. Since I have fixed my type in the volumes to float the is no problem and I can do an unsafe operation when adding the contents of two image volume arrays. I have read a few threads here and had a look around the web, but found no real good explanation of what to do when I want to add two arrays of different types in a fast way. Unfortunately every math operation on generics is not possible, since C# is not able to calculate the size of the underlying data type. Of course there might by a way around this problem by using C++/CLR, but currently everything I have done so far, runs in 32bit and 64bit without having to do a thing. Switching to C++/CLR seemed to me (pleased correct me if I'm wrong) that I'm bound to a certain platform (32bit) and I have to compile two assemblies when I let the application run on another platform (64bit). Is this true?
So asked shortly: How is it possible to add two arrays of two different types in a fast way. Is it true that the developers of C# haven't thought about this. Switching to a different language (C# -> C++) seems not to be an option.
I realize that simply performing this operation
float []A = new float[]{1,2,3};
byte []B = new byte[]{1,2,3};
float []C = A+B;
is not possible and unnecessary although it would be nice if it would work. My solution I was trying was following:
public static class ArrayExt
{
public static unsafe TResult[] Add<T1, T2, TResult>(T1 []A, T2 []B)
{
// Assume the length of both arrays is equal
TResult[] result = new TResult[A.Length];
GCHandle h1 = GCHandle.Alloc (A, Pinned);
GCHandle h2 = GCHandle.Alloc (B, Pinned);
GCHandle hR = GCHandle.Alloc (C, Pinned);
void *ptrA = h1.ToPointer();
void *ptrB = h2.ToPointer();
void *ptrR = hR.ToPointer();
for (int i=0; i<A.Length; i++)
{
*((TResult *)ptrR) = (TResult *)((T1)*ptrA + (T2)*ptrB));
}
h1.Free();
h2.Free();
hR.Free();
return result;
}
}
Please excuse if the code above is not quite correct, I wrote it without using an C# editor. Is such a solution a shown above thinkable? Please feel free to ask if I made a mistake or described some things incompletely.
Thanks for your help
Martin
This seems a (complicated) version of the "why don't we have an INumerical interface" .
The short answer to the last question is: No, going to unsafe pointers is no solution, the compiler still can't figure out the + in ((T1)*ptrA + (T2)*ptrB)) .
If you have only a few types like float and UInt32, provide all needed conversion functions, for example from VoxelVolume<UInt32> to VoxelVolume<float> and do the math on VoxelVolume<float>. That should be fast enough for most practical cases. You could even provide a generic conversion function from VoxelVolume<T1> to VoxelVolume<T2> (if T1 is convertible to T2). On the other hand, if you really need a
public static VoxelVolume<T2> operator+(VoxelVolume<T1> A,VoxelVolume<T2> B)
with type conversion from T1 to T2 for each array element, what hinders you from writing such operators?
Import, being a member of a generic class, probably doesn't also need to be itself generic. If it does, you definitely shouldn't use the same name T for both the generic parameter to the class and the generic parameter to the function.
What you're probably looking is Marc Gravell's Generic Operators
As for your questions about C++/CLI, yes this could help if you use templates instead of generics because then all the possible values for typename T are controlled at compile time and the compiler looks up the operators for each. Also, you can use /clr:pure or /clr:safe in which case your code will be MSIL, runnable on AnyCPU just like C#.
Admittedly, I didn't read the whole question (it's a quite a bit too long), but:
VoxelVolume<T> where T : ISummand ... T a; a.Add(b)
static float Sum (this VoxelVolume<float> self, VoxelVolume<float> other) {...}
To add float to byte in any meaningful sense you have to convert byte to float. So convert array of bytes to array of floats and then add them, you only lose some memory.

Categories

Resources