Skip to content

Instantly share code, notes, and snippets.

@jcdickinson
Created February 28, 2013 15:36
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
Star You must be signed in to star a gist
Save jcdickinson/5057605 to your computer and use it in GitHub Desktop.
Byte keys for RaptorDB
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.InteropServices;
using System.Security;
using System.Text;
namespace RaptorDB
{
public sealed class ByteKey : IComparable<ByteKey>
{
[SuppressUnmanagedCodeSecurity]
private static class NativeMethods
{
[DllImport("msvcrt.dll", CallingConvention = CallingConvention.Cdecl)]
public static extern int memcmp(byte[] b1, byte[] b2, long count);
}
public readonly byte[] Data;
public readonly int Hash;
private static readonly MurmurHash2Unsafe _murmur = new MurmurHash2Unsafe();
public ByteKey(byte[] data)
{
if (data == null) throw new ArgumentNullException("data");
Data = data;
Hash = (int)_murmur.Hash(Data);
}
public ByteKey(byte[] buffer, int offset, int count)
{
if (buffer == null) throw new ArgumentNullException("data");
if (offset + count > buffer.Length) throw new ArgumentOutOfRangeException("offset");
if (offset < 0) throw new ArgumentOutOfRangeException("offset");
Data = new byte[count];
Buffer.BlockCopy(buffer, offset, Data, 0, count);
Hash = (int)_murmur.Hash(Data);
}
public int CompareTo(ByteKey other)
{
if (other == null) throw new ArgumentNullException("other");
// Do some basic comparisons first to avoid unessecary
// pinvoke cost.
if (object.ReferenceEquals(Data, other.Data)) return 0;
else if (Data.Length == 0 && other.Data.Length == 0) return 0;
else if (Data.Length == 0) return -1;
else if (other.Data.Length == 0) return 1;
else if (Data[0] < other.Data[0]) return -1;
else if (Data[0] > other.Data[0]) return 1;
var cmpResult = NativeMethods.memcmp(Data, other.Data, Math.Min(Data.Length, other.Data.Length));
if (cmpResult == 0)
{
if (Data.Length < other.Data.Length) return -1;
else if (Data.Length > other.Data.Length) return 1;
}
return cmpResult;
}
public override int GetHashCode()
{
return Hash;
}
public override bool Equals(object obj)
{
return this.CompareTo(obj as ByteKey) == 0;
}
public static implicit operator byte[](ByteKey key)
{
if (key == null) return null;
return key.Data;
}
public static implicit operator ByteKey(byte[] key)
{
if (key == null) return null;
return new ByteKey(key);
}
public static implicit operator ArraySegment<byte>(ByteKey key)
{
if (key == null) return default(ArraySegment<byte>);
return new ArraySegment<byte>(key.Data, 0, key.Data.Length);
}
public static implicit operator ByteKey(ArraySegment<byte> key)
{
if (key.Array == null) return null;
return new ByteKey(key.Array, key.Offset, key.Count);
}
}
}
// Additions
internal class RDBDataType<T>
{
public static IGetBytes<T> ByteHandler()
{
// ...
else if (type == typeof(ByteKey)) return (IGetBytes<T>)new ByteKey_handler<T>();
// ...
}
public static byte GetByteSize(byte keysize)
{
// ...
if (t == typeof(ByteKey)) size = keysize;
// ...
}
internal static object GetEmpty()
{
// ...
if (t == typeof(ByteKey))
return new ByteKey(new byte[0]);
// ...
}
}
internal class ByteKey_handler<T> : IGetBytes<ByteKey>
{
public byte[] GetBytes(ByteKey obj)
{
var copy = new byte[obj.Data.Length];
Buffer.BlockCopy(obj.Data, 0, copy, 0, obj.Data.Length);
return copy;
}
public ByteKey GetObject(byte[] buffer, int offset, int count)
{
return new ByteKey(buffer, offset, count);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment