155 lines
4.9 KiB
C#
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();
|
|
}
|
|
} |