Skip to content

Commit 92c66b0

Browse files
committed
Lockless single and double conversions
1 parent 28891a9 commit 92c66b0

File tree

1 file changed

+53
-39
lines changed

1 file changed

+53
-39
lines changed

MLAPI/NetworkingManagerComponents/Binary/BitStream.cs

Lines changed: 53 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
using System;
22
using System.IO;
3+
using System.Runtime.InteropServices;
34
using System.Security;
45
using UnityEngine;
56
using static MLAPI.NetworkingManagerComponents.Binary.Arithmetic;
@@ -11,11 +12,27 @@ namespace MLAPI.NetworkingManagerComponents.Binary
1112
/// </summary>
1213
public sealed class BitStream : Stream
1314
{
15+
16+
[StructLayout(LayoutKind.Explicit)]
17+
internal struct UIntFloat
18+
{
19+
[FieldOffset(0)]
20+
public float floatValue;
21+
22+
[FieldOffset(0)]
23+
public uint intValue;
24+
25+
[FieldOffset(0)]
26+
public double doubleValue;
27+
28+
[FieldOffset(0)]
29+
public ulong longValue;
30+
}
31+
32+
1433
const int initialCapacity = 16;
1534
const float initialGrowthFactor = 2.0f;
1635
private byte[] target;
17-
private static readonly float[] holder_f = new float[1];
18-
private static readonly uint[] holder_i = new uint[1];
1936

2037
/// <summary>
2138
/// A stream that supports writing data smaller than a single byte. This stream also has a built-in compression algorithm that can (optionally) be used to write compressed data.
@@ -284,13 +301,10 @@ public void WriteBit(bool bit)
284301
/// <param name="value">Value to write</param>
285302
public void WriteSingle(float value)
286303
{
287-
lock (holder_f)
288-
lock (holder_i)
289-
{
290-
holder_f[0] = value;
291-
Buffer.BlockCopy(holder_f, 0, holder_i, 0, 4);
292-
WriteUInt32(holder_i[0]);
293-
}
304+
UIntFloat conversion = new UIntFloat();
305+
conversion.floatValue = value;
306+
uint binary = conversion.intValue;
307+
WriteUInt32(binary);
294308
}
295309

296310
/// <summary>
@@ -299,8 +313,10 @@ public void WriteSingle(float value)
299313
/// <param name="value">Value to write</param>
300314
public void WriteDouble(double value)
301315
{
302-
long binary = BitConverter.DoubleToInt64Bits(value);
303-
WriteInt64(binary);
316+
UIntFloat conversion = new UIntFloat();
317+
conversion.doubleValue = value;
318+
ulong binary = conversion.longValue;
319+
WriteUInt64(binary);
304320

305321
}
306322

@@ -310,13 +326,10 @@ public void WriteDouble(double value)
310326
/// <param name="value">Value to write</param>
311327
public void WriteSinglePacked(float value)
312328
{
313-
lock (holder_f)
314-
lock (holder_i)
315-
{
316-
holder_f[0] = value;
317-
Buffer.BlockCopy(holder_f, 0, holder_i, 0, 4);
318-
WriteUInt32Packed(BinaryHelpers.SwapEndian(holder_i[0]));
319-
}
329+
UIntFloat conversion = new UIntFloat();
330+
conversion.floatValue = value;
331+
uint binary = conversion.intValue;
332+
WriteUInt32Packed(binary);
320333
}
321334

322335
/// <summary>
@@ -325,8 +338,11 @@ public void WriteSinglePacked(float value)
325338
/// <param name="value">Value to write</param>
326339
public void WriteDoublePacked(double value)
327340
{
328-
long binary = BitConverter.DoubleToInt64Bits(value);
329-
WriteInt64Packed(binary);
341+
UIntFloat conversion = new UIntFloat();
342+
conversion.doubleValue = value;
343+
ulong binary = conversion.longValue;
344+
345+
WriteUInt64Packed(binary);
330346
}
331347

332348
/// <summary>
@@ -506,13 +522,10 @@ public void WriteRotation(Quaternion rotation, int bytesPerAngle)
506522
public float ReadSingle()
507523
{
508524
uint read = ReadUInt32();
509-
lock (holder_f)
510-
lock (holder_i)
511-
{
512-
holder_i[0] = read;
513-
Buffer.BlockCopy(holder_i, 0, holder_f, 0, 4);
514-
return holder_f[0];
515-
}
525+
526+
UIntFloat conversion = new UIntFloat();
527+
conversion.intValue = read;
528+
return conversion.floatValue;
516529
}
517530

518531

@@ -522,10 +535,13 @@ public float ReadSingle()
522535
/// <returns>The read value</returns>
523536
public double ReadDouble()
524537
{
525-
526-
long read = ReadInt64();
527-
return BitConverter.Int64BitsToDouble(read);
538+
ulong read = ReadUInt64();
539+
540+
UIntFloat conversion = new UIntFloat();
541+
conversion.longValue = read;
542+
return conversion.doubleValue;
528543
}
544+
529545

530546
/// <summary>
531547
/// Read a single-precision floating point value from the stream from a varint
@@ -534,13 +550,9 @@ public double ReadDouble()
534550
public float ReadSinglePacked()
535551
{
536552
uint read = ReadUInt32Packed();
537-
lock (holder_f)
538-
lock (holder_i)
539-
{
540-
holder_i[0] = BinaryHelpers.SwapEndian(read);
541-
Buffer.BlockCopy(holder_i, 0, holder_f, 0, 4);
542-
return holder_f[0];
543-
}
553+
UIntFloat conversion = new UIntFloat();
554+
conversion.intValue = read;
555+
return conversion.floatValue;
544556
}
545557

546558
/// <summary>
@@ -549,8 +561,10 @@ public float ReadSinglePacked()
549561
/// <returns>The read value</returns>
550562
public double ReadDoublePacked()
551563
{
552-
long read = ReadInt64Packed();
553-
return BitConverter.Int64BitsToDouble(read);
564+
ulong read = ReadUInt64Packed();
565+
UIntFloat conversion = new UIntFloat();
566+
conversion.longValue = read;
567+
return conversion.doubleValue;
554568
}
555569

556570
/// <summary>

0 commit comments

Comments
 (0)