using System; namespace NetMQ { /// /// Structure to represent a routing key from Router, Peer and Stream sockets. /// Implement Equals and GetHashCode and can be used as key for a Dictionary. /// public readonly struct RoutingKey : IEquatable, IEquatable { private readonly byte[] bytes; private const uint C1 = 0xcc9e2d51; private const uint C2 = 0x1b873593; /// /// Create a new routing key out of a byte array /// /// public RoutingKey(byte[] array) { bytes = array; } /// /// Create a new routing key out of a base64 string /// /// public RoutingKey(string b64) { bytes = Convert.FromBase64String(b64); } /// /// Create a new routing key out of a Int64 /// /// public RoutingKey(long value) { bytes = NetworkOrderBitsConverter.GetBytes(value); } internal byte[] Bytes { get { return bytes; } } /// /// Check if routing-key is equal to the object /// /// Object to compare against, valid types are byte-array and RoutingKey /// True if equals, otherwise false public override bool Equals(object obj) { if (obj is RoutingKey) return Equals((RoutingKey) obj); if (obj is byte[]) return Equals((byte[])obj); return false; } /// /// Check if routing-key is equal to the byte-array /// /// Byte-array to compare against /// True if equals, otherwise false public bool Equals(byte[] x) { if (bytes.Length != x.Length) { return false; } for (int i = 0; i < bytes.Length; i++) { if (bytes[i] != x[i]) { return false; } } return true; } /// /// Check if routing-key is equal to another routing-key /// /// Other routing key to check against /// True if equals, otherwise false public bool Equals(RoutingKey x) { if (bytes.Length != x.bytes.Length) { return false; } for (int i = 0; i < bytes.Length; i++) { if (bytes[i] != x.bytes[i]) { return false; } } return true; } /// /// Return a numeric hashcode of the given byte-array. /// /// an integer that contains a hashcode computed over the byte-array public override int GetHashCode() { unchecked { int remainder = bytes.Length & 3; int alignedLength = bytes.Length - remainder; uint hash = 0; // Walk through data four bytes at a time for (int i = 0; i < alignedLength; i += 4) { var k = (uint)(bytes[i] | bytes[i + 1] << 8 | bytes[i + 2] << 16 | bytes[i + 3] << 24); k *= C1; k = (k << 15) | (k >> (32 - 15)); k *= C2; hash ^= k; hash = (hash << 13) | (hash >> (32 - 13)); hash = (hash * 5) + 0xe6546b64; } // Deal with the one, two or three leftover bytes if (remainder > 0) { uint k = 0; // determine how many bytes we have left to work with based on length switch (remainder) { case 3: k ^= (uint)bytes[alignedLength + 2] << 16; goto case 2; case 2: k ^= (uint)bytes[alignedLength + 1] << 8; goto case 1; case 1: k ^= bytes[alignedLength]; break; } k *= C1; k = (k << 15) | (k >> (32 - 15)); k *= C2; hash ^= k; } hash ^= (uint)bytes.Length; hash ^= hash >> 16; hash *= 0x85ebca6b; hash ^= hash >> 13; hash *= 0xc2b2ae35; hash ^= hash >> 16; return (int)hash; } } /// /// Convert the routing-key to base64 string /// /// Base64 string representation of the routing-key public override string ToString() { return Convert.ToBase64String(bytes); } } }