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); | ||
|  |     } | ||
|  | 
 | ||
|  |     [GenerateTestsForBurstCompatibility] | ||
|  |     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; | ||
|  |             } | ||
|  |         } | ||
|  |     } | ||
|  | } |