ln.bson/ln.bson.storage/index/BsonIndex.cs

155 lines
4.9 KiB
C#

using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using ln.collections;
namespace ln.bson.storage.index
{
public delegate int BsonCompareDelegate(byte[] a, byte[] b);
public class BsonIndex : IBsonIndex
{
private BTreeValueSet<byte[], long> _lookup;
private BTreeValueList<long, byte[]> _reverse = new BTreeValueList<long, byte[]>();
public BsonIndex() : this(CompareBytesLittleEndian) { }
public BsonIndex(Comparison<byte[]> compareDelegate)
{
_lookup = new BTreeValueSet<byte[], long>(compareDelegate);
}
public void AddValue(long key, BsonValue bsonValue) => AddValue(key, bsonValue.GetBytes());
public void AddValue(long key, byte[] value)
{
if (_reverse.TryAdd(key, value))
{
if (_lookup.TryAdd(value, key))
return;
_reverse.TryRemove(key, value);
}
throw new ArgumentOutOfRangeException();
}
public void RemoveValue(long key)
{
if (_reverse.TryGet(key, out IEnumerable<byte[]> values))
{
foreach (var value in values)
{
if (!_lookup.TryRemove(value, key))
throw new InvalidOperationException();
}
_reverse.TryRemove(key);
return;
}
throw new ArgumentOutOfRangeException();
}
public void ReplaceValue(long oldKey, long newKey, BsonValue newValue)
{
AddValue(newKey, newValue);
RemoveValue(oldKey);
}
public void Clear()
{
_lookup.Clear();
_reverse.Clear();
}
public void Query(QueryOperator queryOperator, byte[] value, ISet<long> resultSet)
{
IEnumerable<KeyValuePair<byte[], long>> enumeration;
switch (queryOperator)
{
case QueryOperator.EQUAL:
enumeration = _lookup.GetInterval(value, value);
break;
case QueryOperator.EQUAL | QueryOperator.LESS:
enumeration = _lookup.GetInterval(null, value);
break;
case QueryOperator.EQUAL | QueryOperator.GREATER:
enumeration = _lookup.GetInterval(value, null);
break;
case QueryOperator.LESS:
enumeration = _lookup.GetInterval(null, value, (k,v)=>_lookup.Comparison(k,value) < 0);
break;
case QueryOperator.GREATER:
enumeration = _lookup.GetInterval(value, null, (k,v)=>_lookup.Comparison(k,value) > 0);
break;
case QueryOperator.IN:
// ToDo: Implementation
throw new NotSupportedException();
default:
throw new NotSupportedException();
}
resultSet.UnionWith(enumeration.Select(x => x.Value));
}
public static int CompareBytesBigEndian(byte[] a, byte[] b)
{
int cntBytes = a.Length > b.Length ? a.Length : b.Length;
int pa = a.Length - cntBytes;
int pb = b.Length - cntBytes;
while ((pa < a.Length) || (pb < b.Length))
{
pa++;
pb++;
int va = (pa < 0) ? 0 : a[pa];
int vb = (pb < 0) ? 0 : b[pb];
int d = va - vb;
if (d != 0)
return d;
}
return 0;
}
public static int CompareBytesLittleEndian(byte[] a, byte[] b)
{
int cntBytes = a.Length > b.Length ? a.Length : b.Length;
int pa = a.Length;
int pb = b.Length;
while ((pa > 0) || (pb > 0))
{
pa--;
pb--;
int va = (pa >= a.Length) ? 0 : a[pa];
int vb = (pb >= b.Length) ? 0 : b[pb];
int d = va - vb;
if (d != 0)
return d;
}
return 0;
}
public static int CompareBytesLinear(byte[] a, byte[] b)
{
int cntBytes = a.Length > b.Length ? a.Length : b.Length;
int p = 0;
while (p < cntBytes)
{
int va = (p >= a.Length) ? -1 : a[p];
int vb = (p >= b.Length) ? -1 : b[p];
int d = va - vb;
if (d != 0)
return d;
p++;
}
return 0;
}
public IEnumerator<KeyValuePair<long, byte[]>> GetEnumerator() => _reverse.GetEnumerator();
IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
}
}