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);
}
}
}