unsafe method trouble rewriting it without /unsafe - c#

I have some code that was written in unsafe code.
can somebody help me convert it to normal managed code? I don't know how to do it because i don't understand what it's actually doing. Please educate me on what is happening in here.
public byte[] GetRowData(int row)
{
var buffer = new byte[Cols * 6];
unsafe
{
fixed (byte* lpData = buffer, lpTile = &Data[row * Cols * 6])
{
var lpD = lpData;
var lpT = lpTile;
for (var i = 0; i < Cols; i++, lpD += 6, lpT += 6)
{
lpD[0] = lpT[1];
lpD[1] = lpT[0];
lpD[2] = lpT[3];
lpD[3] = lpT[2];
lpD[4] = lpT[5];
lpD[5] = lpT[4];
}
}
}
return buffer;
}

Pointers. They are arguably the single most fundamental tool of coding. They are also arguably the single most dangerous tool of coding. I have worked with them, and they are like "juggling live handgrenades"
The .NET developers tried their best so you would not have to handle them. And indeed could not handle them by default. If you do need to handle them, you have to dip into unsafe code. unsafe is there to allow the use of that byte pointer byte*.
fixed is a hint for the GarbageCollector: "Do not move this from the memory location as part of your work. You would mess up my code."
Edit:
There is so much wrong and odd with the code, it needed a comment to even figure out what it is doing. So your confusion si expected I will try to explain it with comments:
/*The function signature. row is the only data he does not get from a global source. Because of course he get's half the input from global sources, otherwise it would not be hard enough to read!
It seems to do a combined copy and swap operation. And in batches of 6 elements, for some reason*/
public byte[] GetRowData(int row)
{
//He creates a managed array. It's size is a external value called "Cols" times 6. I hope that at least Cols is a constant, but I doubt it.
//This is also the output variable. Later known as lpData and lpD.
var buffer = new byte[Cols * 6];
//He enters unsafe code, to do his pointer shenanigans.
unsafe
{
//he gets a pointer to the start of the buffer (lpData)
//he gets a pointer to whatever is in "row * Cols * 6" of the global Data Collection. So this is the part where he actually retrieves the INPUT, based on the argument he gave this function.
//If Data[row * Cols * 6] is smaler then Cols * 6/buffer.lenght, he already fucked up.
//He also tells the GC to not optimize those around the memory space. He needs nobody else doing stuff in that area.
fixed (byte* lpData = buffer, lpTile = &Data[row * Cols * 6])
{
//Indexing in arrays with pointers is done with some Pointer Arythmetic: Start Pointer + Index times type width - that is the memory adress you write at.
//This is defintely the part where most people messed up with pointers. Also the only way to do it. And why the .NET Array will do this for you only after sanity checks on the index.
//He makes local copies of the pointers, becaus he will do some of the Arithmethic himself - but not all of it
var lpD = lpData;
var lpT = lpTile;
//A for loop. i is jsut your normal running variable to control how many itterations there will be.
//each itteration he will also count lpD and lpT up by 6, to get the next "batch" of elements.
for (var i = 0; i < Cols; i++, lpD += 6, lpT += 6)
{
//He processes the batch of 6 elements. He copies 6 element from input to output, while also swapping the odd and even elements.
//Mathwise those indexers work out to: Pointer of the array start + i*6 + stated index * element width
lpD[0] = lpT[1];
lpD[1] = lpT[0];
lpD[2] = lpT[3];
lpD[3] = lpT[2];
lpD[4] = lpT[5];
lpD[5] = lpT[4];
}
}
}
//We are back out of unsafe code, the pointers have all gone out of scope and he returns whatever he created there in input, from whatever was in Data[row * Cols * 6]
return buffer;
}
To figure out what this is supposed to do, I would need to know what the elements of Data look like.

The code you have provided is copying data from the memory address lpTile to lpData, that's pretty much it.
To convert it to code which doesn't use unsafe and fixed would be something like this, but only if Data is a byte array, else you will need to use unsafe to fix the object at the Data array's start index sins, say that the array is of type int, in the provided unsafe code the data which is being copied are bytes so, if you will want to do it to a int, you will either have to use unsafe or do shift right (>>) 0, 8, 16 & 24 and get the bytes that way for each int value which is retrieved from the Data array.
If the array is of a struct type which is more "complex" say something like the SYSTEMTIME struct, while it will be possible to get bytes for each field in the struct, it will more than likely give you a headache writing it all out.
This example will only work if Data is a byte array.
var buffer = new byte[Cols * 6];
int b_pos = 0;
int d_pos = (row * Cols * 6);
for (var i = 0; i < Cols; i++, b_pos += 6, d_pos += 6)
{
buffer[b_pos + 0] = Data[d_pos + 1];
buffer[b_pos + 1] = Data[d_pos + 0];
buffer[b_pos + 2] = Data[d_pos + 3];
buffer[b_pos + 3] = Data[d_pos + 2];
buffer[b_pos + 4] = Data[d_pos + 5];
buffer[b_pos + 5] = Data[d_pos + 4];
}
return buffer;
Note that using pointers and unsafe isn't bad, it's there for a reason so, if converting that code to something that isn't unsafe isn't a big issue, I would recommend keeping it that way rather than messing with it. Mind you that quite a bit of code in mscorlib.dll uses pointer, for example the ToCharArray function in the String class, while it may seam to be safe, actually its completely based on pointers and copying data from one memory address to another.
Update
After looking at the code, I realized that it's fixed byte* so the Data array is of type byte.
Here are 2 examples one using fixed and another not, with what is happening in each:
fixed Example:
public unsafe byte[] GetRowData(int row)
{
//The total length which will be used as buffer length, Data array start index multiple & for loop length
int totalLength = (Cols * 6);
//Allocates a byte array of size totalLength
var buffer = new byte[totalLength];
//Gets the memory address of the byte in Data at [row * totalLength]
//which, when moved forwards, leads to the next byte in the Data array i.e. at [(row * totalLength) + 1], because data in a array is sequential.
fixed (byte* dataptr = &Data[row * totalLength])
{
//Does a for loop with the end being totalLength and adding to "i" itself 6 instead of some external variables.
for (var i = 0; i < totalLength; i += 6)
{
//moves data from the fixed address "dataptr" to the byte array "buffer"
buffer[i] = dataptr[i + 1];
buffer[i + 1] = dataptr[i];
buffer[2] = dataptr[i + 3];
buffer[3] = dataptr[i + 2];
buffer[4] = dataptr[i + 5];
buffer[5] = dataptr[i + 4];
}
}
return buffer;
}
Example without fixed
public byte[] GetRowData(int row)
{
//Same as in the above example, the total length.
int totalLength = (Cols * 6);
//Same allocation of the buffer size of totalLength
var buffer = new byte[totalLength];
//The index at which to start moving data from the Data array
int dataStartIndex = (row * totalLength);
//The same for loop as in the above example
for (var i = 0; i < totalLength; i += 6)
{
//Moves data from the Data array at index [dataStartIndex + i + n] to the buffer array.
buffer[i] = Data[dataStartIndex + i + 1];
buffer[i + 1] = Data[dataStartIndex + i];
buffer[2] = Data[dataStartIndex + i + 3];
buffer[3] = Data[dataStartIndex + i + 2];
buffer[4] = Data[dataStartIndex + i + 5];
buffer[5] = Data[dataStartIndex + i + 4];
}
return buffer;
}
Mind you, what I said before about the Data array, if it were not of type byte is true, if it were not one then you would need to use fixed or find a way to get bytes from each variable retrieved from the array but, sins Data is a byte array all of the 3 examples above will work.

These are all array operations. They are walking the pointer through the array so they can use fixed offsets in each case.
Obviously I haven't tested this but my inclination:
for (int loop = 0; loop < Cols; loop++)
{
int Offset = loop * 6;
lpD[Offset + 0] = lpT[Offset + 1];
lpD[Offset + 1] = lpT[Offset + 0];
lpD[Offset + 2] = lpT[Offset + 3];
lpD[Offset + 3] = lpT[Offset + 2];
lpD[Offset + 4] = lpT[Offset + 5];
lpD[Offset + 5] = lpT[Offset + 4];
}
I can't convert the rest of this because we don't have the whole picture here. I'm sure the remaining pointers can be replaced by offsets into the array along the lines of what I did here.
I strongly suspect this is some matrix code that was originally written in C and someone did a minimal-effort port to C#.

Related

What is the most performant method for setting a subset of sequential items in a large array?

I am working with camera streams. I bring in 1,228,800 bytes per frame, so efficiency is crucial and nanoseconds per byte add up quickly.
I've come up with some example code below to describe the problem as succinctly as possible without seeming too contrived.
There are plenty of inefficiencies in this example code such as defining variables inside of loops, or dividing the brightness value instead of just using a composite value. These aren't my concern, and are just there to make the example simpler.
What I need advice on is the most performant method in C# for setting 3 sequential values at some determined location in a very large array, such as in the case below where I'm setting BGR to 255 while skipping the 4th byte.
Edit: To clarify, the concerning issue is where I'm reindexing Output for each index that is being set. It seems like there should potentially be some method for not traversing the entire array for each value if I already have the location of the previous item.
// Colors are stored as 4 bytes: BGRX where X is always 0
public byte[] Input = new byte[640 * 480 * 4];
public byte[] Output = new byte[640 * 480 * 4];
public int Threshold = 180;
public void ProcessImage() {
for (int i = 0; i < Input.Length; i += 4) {
var brightness = (Input[i] + Input[i + 1] + Input[i + 2]) / 3; // some value under 255
if (brightness > Threshold) {
// What is the most efficient way possible to do this?
Output[i] = 255 - Input[i];
Output[i + 1] = 255 - Input[i + 1];
Output[i + 2] = 255 - Input[i + 2];
}
else {
Output[i] = Input[i];
Output[i + 1] = Input[i + 1];
Output[i + 2] = Input[i + 2];
}
}
}
This (untested, and unsafe) code should be faster, if all you care about is speed:
public void ProcessImage()
{
int ilength = Input.Length;
Debug.Assert(ilength == Output.Length);
Debug.Assert(ilength%4 == 0);
unsafe
{
GCHandle pinned1 = GCHandle.Alloc(Input, GCHandleType.Pinned);
byte* input = (byte*)pinned1.AddrOfPinnedObject();
GCHandle pinned2 = GCHandle.Alloc(Input, GCHandleType.Pinned);
byte* output = (byte*)pinned2.AddrOfPinnedObject();
for (int i = 0; i < ilength; i += 4)
{
var brightness = (*(input) + *(input + 1) + *(input + 2)) / 3;
if (brightness > Threshold)
{
// What is the most efficient way possible to do this?
(*(output)) = (byte)(255 - *(input));
(*(output+1)) = (byte)(255 - *(input+1));
(*(output+2)) = (byte)(255 - *(input+2));
}
else
{
(*(output)) = *(input);
(*(output + 1)) = *(input + 1);
(*(output + 2)) = *(input + 2);
}
input += 4;
output += 4;
}
pinned1.Free();
pinned2.Free();
}
}
Note that I've incorporate the necessary assumptions at the top of the function. I'd suggest you always do this, but whether you prefer Debug.Assert or some other form of validation is up to you.
If you're happy to carry the 4th byte through, it would be quicker to copy Input to Output first with a block copy, then not to perform the else clause of the branch:
Buffer.BlockCopy(Input,0,Output,0,Input.Length);
for (int i = 0; i < Input.Length; i += 4) {
var brightness = (Input[i] + Input[i + 1] + Input[i + 2]) / 3;
if (brightness > Threshold) {
Output[i] = (byte)(255 - Input[i]);
Output[i + 1] = (byte)(255 - Input[i + 1]);
Output[i + 2] = (byte)(255 - Input[i + 2]);
}
}
In terms of the most performant way of setting a single value to multiple array indicies in c#, I think you're looking at it. There's no non-looping way to set the same value to multiple indicies. See How can I assign a value to multiple array indices at once without looping?
If it helps, there's no need for the else statement where you set the 3 indicies to 0. default(byte) is already zero, so every index in the Ouput[] array will initialize to 0.
As a side note, defining variables inside of loops vs outside of loops has no effect on the resulting IL. See Is it better to declare a variable inside or outside a loop?
EDIT: To add on to the comment above, you can use unsafe methods. See https://stackoverflow.com/a/5375552/3290789 and http://www.gutgames.com/post/Using-Unsafe-Code-for-Faster-Image-Manipulation.aspx

Displaying the values of a multidimensional array in a MessageBox

I am just now learning about multi-dimensional arrays and message boxes. I am currently have a issue in creating 2 columns in my message box. I can currently get it to print up the random numbers I need, but only in one column. Thanks for the help!
string msg = "";
Random numb = new Random();
int[,] thing = new int[ 10, 2 ];
thing[0, 0] = numb.Next(0,10);
thing[0, 1] = numb.Next(0,10);
thing[1, 0] = numb.Next(0,10);
thing[1, 1] = numb.Next(0,10);
thing[2, 0] = numb.Next(0,10);
thing[2, 1] = numb.Next(0,10);
thing[3, 0] = numb.Next(0,10);
thing[3, 1] = numb.Next(0,10);
thing[4, 0] = numb.Next(0,10);
thing[4, 1] = numb.Next(0,10);
thing[5, 0] = numb.Next(0,10);
thing[5, 1] = numb.Next(0,10);
thing[6, 0] = numb.Next(0,10);
thing[6, 1] = numb.Next(0,10);
thing[7, 0] = numb.Next(0,10);
thing[7, 1] = numb.Next(0,10);
thing[8, 0] = numb.Next(0,10);
thing[8, 1] = numb.Next(0,10);
thing[9, 0] = numb.Next(0,10);
thing[9, 1] = numb.Next(0,10);
foreach (int x in thing)
msg = msg + x + "\n";
MessageBox.Show(msg, "Table");
Change this:
foreach (int x in thing)
msg = msg + x + "\n";
MessageBox.Show(msg, "Table");
To :
for (int i = 0; i < thing.GetLength(0); i++)
msg += String.Format("{0} {1}\n", thing[i, 0], thing[i, 1]);
//msg += thing[i, 0] + " " + thing[i, 1] + "\n";
MessageBox.Show(msg, "Table");
Explanation:
Method GetLength(0) returns length of dimension for our x (it's basically like array.Length for simple array but with specific dimension) and we use i variable and for loop to iterate through it. In y we have only 2 elements so we can just use [0] and [1] indexes as we know there are only two elements there. This explains the line:
msg += thing[i, 0] + " " + thing[i, 1] + "\n";
Be careful with concatenating string like that, as if you don't add this space " " between your numbers compiler will just add them, so element like [33, 10] will be concatenated to string like : "43 \n" instead of "33 10 \n".
P.S.
So let's use String.Format method to make sure it's formatted well :
msg += String.Format("{0} {1}\n", thing[i, 0], thing[i, 1]);
I suspect that this question is a duplicate of an existing one, but I cannot find the appropriate precedent. So maybe we are in need of an answer explaining how to format a two-dimensional array for output. This is such an answer. :)
First thing to keep in mind is that the fact that you are displaying this using MessageBox is only barely relevant. What you are really asking is how to format a two-dimensional array as a string, where that string includes line-breaks between rows in your data, and the columns are lined up in the output. Once you have that string, you can display in any context that uses a fixed-space font (which is actually not the MessageBox…but it is not hard to create your own Form to use as a message box, where you can specify the font used to display the text) and have the output appear as you seem to be asking for.
For example, here's a console program that does what you want:
static void Main(string[] args)
{
StringBuilder sb = new StringBuilder();
Random random = new Random();
int[,] array = new int[10, 2];
for (int i = 0; i < array.GetLength(0); i++)
{
for (int j = 0; j < array.GetLength(1); j++)
{
array[i, j] = random.Next(10);
if (j > 0)
{
sb.Append(", ");
}
sb.Append(array[i, j]);
}
sb.AppendLine();
}
Console.WriteLine(sb);
}
Note that I have consolidated the initialization of the array and the formatting of the values into a single piece of code. I have also used nested for loops to index each individual element in the array; this allows two things:
To initialize the array using loops instead of explicitly writing out each element as you did in your example.
To make it easy to recognize the end of a row in the array so that a line-break can be added to the output.
In your example, your random numbers are only ever a single digit. But if you were to want to format numbers that could vary in their number of digits, you would want to pad the output with spaces for the shorter numbers, so that the numbers in the columns of your output lined up. You can do that by adding a width specifier to the output, like this:
sb.AppendFormat("{0,2}", array[i, j]);
In the above, rather than using the default formatting as the previous code example does, I am explicitly specifying a format (and calling AppendFormat() instead of Append() to do so), and in that explicit format, I have included the text ,2, to indicate that I want the output string to have a minimum width of two characters. The method will add spaces as necessary to ensure that.
I have also changed from simple string concatenation to the use of StringBuilder. In your original example, string concatenation is probably not horrible, but it's also not a good habit to get into. When you are repeatedly appending text in a loop, you should always use StringBuilder. Otherwise, an excessive number of objects may be created, and as well an excessive amount of time spent copying character data may be spent. Using StringBuilder allows the text to be concatenated more efficiently.

find checksum of a string in C# .net

Hi I want to find a checksum of single string. here are the requirements of checksum.
32 digit/8byte check sum represented in hexadecimal character.
It should be XOR of header + session + body + message.
Lets suppose header + session + body + message = "This is test string". I want to calculate the checksum of this. So far I have developed below code.
Checksum is calculated correctly if string length(byte[] data) is multiple of 4.
If "data" is not a multiple of 4 I receive exception as
"System.IndexOutOfRangeException: Index was outside the bounds of the array".
I will be taking different inputs having different string length from user and hence the string length will be variable(means some time user can enter only ABCDE some times q and A and so on.). How can I fix this exception issue and calculate correct checksum with multiple of 4.
public string findchecksum(string userinput)
try
{
ASCIIEncoding enc = new ASCIIEncoding();
byte[] data = Encoding.ASCII.GetBytes(userinput);
byte[] checksum = new byte[4];
for (int i = 16; i <= data.Length - 1; i += 4)
{
checksum[0] = (byte)(checksum[0] ^ data[i]);
checksum[1] = (byte)(checksum[1] ^ data[i + 1]);
checksum[2] = (byte)(checksum[2] ^ data[i + 2]);
checksum[3] = (byte)(checksum[3] ^ data[i + 3]);
}
int check = 0;
for (int i = 0; i <= 3; i++)
{
int r = (Convert.ToInt32(checksum[i]));
int c = (-(r + (1))) & (0xff);
c <<= (24 - (i * 8));
check = (check | c);
}
return check.ToString("X");
Because you use i+3 inside your loop, your array size has to always be divisible by 4. You should extend your data array to met that requirement before entering the loop:
byte[] data = Encoding.ASCII.GetBytes(cmd);
if (data.Length % 4 != 0)
{
var data2 = new byte[(data.Length / 4 + 1) * 4];
Array.Copy(data, data2, data.Length);
data = data2;
}

Search data from one array in another

What I'm trying to do is simple but it's just slooow. Basically I'm looping through data (byte array), converting some parts to a INT and then comparing it to RamCache with is also a byte array. The reason why I'm converting it to a INT is because it's 4 bytes so if 4 bytes are equal in some part of the RamCache array I know it's already 4 length equal.
And then from there I can see how many bytes are equal.
In short what this code must do:
Loop through the data array and take 4 bytes ,then look if it contains in the RamCache array. Currently the code below is slow when the data array and RamCache array contains 65535 bytes.
private unsafe SmartCacheInfo[] FindInCache(byte[] data, Action<SmartCacheInfo> callback)
{
List<SmartCacheInfo> ret = new List<SmartCacheInfo>();
fixed (byte* x = &(data[0]), XcachePtr = &(RamCache[0]))
{
Int32 Loops = data.Length >> 2;
int* cachePtr = (int*)XcachePtr;
int* dataPtr = (int*)x;
if (IndexWritten == 0)
return new SmartCacheInfo[0];
//this part is just horrible slow
for (int i = 0; i < data.Length; i++)
{
if (((data.Length - i) >> 2) == 0)
break;
int index = -1;
dataPtr = (int*)(x + i);
//get the index, alot faster then List.IndexOf
for (int j = 0; ; j++)
{
if (((IndexWritten - j) >> 2) == 0)
break;
if (dataPtr[0] == ((int*)(XcachePtr + j))[0])
{
index = j;
break;
}
}
if (index == -1)
{
//int not found, lets see how
SmartCacheInfo inf = new SmartCacheInfo(-1, i, 4, false);
inf.instruction = Instruction.NEWDATA;
i += inf.Length - 1; //-1... loop does +1
callback(inf);
}
else
{
SmartCacheInfo inf = new SmartCacheInfo(index, i, 0, true); //0 index for now just see what the length is of the MemCmp
inf.Length = MemCmp(data, i, RamCache, index);
ret.Add(inf);
i += inf.Length - 1; //-1... loop does +1
}
}
}
return ret.ToArray();
}
Double looping is what's making it so slow. The data array contains 65535 bytes and so goes for the RamCache array. This code is btw some part of the Cache system I'm working at it's for my SSP project.
Sort the RamCache array or a copy of the array and use a Array.BinarySearch. If you cannot sort it, create a HashSet of the RamCache.

Calculating RMS with overlapping windows

I have a 1-dimensional float array of root mean square values, each calculated with the same window length. Let's say
RMS = {0, 0.01, 0.4, ... }
Now the RMS for a larger window, which can be represented as a range of the original windows, can be calculated as the RMS of the "participating" RMS values from RMS[i] to RMS[i + len]. Here len is the length of the larger window divided by the lenght of the original windows.
I'd like to create a rolling window. I want
rollingRMS[0] = RMS from 0 to len
...
rollingRMS[n] = RMS from n to len+n
calculated as efficiently as possible. I know this isn't very hard to crack, but does anyone have ready code for this?
EDIT: I asked for sample code, so I guess it would be decent to provide some. The following is based on pierr's answer and is written in C#. It's a bit different from my original question as I realized it would be nice to have the resulting array to have the same size as the original and to have the windows end at each element.
// The RMS data to be analysed
float[] RMS = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
// The resulting rolling RMS values
float[] rollingRMS = new float[RMS.Length];
// Window lenght
int len = 3;
// Calculate: rollingRMS will hold root mean square from windows which end at
// each respective sample in the RMS array. For the first len samples the input
// will be treated as zero-padded
for (int i = 0; i < RMS.Length; i++)
{
if (i == 0)
rollingRMS[i] = (float)Math.Sqrt((RMS[i] * RMS[i] / len));
else if (i < len)
rollingRMS[i] = (float)Math.Sqrt(
( RMS[i] * RMS[i] +
len * (rollingRMS[i - 1] * rollingRMS[i - 1])
) / len);
else
rollingRMS[i] = (float)Math.Sqrt(
( len * (rollingRMS[i - 1] * rollingRMS[i - 1]) +
RMS[i] * RMS[i] -
RMS[i - len] * RMS[i - len]
) / len);
}
I am not sure that I have understood your problem correctly. But let me have a try.
a=[1,2,3,4,5,6,7,8,9,10]
LEN = 3
SquareOfRollingRMS[0] = (a[0]^2 + a[1]^2 + a[2]^2 ) / LEN
SquareOfRollingRMS[1] = ( a[1]^2 + a[2]^2 + a[3]^2 ) / LEN
It's not difficult to notice that:
SquareOfRollingRMS[i] = RollingRMS[i-1] * LEN - a[i-1]^2 + a[i+LEN-1]^2
RollingRMS[i] = SqurefOfRollingRMS[i]^(1/2)
Doing it this way ,you are avoiding recaculating the overlap windows.
EDIT:
You can save some divide and multiply operation by moving LEN to the left side of the equations. This might speed up a lot as dividing is usually relatively slow.
LEN_by_SquareOfRollingRMS[0] = (a[0]^2 + a[1]^2 + a[2]^2)
LEN_by_SquareOfRollingRMS[i] = LEN_by_RollingRMS[i-1] - a[i-1]^2 + a[i+LEN-1]^2

Categories

Resources