Reputation: 2552
For a time-critical algorithm, I have an array of struct and need to access multiple fields of one array item like this:
struct MyStruct
{
public int a, b, c;
}
MyStruct[] MyArray = new MyStruct[5];
int Test(int id)
{
return MyArray[id].a + MyArray[id].b + MyArray[id].c;
}
Is this already optimized by the compiler, so that it cannot be made faster?
Even if it is, it is not very readable.
It would become more readable like this:
int Test(int id)
{
var item = MyArray[id];
return item.a + item.b + item.c;
}
However, since it is a struct, it would be copied, correct? That's bad.
I could do this and hope it is inlined:
int Test(ref MyStruct item)
{
return item.a + item.b + item.c;
}
int Test(int id)
{
return Test(ref MyArray[id]);
}
The next idea is to use unsafe pointers, then I could do
//fixed statement, forgot syntax
return item->a + item->b + item->c;
Any suggestions? How to do it poperly?
Other languages have a with
block, as far as I remember - something like this - isn't it nice (in this case - better no discussion about this)?
with MyArray[id] do
return a + b + c;
Upvotes: 2
Views: 121
Reputation: 171178
The best way to learn this is to look at the disassembly. I recommend that you do that for all the variants that you can think of. That way you will gain experience what the JIT tends to get right and what it does not.
To get you started:
The CLI knows a concept called managed pointers. When you say array[i].x
this often is compiled as an access through a managed pointer. That's why array[i].x
often does not load array[i]
on the evaluation stack! It only loads and copies x
.
The C# language shields you very well from the fact that a lot of safe, managed code runs on GC-enabled pointers.
var item = MyArray[id];
return item.a + item.b + item.c;
This will in practice copy the struct. This is a JIT quality issue. It could be optimized but is not as of .NET 4.6.2.
int Test(ref MyStruct item)
ref
is a managed pointer. This is equivalent to the other managed pointer version. Maybe the JIT fails to inline this, I don't know.
Using an unsafe pointer would in theory achieve non-copying semantics as well but the JIT has (according to my limited testing) trouble applying certain optimizations to such code. I have seen the safe code version being faster because of that.
My prediction is that return MyArray[id].a + MyArray[id].b + MyArray[id].c;
is fastest. It's safe and rather clean.
Upvotes: 1
Reputation: 205569
One of the principles of OOP is to encapsulate the operations that purely rely on the object state as instance methods. There is absolutely no reason to not applying such rule to struct
s.
The following is both readable and optimal:
struct MyStruct
{
public int a, b, c;
public int SumABC() { return a + b + c; }
}
int Test(int id)
{
return MyArray[id].SumABC();
}
Upvotes: 1
Reputation: 46323
"For a time-critical algorithm" all your code style variants are irrelevant - the only critical consideration is time. You'd do good if you could first optimize the logic and reduce big-O time complexity (either average or worst), then optimize implementation performance, and only if you have a stalemate between several implementations choose the one that has the cleanest code.
In order to get to the most optimized implementation, consider using low level code ("unsafe code") and profile all your ideas till you know what works best.
Upvotes: 2