/// Handle.cs
/// Hashed handle reference.
///
/// Copyright (c) 2010 Eric Itomura
///
/// This software is provided 'as-is', without any express or implied
/// warranty. In no event will the authors be held liable for any damages
/// arising from the use of this software.
///
/// Permission is granted to anyone to use this software for any purpose,
/// including commercial applications, and to alter it and redistribute it
/// freely.
#if DEBUG
#define HANDLEVERIFY
#endif
using System;
using System.Diagnostics;
using System.Collections.Generic;
namespace ProjectB
{
///
/// Handle is a string reference with basic type safety. It uses a case insensitive
/// quick hash algorithm (fnv1a http://www.isthe.com/chongo/tech/comp/fnv/index.html)
///
/// The type value is only used for type checking
/// and excluding cross type name collisions.
public struct Handle : IEquatable>
{
public static readonly HandleComparer Comparer = new HandleComparer();
public uint ID;
#if HANDLEVERIFY
public string DebugString;
public uint IDVerify;
#endif
public Handle(string name)
{
Debug.Assert(name != null);
uint hash = 2166136261;
int charCount = name.Length;
for (int i = 0; i < charCount; ++i)
{
char c = char.ToLowerInvariant(name[i]);
hash = hash ^ c;
hash = hash * 16777619;
}
ID = hash;
#if HANDLEVERIFY
DebugString = name;
for (int i = 0; i < charCount; ++i)
{
char c = char.ToLowerInvariant(name[i]);
hash = hash ^ c;
hash = hash * 16777619;
}
IDVerify = hash;
#endif
}
public Handle(uint prehash)
{
ID = prehash;
#if HANDLEVERIFY
DebugString = null;
IDVerify = 0;
#endif
}
public override string ToString()
{
var id = " id" + ID;
#if HANDLEVERIFY
id += " " + DebugString;
#endif
return typeof(T).ToString() + id;
}
public static bool operator ==(Handle a, Handle b)
{
Handle.VerifyNoHashCollision(a, b);
return a.ID == b.ID;
}
public static bool operator !=(Handle a, Handle b)
{
Handle.VerifyNoHashCollision(a, b);
return a.ID != b.ID;
}
public bool Equals(Handle handle)
{
Handle.VerifyNoHashCollision(this, handle);
return ID == handle.ID;
}
public override bool Equals(Object o)
{
return o != null && GetHashCode() == (uint)o.GetHashCode();
}
public override int GetHashCode()
{
return (int)ID;
}
public bool IsValid()
{
return ID != 0;
}
[Conditional("HANDLEVERIFY")]
public static void VerifyNoHashCollision(Handle a, Handle b)
{
#if HANDLEVERIFY
Debug.Assert(a.ID != b.ID || a.IDVerify == b.IDVerify || a.IDVerify * b.IDVerify == 0);
#endif
}
}
public class HandleComparer : EqualityComparer>
{
public override bool Equals(Handle a, Handle b)
{
Handle.VerifyNoHashCollision(a, b);
return a.ID == b.ID;
}
public override int GetHashCode(Handle handle)
{
return (int)handle.ID;
}
}
}