63 lines
1.8 KiB
C#
63 lines
1.8 KiB
C#
|
|
namespace PersistentOrderedMap;
|
|
|
|
using System;
|
|
using System.Buffers.Binary;
|
|
using System.Runtime.CompilerServices;
|
|
|
|
public interface IKeyStrategy<in TK>
|
|
{
|
|
int Compare(TK x, TK y);
|
|
long GetPrefix(TK key);
|
|
|
|
bool UsesPrefixes => true;
|
|
|
|
bool IsLossless => false;
|
|
bool UseBinarySearch => false;
|
|
}
|
|
|
|
|
|
|
|
|
|
public struct UnicodeStrategy : IKeyStrategy<string>
|
|
{
|
|
|
|
public bool UsesPrefixes => true;
|
|
public bool UseBinarySearch => false;
|
|
public bool IsLossLess => false;
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
public int Compare(string? x, string? y) => string.CompareOrdinal(x, y);
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
public long GetPrefix(string key)
|
|
{
|
|
if (string.IsNullOrEmpty(key)) return long.MinValue;
|
|
|
|
// 1. Prepare Buffer (8 bytes)
|
|
// stackalloc is virtually free (pointer bump)
|
|
Span<byte> utf8Bytes = stackalloc byte[8];
|
|
|
|
// 2. Transcode (The "Safe" Magic)
|
|
// This intrinsic handles ASCII efficiently and converts Surrogates/Chinese
|
|
// into bytes that maintain the correct "Magnitude" (Sort Order).
|
|
// Invalid surrogates become 0xEF (Replacement Char), which sorts > ASCII.
|
|
System.Text.Unicode.Utf8.FromUtf16(
|
|
key.AsSpan(0, Math.Min(key.Length, 8)),
|
|
utf8Bytes,
|
|
out _,
|
|
out _,
|
|
replaceInvalidSequences: true); // True ensures we get 0xEF for broken chars
|
|
|
|
// 3. Load as Big Endian Long
|
|
long packed = BinaryPrimitives.ReadInt64BigEndian(utf8Bytes);
|
|
|
|
// 4. Sign Toggle
|
|
// Maps the byte range 0x00..0xFF to the signed long range Min..Max
|
|
// Essential for the < and > operators to work correctly.
|
|
return packed ^ unchecked((long)0x8080808080808080);
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|