No Description
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

FixedStringUtils.cs 4.9KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145
  1. using System;
  2. using System.Runtime.InteropServices;
  3. using Unity.Collections.LowLevel.Unsafe;
  4. using System.Diagnostics;
  5. namespace Unity.Collections
  6. {
  7. /// <summary>
  8. /// An interface for a sequence of UTF-8 encoded text.
  9. /// </summary>
  10. public interface IUTF8Bytes
  11. {
  12. /// <summary>
  13. /// Whether this IUTF8Bytes is empty.
  14. /// </summary>
  15. /// <value>True if this IUTF8Bytes is empty.</value>
  16. bool IsEmpty { get; }
  17. /// <summary>
  18. /// Returns a pointer to the content of this IUTF8Bytes.
  19. /// </summary>
  20. /// <remarks>The pointer may point to stack memory.</remarks>
  21. /// <returns>A pointer to the content of this IUTF8Bytes.</returns>
  22. unsafe byte* GetUnsafePtr();
  23. /// <summary>
  24. /// Attempt to set the length in bytes of this IUTF8Bytes's content buffer.
  25. /// </summary>
  26. /// <param name="newLength">The new length in bytes of the IUTF8Bytes's content buffer.</param>
  27. /// <param name="clearOptions">Whether any bytes added should be zeroed out.</param>
  28. /// <returns>True if the new length is valid.</returns>
  29. bool TryResize(int newLength, NativeArrayOptions clearOptions = NativeArrayOptions.ClearMemory);
  30. }
  31. [GenerateTestsForBurstCompatibility]
  32. internal unsafe static class FixedStringUtils
  33. {
  34. [StructLayout(LayoutKind.Explicit)]
  35. internal struct UintFloatUnion
  36. {
  37. [FieldOffset(0)]
  38. public uint uintValue;
  39. [FieldOffset(0)]
  40. public float floatValue;
  41. }
  42. internal static ParseError Base10ToBase2(ref float output, ulong mantissa10, int exponent10)
  43. {
  44. if (mantissa10 == 0)
  45. {
  46. output = 0.0f;
  47. return ParseError.None;
  48. }
  49. if (exponent10 == 0)
  50. {
  51. output = mantissa10;
  52. return ParseError.None;
  53. }
  54. var exponent2 = exponent10;
  55. var mantissa2 = mantissa10;
  56. while (exponent10 > 0)
  57. {
  58. while ((mantissa2 & 0xe000000000000000U) != 0)
  59. {
  60. mantissa2 >>= 1;
  61. ++exponent2;
  62. }
  63. mantissa2 *= 5;
  64. --exponent10;
  65. }
  66. while (exponent10 < 0)
  67. {
  68. while ((mantissa2 & 0x8000000000000000U) == 0)
  69. {
  70. mantissa2 <<= 1;
  71. --exponent2;
  72. }
  73. mantissa2 /= 5;
  74. ++exponent10;
  75. }
  76. // TODO: implement math.ldexpf (which presumably handles denormals (i don't))
  77. UintFloatUnion ufu = new UintFloatUnion();
  78. ufu.floatValue = mantissa2;
  79. var e = (int)((ufu.uintValue >> 23) & 0xFFU) - 127;
  80. e += exponent2;
  81. if (e > 128)
  82. return ParseError.Overflow;
  83. if (e < -127)
  84. return ParseError.Underflow;
  85. ufu.uintValue = (ufu.uintValue & ~(0xFFU << 23)) | ((uint)(e + 127) << 23);
  86. output = ufu.floatValue;
  87. return ParseError.None;
  88. }
  89. internal static void Base2ToBase10(ref ulong mantissa10, ref int exponent10, float input)
  90. {
  91. UintFloatUnion ufu = new UintFloatUnion();
  92. ufu.floatValue = input;
  93. if (ufu.uintValue == 0)
  94. {
  95. mantissa10 = 0;
  96. exponent10 = 0;
  97. return;
  98. }
  99. var mantissa2 = (ufu.uintValue & ((1 << 23) - 1)) | (1 << 23);
  100. var exponent2 = (int)(ufu.uintValue >> 23) - 127 - 23;
  101. mantissa10 = mantissa2;
  102. exponent10 = exponent2;
  103. if (exponent2 > 0)
  104. {
  105. while (exponent2 > 0)
  106. {
  107. // denormalize mantissa10 as much as you can, to minimize loss when doing /5 below.
  108. while (mantissa10 <= UInt64.MaxValue / 10)
  109. {
  110. mantissa10 *= 10;
  111. --exponent10;
  112. }
  113. mantissa10 /= 5;
  114. --exponent2;
  115. }
  116. }
  117. if (exponent2 < 0)
  118. {
  119. while (exponent2 < 0)
  120. {
  121. // normalize mantissa10 just as much as you need, in order to make the *5 below not overflow.
  122. while (mantissa10 > UInt64.MaxValue / 5)
  123. {
  124. mantissa10 /= 10;
  125. ++exponent10;
  126. }
  127. mantissa10 *= 5;
  128. ++exponent2;
  129. }
  130. }
  131. // normalize mantissa10
  132. while (mantissa10 > 9999999U || mantissa10 % 10 == 0)
  133. {
  134. mantissa10 = (mantissa10 + (mantissa10 < 100000000U ? 5u : 0u)) / 10;
  135. ++exponent10;
  136. }
  137. }
  138. }
  139. }