RoutingKey.cs 5.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182
  1. using System;
  2. namespace NetMQ
  3. {
  4. /// <summary>
  5. /// Structure to represent a routing key from Router, Peer and Stream sockets.
  6. /// Implement Equals and GetHashCode and can be used as key for a Dictionary.
  7. /// </summary>
  8. public readonly struct RoutingKey : IEquatable<RoutingKey>, IEquatable<byte[]>
  9. {
  10. private readonly byte[] bytes;
  11. private const uint C1 = 0xcc9e2d51;
  12. private const uint C2 = 0x1b873593;
  13. /// <summary>
  14. /// Create a new routing key out of a byte array
  15. /// </summary>
  16. /// <param name="array"></param>
  17. public RoutingKey(byte[] array)
  18. {
  19. bytes = array;
  20. }
  21. /// <summary>
  22. /// Create a new routing key out of a base64 string
  23. /// </summary>
  24. /// <param name="b64"></param>
  25. public RoutingKey(string b64)
  26. {
  27. bytes = Convert.FromBase64String(b64);
  28. }
  29. /// <summary>
  30. /// Create a new routing key out of a Int64
  31. /// </summary>
  32. /// <param name="value"></param>
  33. public RoutingKey(long value)
  34. {
  35. bytes = NetworkOrderBitsConverter.GetBytes(value);
  36. }
  37. internal byte[] Bytes
  38. {
  39. get { return bytes; }
  40. }
  41. /// <summary>
  42. /// Check if routing-key is equal to the object
  43. /// </summary>
  44. /// <param name="obj">Object to compare against, valid types are byte-array and RoutingKey</param>
  45. /// <returns>True if equals, otherwise false</returns>
  46. public override bool Equals(object obj)
  47. {
  48. if (obj is RoutingKey)
  49. return Equals((RoutingKey) obj);
  50. if (obj is byte[])
  51. return Equals((byte[])obj);
  52. return false;
  53. }
  54. /// <summary>
  55. /// Check if routing-key is equal to the byte-array
  56. /// </summary>
  57. /// <param name="x">Byte-array to compare against</param>
  58. /// <returns>True if equals, otherwise false</returns>
  59. public bool Equals(byte[] x)
  60. {
  61. if (bytes.Length != x.Length)
  62. {
  63. return false;
  64. }
  65. for (int i = 0; i < bytes.Length; i++)
  66. {
  67. if (bytes[i] != x[i])
  68. {
  69. return false;
  70. }
  71. }
  72. return true;
  73. }
  74. /// <summary>
  75. /// Check if routing-key is equal to another routing-key
  76. /// </summary>
  77. /// <param name="x">Other routing key to check against</param>
  78. /// <returns>True if equals, otherwise false</returns>
  79. public bool Equals(RoutingKey x)
  80. {
  81. if (bytes.Length != x.bytes.Length)
  82. {
  83. return false;
  84. }
  85. for (int i = 0; i < bytes.Length; i++)
  86. {
  87. if (bytes[i] != x.bytes[i])
  88. {
  89. return false;
  90. }
  91. }
  92. return true;
  93. }
  94. /// <summary>
  95. /// Return a numeric hashcode of the given byte-array.
  96. /// </summary>
  97. /// <returns>an integer that contains a hashcode computed over the byte-array</returns>
  98. public override int GetHashCode()
  99. {
  100. unchecked
  101. {
  102. int remainder = bytes.Length & 3;
  103. int alignedLength = bytes.Length - remainder;
  104. uint hash = 0;
  105. // Walk through data four bytes at a time
  106. for (int i = 0; i < alignedLength; i += 4)
  107. {
  108. var k = (uint)(bytes[i] | bytes[i + 1] << 8 | bytes[i + 2] << 16 | bytes[i + 3] << 24);
  109. k *= C1;
  110. k = (k << 15) | (k >> (32 - 15));
  111. k *= C2;
  112. hash ^= k;
  113. hash = (hash << 13) | (hash >> (32 - 13));
  114. hash = (hash * 5) + 0xe6546b64;
  115. }
  116. // Deal with the one, two or three leftover bytes
  117. if (remainder > 0)
  118. {
  119. uint k = 0;
  120. // determine how many bytes we have left to work with based on length
  121. switch (remainder)
  122. {
  123. case 3:
  124. k ^= (uint)bytes[alignedLength + 2] << 16;
  125. goto case 2;
  126. case 2:
  127. k ^= (uint)bytes[alignedLength + 1] << 8;
  128. goto case 1;
  129. case 1:
  130. k ^= bytes[alignedLength];
  131. break;
  132. }
  133. k *= C1;
  134. k = (k << 15) | (k >> (32 - 15));
  135. k *= C2;
  136. hash ^= k;
  137. }
  138. hash ^= (uint)bytes.Length;
  139. hash ^= hash >> 16;
  140. hash *= 0x85ebca6b;
  141. hash ^= hash >> 13;
  142. hash *= 0xc2b2ae35;
  143. hash ^= hash >> 16;
  144. return (int)hash;
  145. }
  146. }
  147. /// <summary>
  148. /// Convert the routing-key to base64 string
  149. /// </summary>
  150. /// <returns>Base64 string representation of the routing-key</returns>
  151. public override string ToString()
  152. {
  153. return Convert.ToBase64String(bytes);
  154. }
  155. }
  156. }