Skip to content

Commit 15018c5

Browse files
committed
Added default comparer options for optimized usage
1 parent 0dc368d commit 15018c5

13 files changed

+787
-0
lines changed

src/LightningDB.Tests/ComparerTests.cs

Lines changed: 465 additions & 0 deletions
Large diffs are not rendered by default.
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
using System;
2+
using System.Collections.Generic;
3+
4+
namespace LightningDB.Comparers;
5+
6+
/// <summary>
7+
/// Compares MDBValue instances using lexicographic byte comparison (memcmp-style).
8+
/// </summary>
9+
public sealed class BitwiseComparer : IComparer<MDBValue>
10+
{
11+
public static readonly BitwiseComparer Instance = new();
12+
13+
private BitwiseComparer() { }
14+
15+
public int Compare(MDBValue x, MDBValue y)
16+
=> x.AsSpan().SequenceCompareTo(y.AsSpan());
17+
}
Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
using System;
2+
using System.Collections.Generic;
3+
#if !NET6_0_OR_GREATER
4+
using System.Runtime.InteropServices;
5+
#endif
6+
7+
namespace LightningDB.Comparers;
8+
9+
/// <summary>
10+
/// Compares MDBValue instances by hash code for faster comparison of large values.
11+
/// Falls back to byte comparison when hashes collide.
12+
/// Sort order is deterministic within a process but may vary across restarts.
13+
/// </summary>
14+
public sealed class HashCodeComparer : IComparer<MDBValue>
15+
{
16+
public static readonly HashCodeComparer Instance = new();
17+
18+
private HashCodeComparer() { }
19+
20+
public int Compare(MDBValue x, MDBValue y)
21+
{
22+
var left = x.AsSpan();
23+
var right = y.AsSpan();
24+
25+
var leftHash = ComputeHash(left);
26+
var rightHash = ComputeHash(right);
27+
28+
var hashCmp = leftHash.CompareTo(rightHash);
29+
return hashCmp != 0 ? hashCmp : left.SequenceCompareTo(right);
30+
}
31+
32+
#if NET6_0_OR_GREATER
33+
private static int ComputeHash(ReadOnlySpan<byte> data)
34+
{
35+
var hc = new HashCode();
36+
hc.AddBytes(data);
37+
return hc.ToHashCode();
38+
}
39+
#else
40+
private static ulong ComputeHash(ReadOnlySpan<byte> data)
41+
{
42+
const ulong prime = 0x9E3779B97F4A7C15UL;
43+
var hash = (ulong)data.Length;
44+
45+
while (data.Length >= 8)
46+
{
47+
hash ^= MemoryMarshal.Read<ulong>(data);
48+
hash *= prime;
49+
hash ^= hash >> 32;
50+
data = data.Slice(8);
51+
}
52+
53+
if (data.Length >= 4)
54+
{
55+
hash ^= MemoryMarshal.Read<uint>(data);
56+
hash *= prime;
57+
data = data.Slice(4);
58+
}
59+
60+
foreach (var b in data)
61+
{
62+
hash ^= b;
63+
hash *= prime;
64+
}
65+
66+
return hash;
67+
}
68+
#endif
69+
}
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
using System;
2+
using System.Collections.Generic;
3+
4+
namespace LightningDB.Comparers;
5+
6+
/// <summary>
7+
/// Compares MDBValue instances by length first, then by content.
8+
/// Shorter values sort before longer values.
9+
/// </summary>
10+
public sealed class LengthComparer : IComparer<MDBValue>
11+
{
12+
public static readonly LengthComparer Instance = new();
13+
14+
private LengthComparer() { }
15+
16+
public int Compare(MDBValue x, MDBValue y)
17+
{
18+
var left = x.AsSpan();
19+
var right = y.AsSpan();
20+
var lengthCmp = left.Length.CompareTo(right.Length);
21+
return lengthCmp != 0 ? lengthCmp : left.SequenceCompareTo(right);
22+
}
23+
}
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
using System.Collections.Generic;
2+
3+
namespace LightningDB.Comparers;
4+
5+
/// <summary>
6+
/// Compares MDBValue instances by length only, ignoring content.
7+
/// Values of equal length are considered equal regardless of content.
8+
/// </summary>
9+
public sealed class LengthOnlyComparer : IComparer<MDBValue>
10+
{
11+
public static readonly LengthOnlyComparer Instance = new();
12+
13+
private LengthOnlyComparer() { }
14+
15+
public int Compare(MDBValue x, MDBValue y)
16+
=> x.AsSpan().Length.CompareTo(y.AsSpan().Length);
17+
}
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
using System;
2+
using System.Collections.Generic;
3+
4+
namespace LightningDB.Comparers;
5+
6+
/// <summary>
7+
/// Compares MDBValue instances using lexicographic byte comparison in descending order.
8+
/// </summary>
9+
public sealed class ReverseBitwiseComparer : IComparer<MDBValue>
10+
{
11+
public static readonly ReverseBitwiseComparer Instance = new();
12+
13+
private ReverseBitwiseComparer() { }
14+
15+
public int Compare(MDBValue x, MDBValue y)
16+
=> y.AsSpan().SequenceCompareTo(x.AsSpan());
17+
}
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
using System;
2+
using System.Collections.Generic;
3+
4+
namespace LightningDB.Comparers;
5+
6+
/// <summary>
7+
/// Compares MDBValue instances by length first (descending), then by content (descending).
8+
/// Longer values sort before shorter values.
9+
/// </summary>
10+
public sealed class ReverseLengthComparer : IComparer<MDBValue>
11+
{
12+
public static readonly ReverseLengthComparer Instance = new();
13+
14+
private ReverseLengthComparer() { }
15+
16+
public int Compare(MDBValue x, MDBValue y)
17+
{
18+
var left = x.AsSpan();
19+
var right = y.AsSpan();
20+
var lengthCmp = right.Length.CompareTo(left.Length);
21+
return lengthCmp != 0 ? lengthCmp : right.SequenceCompareTo(left);
22+
}
23+
}
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using System.Runtime.InteropServices;
4+
5+
namespace LightningDB.Comparers;
6+
7+
/// <summary>
8+
/// Compares MDBValue instances as signed integers (int or long) in descending order.
9+
/// Supports 4-byte and 8-byte values. Falls back to reverse bitwise comparison for other sizes.
10+
/// </summary>
11+
public sealed class ReverseSignedIntegerComparer : IComparer<MDBValue>
12+
{
13+
public static readonly ReverseSignedIntegerComparer Instance = new();
14+
15+
private ReverseSignedIntegerComparer() { }
16+
17+
public int Compare(MDBValue x, MDBValue y)
18+
{
19+
var left = x.AsSpan();
20+
var right = y.AsSpan();
21+
22+
if (left.Length == 4 && right.Length == 4)
23+
return MemoryMarshal.Read<int>(right).CompareTo(MemoryMarshal.Read<int>(left));
24+
25+
if (left.Length == 8 && right.Length == 8)
26+
return MemoryMarshal.Read<long>(right).CompareTo(MemoryMarshal.Read<long>(left));
27+
28+
return right.SequenceCompareTo(left);
29+
}
30+
}
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using System.Runtime.InteropServices;
4+
5+
namespace LightningDB.Comparers;
6+
7+
/// <summary>
8+
/// Compares MDBValue instances as unsigned integers (uint or ulong) in descending order.
9+
/// Supports 4-byte and 8-byte values. Falls back to reverse bitwise comparison for other sizes.
10+
/// </summary>
11+
public sealed class ReverseUnsignedIntegerComparer : IComparer<MDBValue>
12+
{
13+
public static readonly ReverseUnsignedIntegerComparer Instance = new();
14+
15+
private ReverseUnsignedIntegerComparer() { }
16+
17+
public int Compare(MDBValue x, MDBValue y)
18+
{
19+
var left = x.AsSpan();
20+
var right = y.AsSpan();
21+
22+
if (left.Length == 4 && right.Length == 4)
23+
return MemoryMarshal.Read<uint>(right).CompareTo(MemoryMarshal.Read<uint>(left));
24+
25+
if (left.Length == 8 && right.Length == 8)
26+
return MemoryMarshal.Read<ulong>(right).CompareTo(MemoryMarshal.Read<ulong>(left));
27+
28+
return right.SequenceCompareTo(left);
29+
}
30+
}
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
using System;
2+
using System.Collections.Generic;
3+
4+
namespace LightningDB.Comparers;
5+
6+
/// <summary>
7+
/// Compares MDBValue instances as UTF-8 encoded strings in descending order.
8+
/// </summary>
9+
public sealed class ReverseUtf8StringComparer : IComparer<MDBValue>
10+
{
11+
public static readonly ReverseUtf8StringComparer Instance = new();
12+
13+
private ReverseUtf8StringComparer() { }
14+
15+
public int Compare(MDBValue x, MDBValue y)
16+
=> y.AsSpan().SequenceCompareTo(x.AsSpan());
17+
}

0 commit comments

Comments
 (0)