private long KeyToLong(TRowKey key) { // ReSharper disable once ImpureMethodCallOnReadonlyValueField return(_comparer.Diff(key, default(TRowKey))); }
internal static int InterpolationSearchGeneric <T>(ref T searchSpace, int offset, int length, T value, KeyComparer <T> comparer = default) { // Try interpolation only for big-enough lengths and do minimal job, // just find the range with exponential search with minimal branches // and switch to binary search. unchecked { int i; int lo = offset; int hi = offset + length - 1; if (hi - lo > 16) { var vlo = UnsafeEx.ReadUnaligned(ref searchSpace); var vhi = UnsafeEx.ReadUnaligned(ref Unsafe.Add(ref searchSpace, hi)); int range = hi - lo; long vRange = comparer.Diff(vhi, vlo); // (hi - lo) <= int32.MaxValue // vlo could be zero while value could easily be close to int64.MaxValue (nanos in unix time, we are now between 60 and 61 bit at 60.4) // convert to double here to avoid overflow and for much faster calculations // (only 4 cycles vs 25 cycles https://lemire.me/blog/2017/11/16/fast-exact-integer-divisions-using-floating-point-operations/) double nominator = (hi - lo) * (double)comparer.Diff(value, vlo); i = (int)(nominator / vRange); if ((uint)i > range) { i = i < 0 ? 0 : range; } // make i relative to vecStart i += lo; int c = comparer.Compare(value, UnsafeEx.ReadUnaligned(ref Unsafe.Add(ref searchSpace, i))); if (c == 0) { goto FOUND; } var step = 1; if (c > 0) { while (true) { i += step; if (i > hi) { break; } c = comparer.Compare(value, UnsafeEx.ReadUnaligned(ref Unsafe.Add(ref searchSpace, i))); if (c <= 0) { if (c == 0) { goto FOUND; } hi = i - 1; break; } step <<= 1; } lo = i - step + 1; } else { while (true) { i -= step; if (i < lo) { break; } c = comparer.Compare(value, UnsafeEx.ReadUnaligned(ref Unsafe.Add(ref searchSpace, i))); if (c >= 0) { if (c == 0) { goto FOUND; } lo = i + 1; break; } step <<= 1; } hi = i + step - 1; } } return(BinarySearch(ref searchSpace, lo, 1 + hi - lo, value)); FOUND: return(i); } }