146 lines
4.9 KiB
C#
146 lines
4.9 KiB
C#
|
using System;
|
||
|
using System.Runtime.InteropServices;
|
||
|
using Unity.Collections.LowLevel.Unsafe;
|
||
|
using System.Diagnostics;
|
||
|
|
||
|
namespace Unity.Collections
|
||
|
{
|
||
|
/// <summary>
|
||
|
/// An interface for a sequence of UTF-8 encoded text.
|
||
|
/// </summary>
|
||
|
public interface IUTF8Bytes
|
||
|
{
|
||
|
/// <summary>
|
||
|
/// Whether this IUTF8Bytes is empty.
|
||
|
/// </summary>
|
||
|
/// <value>True if this IUTF8Bytes is empty.</value>
|
||
|
bool IsEmpty { get; }
|
||
|
|
||
|
/// <summary>
|
||
|
/// Returns a pointer to the content of this IUTF8Bytes.
|
||
|
/// </summary>
|
||
|
/// <remarks>The pointer may point to stack memory.</remarks>
|
||
|
/// <returns>A pointer to the content of this IUTF8Bytes.</returns>
|
||
|
unsafe byte* GetUnsafePtr();
|
||
|
|
||
|
/// <summary>
|
||
|
/// Attempt to set the length in bytes of this IUTF8Bytes's content buffer.
|
||
|
/// </summary>
|
||
|
/// <param name="newLength">The new length in bytes of the IUTF8Bytes's content buffer.</param>
|
||
|
/// <param name="clearOptions">Whether any bytes added should be zeroed out.</param>
|
||
|
/// <returns>True if the new length is valid.</returns>
|
||
|
bool TryResize(int newLength, NativeArrayOptions clearOptions = NativeArrayOptions.ClearMemory);
|
||
|
}
|
||
|
|
||
|
[BurstCompatible]
|
||
|
internal unsafe static class FixedStringUtils
|
||
|
{
|
||
|
[StructLayout(LayoutKind.Explicit)]
|
||
|
internal struct UintFloatUnion
|
||
|
{
|
||
|
[FieldOffset(0)]
|
||
|
public uint uintValue;
|
||
|
[FieldOffset(0)]
|
||
|
public float floatValue;
|
||
|
}
|
||
|
|
||
|
internal static ParseError Base10ToBase2(ref float output, ulong mantissa10, int exponent10)
|
||
|
{
|
||
|
if (mantissa10 == 0)
|
||
|
{
|
||
|
output = 0.0f;
|
||
|
return ParseError.None;
|
||
|
}
|
||
|
if (exponent10 == 0)
|
||
|
{
|
||
|
output = mantissa10;
|
||
|
return ParseError.None;
|
||
|
}
|
||
|
var exponent2 = exponent10;
|
||
|
var mantissa2 = mantissa10;
|
||
|
while (exponent10 > 0)
|
||
|
{
|
||
|
while ((mantissa2 & 0xe000000000000000U) != 0)
|
||
|
{
|
||
|
mantissa2 >>= 1;
|
||
|
++exponent2;
|
||
|
}
|
||
|
mantissa2 *= 5;
|
||
|
--exponent10;
|
||
|
}
|
||
|
while (exponent10 < 0)
|
||
|
{
|
||
|
while ((mantissa2 & 0x8000000000000000U) == 0)
|
||
|
{
|
||
|
mantissa2 <<= 1;
|
||
|
--exponent2;
|
||
|
}
|
||
|
mantissa2 /= 5;
|
||
|
++exponent10;
|
||
|
}
|
||
|
// TODO: implement math.ldexpf (which presumably handles denormals (i don't))
|
||
|
UintFloatUnion ufu = new UintFloatUnion();
|
||
|
ufu.floatValue = mantissa2;
|
||
|
var e = (int)((ufu.uintValue >> 23) & 0xFFU) - 127;
|
||
|
e += exponent2;
|
||
|
if (e > 128)
|
||
|
return ParseError.Overflow;
|
||
|
if (e < -127)
|
||
|
return ParseError.Underflow;
|
||
|
ufu.uintValue = (ufu.uintValue & ~(0xFFU << 23)) | ((uint)(e + 127) << 23);
|
||
|
output = ufu.floatValue;
|
||
|
return ParseError.None;
|
||
|
}
|
||
|
|
||
|
internal static void Base2ToBase10(ref ulong mantissa10, ref int exponent10, float input)
|
||
|
{
|
||
|
UintFloatUnion ufu = new UintFloatUnion();
|
||
|
ufu.floatValue = input;
|
||
|
if (ufu.uintValue == 0)
|
||
|
{
|
||
|
mantissa10 = 0;
|
||
|
exponent10 = 0;
|
||
|
return;
|
||
|
}
|
||
|
var mantissa2 = (ufu.uintValue & ((1 << 23) - 1)) | (1 << 23);
|
||
|
var exponent2 = (int)(ufu.uintValue >> 23) - 127 - 23;
|
||
|
mantissa10 = mantissa2;
|
||
|
exponent10 = exponent2;
|
||
|
if (exponent2 > 0)
|
||
|
{
|
||
|
while (exponent2 > 0)
|
||
|
{
|
||
|
// denormalize mantissa10 as much as you can, to minimize loss when doing /5 below.
|
||
|
while (mantissa10 <= UInt64.MaxValue / 10)
|
||
|
{
|
||
|
mantissa10 *= 10;
|
||
|
--exponent10;
|
||
|
}
|
||
|
mantissa10 /= 5;
|
||
|
--exponent2;
|
||
|
}
|
||
|
}
|
||
|
if (exponent2 < 0)
|
||
|
{
|
||
|
while (exponent2 < 0)
|
||
|
{
|
||
|
// normalize mantissa10 just as much as you need, in order to make the *5 below not overflow.
|
||
|
while (mantissa10 > UInt64.MaxValue / 5)
|
||
|
{
|
||
|
mantissa10 /= 10;
|
||
|
++exponent10;
|
||
|
}
|
||
|
mantissa10 *= 5;
|
||
|
++exponent2;
|
||
|
}
|
||
|
}
|
||
|
// normalize mantissa10
|
||
|
while (mantissa10 > 9999999U || mantissa10 % 10 == 0)
|
||
|
{
|
||
|
mantissa10 = (mantissa10 + (mantissa10 < 100000000U ? 5u : 0u)) / 10;
|
||
|
++exponent10;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|