Firstborn/Library/PackageCache/com.unity.collections@1.4.0/Unity.Collections/FixedStringUtils.cs

146 lines
4.9 KiB
C#
Raw Normal View History

2023-03-28 13:24:16 -04:00
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;
}
}
}
}