How to pass/access a pointer to an index of an array? - c#

In C / Objective-C when I have a lot of data in an array of structs and I need to do repeatable things with various indexes of the array I could pass the address of the index and access members using ->. Say to simplify things say I have this struct.
typedef struct _Particle {
float x;
float y;
float z;
int somethingCool;
} Particle;
Particle particles[100];
I had a function/method like this:
-(void) resetParticle: (Particle *) thisParticle {
thisParticle->x = 0;
thisParticle->y = 0;
thisParticle->z = 0;
thisParticle->somethingCool = 1234;
}
Then I could call it like this:
[self resetParticle:& particles[20]];
How do I replicate this in C#? I want to know how to do it with array of structs for particle systems.
But also in C# I'm using Vector3[] arrays for procedural meshes (Unity), which I think is an object and not a struct. I keep having to type the same code over and over to build quads. Seems like it should go in a method, but I don't want to copy data all over the place times several thousand indexes per frame.

Related

How to copy an array of floats from c# to a C dll

I'm trying to copy an array of floats from my C# application to an array in a C-coded DLL.
Im used to programming in C#, not so much with C. However I have no problem doing the reverse procedure ie. reading an array of floats from a C coded DLL into my C# application. I've read several threads on this site but cant work out where Im going wrong.
C# CODE
[DllImport(#"MyDll")]
static extern int CopyArray(double[] MyArray);
double[] myValues = new double[100]
int a = 0;
while(a < 100)
{
myValues[a] = a;
a++;
}
CopyArray(myValues);
C++ DLL
This is the function header;
__declspec(dllexport) int CopyArray(float* Wavelengths);
This is the function code;
float theValues[100];
int CopyArray(float* theArray)
{
status = 0;
int count = 0;
while (count < 100)
{
theValues[count] = theArray[count];
++count;
}
return(status);
}
I'm expecting my C# array to end up in the C array "theValues" but that's not happening. There is nothing getting into "theValues" array.
A couple of things.
You are mixing data types and they are different lengths (float is 32bit and double is 64bit). Both types exist in both languages, but your caller and callee need to agree on the data type. Here is a list of data types and their managed/unmanaged equivalents.
The parameter you are sending is not a pointer. It might be translated to that automatically by the compiler, but there are several options. It is entirely possible that the compiler will pick one you don't want (more info here). The one you are probably looking for is [In]. If you want to get data back from C to C#, you will also want [Out]:
[DllImport(#"MyDll")]
static extern int CopyArray([In, Out]double[] MyArray);

Is it possible to do fast unchecked cast of structs in C#?

Suppose you have two structs that have exactly the same memory layout. Is it possible to do a very fast unchecked memory cast from one to the other in C#/.NET?
//my code base
[StructLayout(LayoutKind.Sequential)]
public struct VectorA
{
float x;
float y;
float z;
}
//defined by a third party library
[StructLayout(LayoutKind.Sequential)]
public struct VectorB
{
float a;
float b;
float c;
}
//somewhere else in my code
var vectorA = new VectorA();
//then calling a method from the library
MethodFromThirdPartyLibrary((VectorB)vectorA); //compiler error
Of course it should be faster as a method that assigns the data fields and creates a new copy in memory.
Also: The 3d vector is only an example, same problem for matrices which is 16 floats and Vector2, Vector4, ...
EDIT: Improved code with more comments and better usage example.
Why would it be faster? Would it be faster in C++ than writing the copy explicitly as in C#? Remember, you only have 3 x 32-bit numbers you want to copy from one place to another, so it's not exactly a good fit for vectorization.
It's likely if you had an array of these structures that you could get some speed up using vectorized load/stores in an unrolled loop in assembler. But you've not stated that in the question.
The main overhead here is probably the method call, rather than the assignment:
static void VecAToB(ref VectorA vectorA, ref VectorB vectorB)
{
vectorB.x = vectorA.a;
vectorB.y = vectorA.b;
vectorB.z = vectorA.c;
}
You might like to try:
[MethodImpl(MethodImplOptions.AggressiveInlining)]
static void VecAToB(ref VectorA vectorA, ref VectorB vectorB)
{
vectorB.x = vectorA.a;
vectorB.y = vectorA.b;
vectorB.z = vectorA.c;
}

Serializing a dictionary in C#

I have a class named serializableVector2:
[Serializable]
class serializableVector2
{
public float x, y;
public serializableVector2(int x, int y)
{
this.x = x;
this.y = y;
}
}
and I have a struct named savedMapTile:
[Serializable]
struct savedMapTile
{
public oreInstance ore;
public int backgroundTileId;
public int playerId;
public tree tree;
}
and I have a dictionary using these two classes:
[SerializeField]
Dictionary<serializableVector2, savedMapTile> savedTiles;
I am trying to load this dictionary modify it, and then save it again all using serialization.
I am deserializing the dictionary like so:
FileStream f = File.Open(saveFileName, FileMode.Open);
BinaryFormatter b = new BinaryFormatter();
savedTiles = (Dictionary<serializableVector2, savedMapTile>)b.Deserialize(f);
f.Close();
and I am serializing it like so:
FileStream f = File.Open(saveFileName, FileMode.Create);
BinaryFormatter b = new BinaryFormatter();
b.Serialize(f, savedTiles);
f.Close();
However, when I try to access an element in the dictionary that I know should exist I get the following error:
System.Collections.Generic.KeyNotFoundException: The given key was not
present in the dictionary.
I get this error from running this code:
id = (savedTiles[new serializableVector2(-19,13)].backgroundTileId);
What I find really strange is that I am able to print out the entirety of the dictionaries keys and its values as well. This is where I am getting the values -19 and 13 for the Vector2. I print the keys and values like so:
for (int i = 0; i < 100; i++ )
{
UnityEngine.Debug.Log(vv[i].x +" "+vv[i].y);
UnityEngine.Debug.Log(x[i].backgroundTileId);
}
At this point I'm really stumped, I have no clue what is going on. I can see the file being saved in windows explorer, I can access keys and values in the dictionary, but I cant seem to use it properly. It is also important to note that when I use the .Contains() method on the dictionary in a similar way to how I am trying to access a value, it always returns false.
This is for a Unity 5 project, using C# in visual studio running on windows 8.1.
Change your serializableVector2 from a class to a struct and you should be able to find things in your dictionary. Someone may correct me if I have this wrong, but to the best of my knowledge the Dictionary is going to call GetHashCode on the key and use that code to store the item in the dictionary. If you create two instances of your class with the same x and y coordinates and call GetHashCode you will see that two instances yield different hash codes. If you change it to a struct than they will produce the same hash code. I believe this is what is causing you to get the "Key not found" issues. On a somewhat related note, it does seem strange that the constructor takes int for the x and y and then stores them as floats. You may want to consider changing the constructor to take float.
[Serializable]
struct serializableVector2
{
public float x, y;
public serializableVector2(float x, float y)
{
this.x = x;
this.y = y;
}
}
You have two issues:
Your dictionary key serializableVector2 is a class relying on the default equality and hashing methods. The defaults use reference equality such that only variables pointing to the same object will be equal and return the same hash.
If that were not the case you would still be relying on floating point equality. Unless your serialised can guarantee precise storage and retrieval of floating point values the deserialised serializableVector2 may NOT be equal to the original.
Suggested solution:
Override GetHashCode and Equals for your serializableVector2 class. When performing comparisons and hashing round your floats to within 32-bit floating point precision of your expected range of values. You can rely on 6+ significant digits of precision (within the same range) so if your world is += 1000 units I believe you can safely round to 3 decimal points.
Example for GetHashCode (without testing):
public override int GetHashCode() {
return Math.Round(x,3).GetHashCode() ^ Math.Round(y,3).GetHashCode();
}

converting type double[][] to float

I have a function signature like:
static public double[][] G2Sweep(int row1, int row2, double[][] mtx)
{
mtx = (float) mtx;
}
But I need to covert the double[][] matrix into float values. How is this done as the code can't explicitly convert it?
public static float[][] Convert(double[][] mtx)
{
var floatMtx = new float[mtx.Length][];
for (int i = 0; i < mtx.Length; i++)
{
floatMtx[i] = new float[mtx[i].Length];
for (int j = 0; j < mtx[i].Length; j++)
floatMtx[i][j] = (float)mtx[i][j];
}
return floatMtx;
}
Or:
public static float[][] Convert(double[][] mtx)
{
return mtx.Select(i => i.Select(j => (float)j).ToArray()).ToArray();
}
No, you can't convert double to float in place, especially for arrays. You need to create copy with correct type.
Another way you can do this by is using the Array.ConvertAll method:
Array.ConvertAll<double, float>(doubles, d => (float)d);
Does the same looping and explicit converting, but looks better.
yes all values to float, but i'd prefer not having to do a for loop to lop through it all
Well, sorry, but you can't. Casting an array to a type like float (or int, or String, or MonkeyPoo, or whatever) makes no sense. If you need to look at every value in an array then you need a loop. There is no getting around that fact.
Lamdas and whatnot all boil down to a loop as well. You'll just need to bite the bullet and either A) Convert in a loop (or use something like .Cast<float>), or use the correct type to begin with.
It's true that you cant convert in place and that you have to loop through the values.
However, it's fair* to say nowadays that memory is cheap.
At the point of creating your double[][] variable; why not simply also create a float[][] at the same time, so the conversion is done one, in place.
that way in the rest of your lifecycle, you can just use the write array for the write task.
That said, can you clarify why you need a distinct float and double array ?
*Fair but not necessarily acceptable; if it's a webapp hosted on its own box or virtual image; then it's fine. If this is a standalone app that might have to work on a netbook or in Silverlight somewhere, it is not fair or fine.
You can avoid writing the loop by hand if you use Linq.
float[][] floats = mtx.Select(r=>r.Select(Convert.ToSingle).ToArray()).ToArray();
EDIT: fixed.

Return list of points (x,y,z) from C to C# using PInvoke

I need to return a list of points i have from a C dll to a C# application using PInvoke. These are points in 3 dimensions [x,y,z]. The number of points varies by what kind of model it is. In C i handle this a linked list of structs. But I don't see how i can pass this on to C#.
The way I see it, I have to return a flexible two dimensional array, probably in a struct.
Any suggestions to how this can be done? Both ideas on how to return it in C and how to access it in C# are highly appreciated.
A linked list of structs could be passed back, but it would be quite a hassle to deal with, as you would have to write code to loop through the pointers, reading and copying the data from native memory into managed memory space. I would recommend a simple array of structs instead.
If you have a C struct like the following (assuming 32-bit ints)...
struct Point
{
int x;
int y;
int z;
}
... then you'd represent it nearly the same way in C#:
[StructLayout(LayoutKind.Sequential]
struct Point
{
public int x;
public int y;
public int z;
}
Now to pass an array back, it would be easiest to have your native code allocate the array and pass it back as a pointer, along with another pointer specifying the size in elements.
Your C prototype might look like this:
// Return value would represent an error code
// (in case something goes wrong or the caller
// passes some invalid pointer, e.g. a NULL).
// Caller must pass in a valid pointer-to-pointer to
// capture the array and a pointer to capture the size
// in elements.
int GetPoints(Point ** array, int * arraySizeInElements);
The P/Invoke declaration would then be this:
[DllImport("YourLib.dll")]
static extern int GetPoints(
[MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 1)] out Point[] array,
out int arraySizeInElements);
The MarshalAs attribute specifies that the array should be marshaled using the size specified in the second parameter (you can read more about this at MSDN, "Default Marshaling for Arrays").
If you use this approach, note that you must use CoTaskMemAlloc to allocate the native buffer as this is what the .NET marshaler expects. Otherwise, you will get memory leaks and/or other errors in your application.
Here is a snippet from the simple example I compiled while verifying my answer:
struct Point
{
int x;
int y;
int z;
};
extern "C"
int GetPoints(Point ** array, int * arraySizeInElements)
{
// Always return 3 items for this simple example.
*arraySizeInElements = 3;
// MUST use CoTaskMemAlloc to allocate (from ole32.dll)
int bytesToAlloc = sizeof(Point) * (*arraySizeInElements);
Point * a = static_cast<Point *>(CoTaskMemAlloc(bytesToAlloc));
*array = a;
Point p1 = { 1, 2, 3 };
a[0] = p1;
Point p2 = { 4, 5, 6 };
a[1] = p2;
Point p3 = { 7, 8, 9 };
a[2] = p3;
return 0;
}
The managed caller can then deal with the data very simply (in this example, I put all the interop code inside a static class called NativeMethods):
NativeMethods.Point[] points;
int size;
int result = NativeMethods.GetPoints(out points, out size);
if (result == 0)
{
Console.WriteLine("{0} points returned.", size);
foreach (NativeMethods.Point point in points)
{
Console.WriteLine("({0}, {1}, {2})", point.x, point.y, point.z);
}
}

Categories