Extensions.cs 3.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102
  1. using System;
  2. using System.Collections.Concurrent;
  3. using System.Collections.Generic;
  4. using System.Runtime.CompilerServices;
  5. namespace Mirror
  6. {
  7. public static class Extensions
  8. {
  9. public static string ToHexString(this ArraySegment<byte> segment) =>
  10. BitConverter.ToString(segment.Array, segment.Offset, segment.Count);
  11. // string.GetHashCode is not guaranteed to be the same on all
  12. // machines, but we need one that is the same on all machines.
  13. // Uses fnv1a as hash function for more uniform distribution http://www.isthe.com/chongo/tech/comp/fnv/
  14. // Tests: https://softwareengineering.stackexchange.com/questions/49550/which-hashing-algorithm-is-best-for-uniqueness-and-speed
  15. // NOTE: Do not call this from hot path because it's slow O(N) for long method names.
  16. // - As of 2012-02-16 There are 2 design-time callers (weaver) and 1 runtime caller that caches.
  17. public static int GetStableHashCode(this string text)
  18. {
  19. unchecked
  20. {
  21. uint hash = 0x811c9dc5;
  22. uint prime = 0x1000193;
  23. for (int i = 0; i < text.Length; ++i)
  24. {
  25. byte value = (byte)text[i];
  26. hash = hash ^ value;
  27. hash *= prime;
  28. }
  29. //UnityEngine.Debug.Log($"Created stable hash {(ushort)hash} for {text}");
  30. return (int)hash;
  31. }
  32. }
  33. // smaller version of our GetStableHashCode.
  34. // careful, this significantly increases chance of collisions.
  35. public static ushort GetStableHashCode16(this string text)
  36. {
  37. // deterministic hash
  38. int hash = GetStableHashCode(text);
  39. // Gets the 32bit fnv1a hash
  40. // To get it down to 16bit but still reduce hash collisions we cant just cast it to ushort
  41. // Instead we take the highest 16bits of the 32bit hash and fold them with xor into the lower 16bits
  42. // This will create a more uniform 16bit hash, the method is described in:
  43. // http://www.isthe.com/chongo/tech/comp/fnv/ in section "Changing the FNV hash size - xor-folding"
  44. return (ushort)((hash >> 16) ^ hash);
  45. }
  46. // previously in DotnetCompatibility.cs
  47. // leftover from the UNET days. supposedly for windows store?
  48. internal static string GetMethodName(this Delegate func)
  49. {
  50. #if NETFX_CORE
  51. return func.GetMethodInfo().Name;
  52. #else
  53. return func.Method.Name;
  54. #endif
  55. }
  56. // helper function to copy to List<T>
  57. // C# only provides CopyTo(T[])
  58. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  59. public static void CopyTo<T>(this IEnumerable<T> source, List<T> destination)
  60. {
  61. // foreach allocates. use AddRange.
  62. destination.AddRange(source);
  63. }
  64. #if !UNITY_2021_OR_NEWER
  65. // Unity 2020 and earlier don't have Queue.TryDequeue which we need for batching.
  66. public static bool TryDequeue<T>(this Queue<T> source, out T element)
  67. {
  68. if (source.Count > 0)
  69. {
  70. element = source.Dequeue();
  71. return true;
  72. }
  73. element = default;
  74. return false;
  75. }
  76. #endif
  77. #if !UNITY_2021_OR_NEWER
  78. // Unity 2020 and earlier don't have ConcurrentQueue.Clear which we need for ThreadedTransport.
  79. public static void Clear<T>(this ConcurrentQueue<T> source)
  80. {
  81. // while count > 0 risks deadlock if other thread write at the same time.
  82. // our safest solution is a best-effort approach to clear 'Count' once.
  83. int count = source.Count; // get it only once
  84. for (int i = 0; i < count; ++i)
  85. {
  86. source.TryDequeue(out _);
  87. }
  88. }
  89. #endif
  90. }
  91. }