Changed C# ByteBuffer to use bit shifts instead of BitConverter

BitConverter was excessively slow since it allocates a byte array
at each access.

Bug: 18702381
Change-Id: I47be9c38e1d04287ba4c10bc369848f3e13a2a2f
Tested: on Windows.
parent 7ef2fc25
...@@ -44,6 +44,12 @@ namespace FlatBuffers ...@@ -44,6 +44,12 @@ namespace FlatBuffers
public int position() { return _pos; } public int position() { return _pos; }
// Pre-allocated helper arrays for convertion.
private float[] floathelper = new[] { 0.0f };
private int[] inthelper = new[] { 0 };
private double[] doublehelper = new[] { 0.0 };
private ulong[] ulonghelper = new[] { 0UL };
// Helper functions for the unsafe version. // Helper functions for the unsafe version.
static public ushort ReverseBytes(ushort input) static public ushort ReverseBytes(ushort input)
{ {
...@@ -71,24 +77,44 @@ namespace FlatBuffers ...@@ -71,24 +77,44 @@ namespace FlatBuffers
#if !UNSAFE_BYTEBUFFER #if !UNSAFE_BYTEBUFFER
// Helper functions for the safe (but slower) version. // Helper functions for the safe (but slower) version.
protected void WriteLittleEndian(int offset, byte[] data) protected void WriteLittleEndian(int offset, int count, ulong data)
{ {
if (!BitConverter.IsLittleEndian) if (BitConverter.IsLittleEndian)
{ {
Array.Reverse(data, 0, data.Length); for (int i = 0; i < count; i++)
{
_buffer[offset + i] = (byte)(data >> i * 8);
}
}
else
{
for (int i = 0; i < count; i++)
{
_buffer[offset + count - 1 - i] = (byte)(data >> i * 8);
}
} }
Buffer.BlockCopy(data, 0, _buffer, offset, data.Length);
_pos = offset; _pos = offset;
} }
protected byte[] ReadLittleEndian(int offset, int count) protected ulong ReadLittleEndian(int offset, int count)
{ {
AssertOffsetAndLength(offset, count); AssertOffsetAndLength(offset, count);
var tmp = new byte[count]; ulong r = 0;
Buffer.BlockCopy(_buffer, offset, tmp, 0, count); if (BitConverter.IsLittleEndian)
return (BitConverter.IsLittleEndian) {
? tmp for (int i = 0; i < count; i++)
: tmp.Reverse().ToArray(); {
r |= (ulong)_buffer[offset + i] << i * 8;
}
}
else
{
for (int i = 0; i < count; i++)
{
r |= (ulong)_buffer[offset + count - 1 - i] << i * 8;
}
}
return r;
} }
#endif // !UNSAFE_BYTEBUFFER #endif // !UNSAFE_BYTEBUFFER
...@@ -207,49 +233,53 @@ namespace FlatBuffers ...@@ -207,49 +233,53 @@ namespace FlatBuffers
public void PutShort(int offset, short value) public void PutShort(int offset, short value)
{ {
AssertOffsetAndLength(offset, sizeof(short)); AssertOffsetAndLength(offset, sizeof(short));
WriteLittleEndian(offset, BitConverter.GetBytes(value)); WriteLittleEndian(offset, sizeof(short), (ulong)value);
} }
public void PutUshort(int offset, ushort value) public void PutUshort(int offset, ushort value)
{ {
AssertOffsetAndLength(offset, sizeof(ushort)); AssertOffsetAndLength(offset, sizeof(ushort));
WriteLittleEndian(offset, BitConverter.GetBytes(value)); WriteLittleEndian(offset, sizeof(ushort), (ulong)value);
} }
public void PutInt(int offset, int value) public void PutInt(int offset, int value)
{ {
AssertOffsetAndLength(offset, sizeof(int)); AssertOffsetAndLength(offset, sizeof(int));
WriteLittleEndian(offset, BitConverter.GetBytes(value)); WriteLittleEndian(offset, sizeof(int), (ulong)value);
} }
public void PutUint(int offset, uint value) public void PutUint(int offset, uint value)
{ {
AssertOffsetAndLength(offset, sizeof(uint)); AssertOffsetAndLength(offset, sizeof(uint));
WriteLittleEndian(offset, BitConverter.GetBytes(value)); WriteLittleEndian(offset, sizeof(uint), (ulong)value);
} }
public void PutLong(int offset, long value) public void PutLong(int offset, long value)
{ {
AssertOffsetAndLength(offset, sizeof(long)); AssertOffsetAndLength(offset, sizeof(long));
WriteLittleEndian(offset, BitConverter.GetBytes(value)); WriteLittleEndian(offset, sizeof(long), (ulong)value);
} }
public void PutUlong(int offset, ulong value) public void PutUlong(int offset, ulong value)
{ {
AssertOffsetAndLength(offset, sizeof(ulong)); AssertOffsetAndLength(offset, sizeof(ulong));
WriteLittleEndian(offset, BitConverter.GetBytes(value)); WriteLittleEndian(offset, sizeof(ulong), value);
} }
public void PutFloat(int offset, float value) public void PutFloat(int offset, float value)
{ {
AssertOffsetAndLength(offset, sizeof(float)); AssertOffsetAndLength(offset, sizeof(float));
WriteLittleEndian(offset, BitConverter.GetBytes(value)); floathelper[0] = value;
Buffer.BlockCopy(floathelper, 0, inthelper, 0, sizeof(float));
WriteLittleEndian(offset, sizeof(float), (ulong)inthelper[0]);
} }
public void PutDouble(int offset, double value) public void PutDouble(int offset, double value)
{ {
AssertOffsetAndLength(offset, sizeof(double)); AssertOffsetAndLength(offset, sizeof(double));
WriteLittleEndian(offset, BitConverter.GetBytes(value)); doublehelper[0] = value;
Buffer.BlockCopy(doublehelper, 0, ulonghelper, 0, sizeof(double));
WriteLittleEndian(offset, sizeof(double), ulonghelper[0]);
} }
#endif // UNSAFE_BYTEBUFFER #endif // UNSAFE_BYTEBUFFER
...@@ -353,58 +383,49 @@ namespace FlatBuffers ...@@ -353,58 +383,49 @@ namespace FlatBuffers
// Slower versions of Get* for when unsafe code is not allowed. // Slower versions of Get* for when unsafe code is not allowed.
public short GetShort(int index) public short GetShort(int index)
{ {
var tmp = ReadLittleEndian(index, sizeof(short)); return (short)ReadLittleEndian(index, sizeof(short));
var value = BitConverter.ToInt16(tmp, 0);
return value;
} }
public ushort GetUshort(int index) public ushort GetUshort(int index)
{ {
var tmp = ReadLittleEndian(index, sizeof(ushort)); return (ushort)ReadLittleEndian(index, sizeof(ushort));
var value = BitConverter.ToUInt16(tmp, 0);
return value;
} }
public int GetInt(int index) public int GetInt(int index)
{ {
var tmp = ReadLittleEndian(index, sizeof(int)); return (int)ReadLittleEndian(index, sizeof(int));
var value = BitConverter.ToInt32(tmp, 0);
return value;
} }
public uint GetUint(int index) public uint GetUint(int index)
{ {
var tmp = ReadLittleEndian(index, sizeof(uint)); return (uint)ReadLittleEndian(index, sizeof(uint));
var value = BitConverter.ToUInt32(tmp, 0);
return value;
} }
public long GetLong(int index) public long GetLong(int index)
{ {
var tmp = ReadLittleEndian(index, sizeof(long)); return (long)ReadLittleEndian(index, sizeof(long));
var value = BitConverter.ToInt64(tmp, 0);
return value;
} }
public ulong GetUlong(int index) public ulong GetUlong(int index)
{ {
var tmp = ReadLittleEndian(index, sizeof(ulong)); return ReadLittleEndian(index, sizeof(ulong));
var value = BitConverter.ToUInt64(tmp, 0);
return value;
} }
public float GetFloat(int index) public float GetFloat(int index)
{ {
var tmp = ReadLittleEndian(index, sizeof(float)); int i = (int)ReadLittleEndian(index, sizeof(float));
var value = BitConverter.ToSingle(tmp, 0); inthelper[0] = i;
return value; Buffer.BlockCopy(inthelper, 0, floathelper, 0, sizeof(float));
return floathelper[0];
} }
public double GetDouble(int index) public double GetDouble(int index)
{ {
var tmp = ReadLittleEndian(index, sizeof(double)); ulong i = ReadLittleEndian(index, sizeof(double));
var value = BitConverter.ToDouble(tmp, 0); // There's Int64BitsToDouble but it uses unsafe code internally.
return value; ulonghelper[0] = i;
Buffer.BlockCopy(ulonghelper, 0, doublehelper, 0, sizeof(double));
return doublehelper[0];
} }
#endif // UNSAFE_BYTEBUFFER #endif // UNSAFE_BYTEBUFFER
} }
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment