Example #1
0
 private long KeyToLong(TRowKey key)
 {
     // ReSharper disable once ImpureMethodCallOnReadonlyValueField
     return(_comparer.Diff(key, default(TRowKey)));
 }
Example #2
0
        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);
            }
        }