How do I get a byte array from an ArraySegment - c#

If someone passes me an ArraySegment<byte> foo and this segment points into a larger buffer, what's the idiomatic way to copy this segment into a fresh new byte[] ?
I tried accessing at foo.Array but this seems to point to the beginning of the larger buffer, not the beginning of the segment.
e.g. the larger buffer could be "blahfoobar" and the ArraySegment points to "foo". I want to get a byte[] with just "foo".
I'm sure it's dead simple, but coming from C++, I can't figure the lingo used in c#.

Creating a new array would be entirely to miss the point of the API, which is to represent a pre-existing segment. In more recent .NET version, Span<T> and ReadOnlySpan<T> would be better choices - they allow you to create an abstraction over contiguous memory without needing the consumer to worry about the Offset etc, as that can be imposed externally. There are constructors on Span<T> and ReadOnlySpan<T> that allow you to deal with aspects so that the consumer never needs to know about them, with the knowledge that on recent runtimes: the JIT will elide bounds checks on spans.

using System;
using System.Text;
namespace ConsoleApp1
{
class Program
{
private static readonly byte[] _initArray = Encoding.ASCII.GetBytes("blahfoobar");
//private static byte[] ArraySegmentToArray(ArraySegment<byte> segment)
//{
// var result = new byte[segment.Count];
// for (int i = 0; i < segment.Count; i++)
// {
// result[i] = segment.Array[i + segment.Offset];
// }
// return result;
//}
private static byte[] ArraySegmentToArray(ArraySegment<byte> segment) =>
segment.ToArray();
static void Main(string[] args)
{
var segFoo = new ArraySegment<byte>(_initArray, 4, 3);
var test = ArraySegmentToArray(segFoo);
}
}
}
But of course it is bad practice. Because if you turn segment to array you allocate memory, and if you use ArraySegment stuff as pointers , you don't allocate memory, actually, that is the main idea of using ArraySegment, because if not the array could be provided as parameters :)
P.S. Commented code just for understanding the idea.

Related

Advice neaed: a best way to write binary data to pipe

I need a way to write data with minimum allocations, as it possible when read from ReadOnlySequence.
A best way that I found is SpanWriter from side library.
But probably some one knows a better standard solution.
using System.IO.Pipelines
namespace WriteSample
{
public async Task Write()
{
var pipe = new Pipe();
var memory = pipe.Writer.GetMemory(2048);
var writer = new Writer???(memory.Span);
writer.Write((byte)0xFF);
writer.Write((long)12345);
writer.WriteBigEndian((long)12345);
await pipe.Writer.FlushAsync()
}
}
The way provided by the runtime is using BinaryPrimitives:
var span = memory.Span;
span[0] = 0xFF;
BinaryPrimitives.WriteInt64LittleEndian(span.Slice(1), 12345);
BinaryPrimitives.WriteInt64BigEndian(span.Slice(9), 12345);
This does have the disadvantage of meaning you need to keep track of where in the span you've written to so far, unlike e.g. BinaryWriter. I don't know of any types in the runtime to help with this, so you'll probably have to write your own, if you care.
Something like:
public ref struct SpanWriter
{
private Span<byte> span;
public SpanWriter(Span<byte> span) => this.span = span;
public void WriteInt64BigEndian(long value)
{
BinaryPrimitives.WriteInt64BigEndian(span, value);
span = span.Slice(8);
}
}

returning byte array reference from android java to csharp unity

byte[] bytes = Call("getBytes") ; where getBytes function returns a byte[].
above function is called to fetch image rgb data in csharp. Returned byte[] is deep copied into the bytes array.
Since return byte array is large, deep copying adds more time.
how to make bytes array in csharp to hold only reference of java byte[]?
public class TestUtil : MonoBehaviour
{
public static string TAG = "--------TestUtil------------> ";
private static AndroidJavaObject pluginClass;
public static List<byte[]> rgbList = new List<byte[]>();
void Start()
{
Debug.Log(TAG + "start called");
//mainDataArray = new byte[1280*720*4];
Debug.Log(TAG + "creating java object");
initializePlayer();
}
public void initializePlayer()
{
// StreamHandler is the Javaclass. here i am creating a object StreamHandler
pluginClass = new AndroidJavaObject("com.test.android.decoder.StreamHandler");
// using this code to get the context
AndroidJavaClass unityPlayer = new AndroidJavaClass("com.unity3d.player.UnityPlayer");
AndroidJavaObject activity = unityPlayer.GetStatic<AndroidJavaObject>("currentActivity");
// setting context StreamHandler object
pluginClass.Call("setActivity", activity);
// setting the interface object, where java class will call the respective function
pluginClass.Call("setOnDecodeListener", new AndroidPluginCallback());
// initializing the player
pluginClass.Call("init", ipAddress, port, outWidth, outHeight);
Debug.Log(TAG + " Initialization done");
}
public void quitApplication(string sid)
{
Application.Quit();
}
private void Update()
{
if (Input.GetKey(KeyCode.Escape)) {
Debug.Log(TAG + "Escape");
quitApplication(sId);
}
}
int count;
private void LateUpdate()
{
if (0 != rgbList.Count) {
// here i am updating the rgb texture to Quad gameobject
}
}
class AndroidPluginCallback : AndroidJavaProxy
{
public AndroidPluginCallback() : base("com.test.android.OnDecodeListener") { }
public void success(byte[] videoPath)
{
}
public void onFrameAvailable()
{
// Called when java code successfully generate RGBA data
long startTime = DateTimeOffset.Now.ToUnixTimeMilliseconds();
// Need to call "getBytes()" to get the RGBA frame.
//Note: generally if you call same function from another java class it do shallow copy to byte[] object
// but in this case it is doing deep copy or i am not sure whats going on.
byte[] rawBytes = pluginClass.Call<byte[]>("getBytes"); // width and height of frame is 1088x1088
rgbList.Add(rawBytes);
long diff = DateTimeOffset.Now.ToUnixTimeMilliseconds() - startTime;
Debug.Log(TAG + "Entered into onFrameAvailable callback. time taken to copy to rawbytes: " + diff); // diff is 14ms on average. Not sure why.
}
public void fail(string errorMessage)
{
Debug.Log(TAG + "ENTER callback onError: " + errorMessage);
}
}
}
AndroidJavaObject uses the JNI (Java Native Interface) to marshal data to and from Java land. Depending on how Java stores the arrays in memory, the JNI may need to do a deep copy to form an array that C# would understand, such as if the JVM originally stored the array in non-contiguous blocks.
Here's IBM's description:
JNI provides a clean interface between Java code and native code. To maintain this separation, arrays are passed as opaque handles, and native code must call back to the JVM in order to manipulate array elements using set and get calls. The Java specification leaves it up to the JVM implementation whether these calls provide direct access to the arrays or return a copy of the array. For example, the JVM might return a copy when it has optimized arrays in a way that does not store them contiguously.
These calls, then, might cause copying of the elements being manipulated. For example, if you call GetLongArrayElements() on an array with 1,000 elements, you might cause the allocation and copy of at least 8,000 bytes (1,000 elements * 8 bytes for each long). When you then update the array's contents with ReleaseLongArrayElements(), another copy of 8,000 bytes might be required to update the array. Even when you use the newer GetPrimitiveArrayCritical(), the specification still permits the JVM to make copies of the full array.
So basically, try to avoid marshalling arrays across the JNI (such as with AndroidJavaObject as much as possible, because it's not up to the C# on whether the JNI makes a deep copy or not.

improving conversions to binary and back in C#

I'm trying to write a general purpose socket server for a game I'm working on. I know I could very well use already built servers like SmartFox and Photon, but I wan't to go through the pain of creating one myself for learning purposes.
I've come up with a BSON inspired protocol to convert the the basic data types, their arrays, and a special GSObject to binary and arrange them in a way so that it can be put back together into object form on the client end. At the core, the conversion methods utilize the .Net BitConverter class to convert the basic data types to binary. Anyways, the problem is performance, if I loop 50,000 times and convert my GSObject to binary each time it takes about 5500ms (the resulting byte[] is just 192 bytes per conversion). I think think this would be way too slow for an MMO that sends 5-10 position updates per second with a 1000 concurrent users. Yes, I know it's unlikely that a game will have a 1000 users on at the same time, but like I said earlier this is supposed to be a learning process for me, I want to go out of my way and build something that scales well and can handle at least a few thousand users.
So yea, if anyone's aware of other conversion techniques or sees where I'm loosing performance I would appreciate the help.
GSBitConverter.cs
This is the main conversion class, it adds extension methods to main datatypes to convert to the binary format. It uses the BitConverter class to convert the base types. I've shown only the code to convert integer and integer arrays, but the rest of the method are pretty much replicas of those two, they just overload the type.
public static class GSBitConverter
{
public static byte[] ToGSBinary(this short value)
{
return BitConverter.GetBytes(value);
}
public static byte[] ToGSBinary(this IEnumerable<short> value)
{
List<byte> bytes = new List<byte>();
short length = (short)value.Count();
bytes.AddRange(length.ToGSBinary());
for (int i = 0; i < length; i++)
bytes.AddRange(value.ElementAt(i).ToGSBinary());
return bytes.ToArray();
}
public static byte[] ToGSBinary(this bool value);
public static byte[] ToGSBinary(this IEnumerable<bool> value);
public static byte[] ToGSBinary(this IEnumerable<byte> value);
public static byte[] ToGSBinary(this int value);
public static byte[] ToGSBinary(this IEnumerable<int> value);
public static byte[] ToGSBinary(this long value);
public static byte[] ToGSBinary(this IEnumerable<long> value);
public static byte[] ToGSBinary(this float value);
public static byte[] ToGSBinary(this IEnumerable<float> value);
public static byte[] ToGSBinary(this double value);
public static byte[] ToGSBinary(this IEnumerable<double> value);
public static byte[] ToGSBinary(this string value);
public static byte[] ToGSBinary(this IEnumerable<string> value);
public static string GetHexDump(this IEnumerable<byte> value);
}
Program.cs
Here's the the object that I'm converting to binary in a loop.
class Program
{
static void Main(string[] args)
{
GSObject obj = new GSObject();
obj.AttachShort("smallInt", 15);
obj.AttachInt("medInt", 120700);
obj.AttachLong("bigInt", 10900800700);
obj.AttachDouble("doubleVal", Math.PI);
obj.AttachStringArray("muppetNames", new string[] { "Kermit", "Fozzy", "Piggy", "Animal", "Gonzo" });
GSObject apple = new GSObject();
apple.AttachString("name", "Apple");
apple.AttachString("color", "red");
apple.AttachBool("inStock", true);
apple.AttachFloat("price", (float)1.5);
GSObject lemon = new GSObject();
apple.AttachString("name", "Lemon");
apple.AttachString("color", "yellow");
apple.AttachBool("inStock", false);
apple.AttachFloat("price", (float)0.8);
GSObject apricoat = new GSObject();
apple.AttachString("name", "Apricoat");
apple.AttachString("color", "orange");
apple.AttachBool("inStock", true);
apple.AttachFloat("price", (float)1.9);
GSObject kiwi = new GSObject();
apple.AttachString("name", "Kiwi");
apple.AttachString("color", "green");
apple.AttachBool("inStock", true);
apple.AttachFloat("price", (float)2.3);
GSArray fruits = new GSArray();
fruits.AddGSObject(apple);
fruits.AddGSObject(lemon);
fruits.AddGSObject(apricoat);
fruits.AddGSObject(kiwi);
obj.AttachGSArray("fruits", fruits);
Stopwatch w1 = Stopwatch.StartNew();
for (int i = 0; i < 50000; i++)
{
byte[] b = obj.ToGSBinary();
}
w1.Stop();
Console.WriteLine(BitConverter.IsLittleEndian ? "Little Endian" : "Big Endian");
Console.WriteLine(w1.ElapsedMilliseconds + "ms");
}
Here's the code for some of my other classes that are used in the code above. Most of it is repetitive.
GSObject
GSArray
GSWrappedObject
My first hunch, without much to go off, would be that a lot of your time is being sunk into constantly re-creating arrays and lists.
I would be inclined to move to a Stream-based approach rather than trying to create arrays constantly. That being, make all the GSBinary methods accept a Stream then write to it rather than making their own arrays, then if you want it in local memory use a MemoryStream at the base and then get your array out of it at the end (Or even better if you're planning this to be a networked application, write directly to the network stream).
As per Chris's comment earlier however the best way to start is to run a profiler such at dotTrace or redgate's ANTS performance profiler to actually find out which step is taking the most time before investing time refactoring something which, while inefficient, may only be a small fraction of the actual time.
1) ElementAt is very expensive. Use foreach (var v in value) instead of for (int i = 0; i < length; i++) .. .ElementAt(i) ..
2) ToGsBinary methods is expensive because they copy arrays frequently.
Use signature void WriteToGsBinary(Stream stream) instead of byte[] ToGsBinary()
3) Add overloads for arrays: void WriteToGsBinary(Stream stream, byte[] values), void WriteToGsBinary(Stream stream, short[] values), etc

ValueType to IntPtr to use during application lifetime

Lets say we have a native library that works with data like this:
double *pointer = &globalValue;
SetAddress(pointer);
//Then we can change value and write it to disk
globalValue = 5.0;
FlushValues(); // this function writes all values
// registered by SetAddress(..) functions
... //Then we change our value (or values)
FlushValues(); //and do write any time we need
Now I have to interop it to C#. I would like to avoid using unsafe... but... I dont know =)
So on C# side we will have some class wich fields we will write. And we can do writing like:
public class Data
{
[Serializable] <-- somehow we mark what we are going to write
double myValue;
...
[Serializable]
double myValueN;
}
public class LibraryInterop
{
IntPtr[] pointers; //Pointers that will go to SetAddressMethod
...
public void RegisterObject(Data data)
{
... //With reflection we look for [Serializable] values
//create a pointer for each and some kind of BindingInfo
//that knows connection of pointers[i] to data.myValueN
//Then add this pointers to C++ library
foreach(IntPtr pointer in pointers) { SetAddress(pointer);}
}
public void Flush()
{
//Loop through all added pointers
for(int i=0; i<pointers.Length; i++)
{
double value = ... //With reflections and BindingInfo we find data.myValueN
// that corresponds to pointers[i]
// then we write this value to memory of IntPtr
// we have to brake value to bytes and write it one by one to memory
// we could use BitConverter.DoubleToInt64Bits() but double - is just
// an example, so in general case we will use GetBytes
int offset = 0;
foreach(byte b in BitConverter.GetBytes(value))
{
Marshal.WriteByte(pointer[i],offset,byte);
offset++;
}
}
//Save values of IntPtr to disk
FlushValues();
}
}
Then the user code looks like this then
var library = new LibraryInterop();
var data1 = new Data();
var data2 = new AnotherData();
library.RegisterObject(data1);
library.RegisterObject(data2);
...//change data
library.Flush();
...//change data
library.Flush();
...//change data
library.Flush();
So in C++ we have a very neat structure. We have pointers, we fill data behind this pointers and on FlushValues all this values are writed.
C# part cannot have SetAddress(ref double value). Since address may change, we have to pin pointers - use unsafe+fixed or IntPtr, and have SO many headache.
On the other hand, we can have "managed pointers" by boxing|unboxing data.myValue to Object. So if it would be possible to somehow bind this ValueType data.myValue to IntPtr without this coping and reflection - it would be much much neater.
Is it possible to do this interop and have less ugly and slow C# part then the one I listed here?
(There are some major downsides to this...)
You can use GCHandle.Alloc(data1, GCHandleType.Pinned) to "pin" an object, and then get an IntPtr from GCHandle.AddrOfPinnedObject. If you do this, you'll be able to pass this IntPtr to your native code, which should work as expected.
However, this is going to cause a lot of issues in terms of undermining the efficiency of the garbage collector. If you decide to do something like this, I'd recommend allocating all of the objects very early on in your program (potentially immediately after calling a GC.Collect(), which is something I really don't normally recommend), and leaving them alone for the lifetime of your program. This would (slightly) mitigate the GC issues, as it'd allocate them into the "best" possible spot early on, and leave them where they'll only be touched in Gen2 collections.

What is the equivalent of "ByteBuffer.flip" & "ByteBuffer.slice" in .NET?

I need to port code from Java to C#. In the Java code, the methods "ByteBuffer.flip()" and "ByteBuffer.slice" is used, and I don't know how to translate this.
I've read this question (An equivalent of javax.nio.Buffer.flip() in c#), but although an answer is given, I cannot figure how to apply it. According to Tom Hawtin, I should "Set the limit to the current position and then set the position to zero" in the underlying array. I am unsure as of how to change these values. (If you could explain the underlying logic, it would help me a lot :)
As for the ByteBuffer.slice, I have no clue on how to translate it.
EDIT: If it can be clearer with the actual code, I'll post it:
Java:
ByteBuffer buff;
buff.putShort((short) 0);
buff.put(customArray);
buff.flip();
buff.putShort((short) 0);
ByteBuffer b = buff.slice();
short size = (short) (customFunction(b) + 2);
buff.putShort(0, size);
buff.position(0).limit(size);
So far, my translation in C#.NET:
BinaryWriter b = new BinaryWriter(); //ByteBuffer buff;
b.Write((short)0); // buff.putShort((short) 0);
b.Write(paramStream.ToArray()); // buff.put(customArray);
b.BaseStream.SetLength(b.BaseStream.Position); // buff.flip; (not sure)
b.BaseStream.Position = 0; // buff.flip; too (not sure)
b.Write((short)0); // buff.putShort((short) 0)
??? // ByteBuffer b = buff.slice();
// Not done but I can do it, short size = (short) (customFunction(b) + 2);
??? // How do I write at a particular position?
??? // buff.position(0).limit(size); I don't know how to do this
Thank you!
EDIT: Changed b.BaseStream.SetLength(b.BaseStream.Length); to b.BaseStream.SetLength(b.BaseStream.Position);, based on the Java docs.
(See See http://java.sun.com/javase/6/docs/api/java/nio/ByteBuffer.html#slice%28%29 and http://java.sun.com/javase/6/docs/api/java/nio/Buffer.html#flip%28%29 for java's calls)
Flip is a quick way to reset the buffer. So for example
(pseudocode)
void flip()
{
Length = currentPos;
currentPos = 0;
}
Allows you to quickly setup the buffer you presumably just wrote to for reading from the beginning.
Update:
Splice is a bit trickier due to the requirement that "Changes to this buffer's content will be visible in the new buffer, and vice versa; the two buffers' position, limit, and mark values will be independent". There unfortunately is no concept of a shared portion of buffer (that i know of - theres always using arrays, detailed below) without making your own class. The closest thing you could do is this:
Old Code:
ByteBuffer b = buff.slice();
New Code (assuming a List)
List<Byte> b= buff;
int bStart = buffPos; // buffPos is your way of tracking your mark
the downside to the code above is that there is no way for c# to hold the new starting point of the new buffer and still share it. You'll have to manually use the new starting point whenever you do anything, from for loops (for i=bStart;...) to indexing (newList[i + bStart]...)
Your other option is to do use Byte[] arrays instead, and do something like this:
Byte[] b = &buff[buffPos];
... however that requires unsafe operations to be enabled, and I cannot vouch for its saftey, due to the garbage collector and my avoidance of the "unsafe" features.
Outside of that, theres always making your own ByteBuffer class.
Untested, but if I understand the java bits correctly, this would give you an idea on how to implement.
public class ByteBuffer {
private int _Position;
private int _Capacity;
private byte[] _Buffer;
private int _Start;
private ByteBuffer(int capacity, int position, int start, byte[] buffer) {
_Capacity = capacity;
_Position = position;
_Start = start;
_Buffer = buffer;
}
public ByteBuffer(int capacity) : this(capacity, 0 , 0, new byte[capacity]) {
}
public void Write(byte item) {
if (_Position >= _Capacity) {
throw new InvalidOperationException();
}
_Buffer[_Start + _Position++] = item;
}
public byte Read() {
if (_Position >= _Capacity) {
throw new InvalidOperationException();
}
return _Buffer[_Start + _Position++];
}
public void Flip() {
_Capacity = _Position;
_Position = _Start;
}
public ByteBuffer Slice() {
return new ByteBuffer(_Capacity-_Position, 0, _Position, _Buffer);
}
}

Categories

Resources