private const int MaximumSectionCount = 128;   // This is the maximum granularity for GetBestStartPoint

        private static ListSearchConfiguration UpdateListSearchConfiguration(IList list)
        {
            ListSearchConfiguration configuration = default(ListSearchConfiguration);

            if (list is Array)
            {
                configuration.LowerBound = ((Array)list).GetLowerBound(0);
                configuration.UpperBound = ((Array)list).GetUpperBound(0);
            }
            else
            {
                configuration.LowerBound = 0;
                configuration.UpperBound = list.Count - 1;
            }

            configuration.ListSize    = list.Count;
            configuration.SectionSize = InitialSectionSize;

            while (configuration.SectionSize > 0 && (list.Count / configuration.SectionSize) > MaximumSectionCount)
            {
                configuration.SectionSize *= 2;
            }

            while (configuration.SectionSize > 0 && (list.Count / configuration.SectionSize) < 1)
            {
                configuration.SectionSize /= 2;
            }

            configuration.InitialCutSize = (configuration.SectionSize / 2);
            configuration.SectionCount   = configuration.SectionSize > 0 ? (list.Count / configuration.SectionSize) : 0;

            return(configuration);
        }
        public static int[] FindIndexBinary <T>(this IList list, T item, IComparer <T> comparer = null)
        {
            if (comparer == null)
            {
                comparer = Comparer <T> .Default;
            }

            ListSearchConfiguration configuration = default(ListSearchConfiguration);

            if (listSearchConfigCache.ContainsKey(list))
            {
                configuration = listSearchConfigCache[list];
            }

            if (configuration.ListSize == 0 || list.Count > configuration.SectionCount * configuration.SectionSize ||
                Math.Abs(list.Count - configuration.ListSize) > configuration.SectionSize)
            {
                if (listSearchConfigCache.ContainsKey(list))
                {
                    listSearchConfigCache[list] = UpdateListSearchConfiguration(list);
                }
                else
                {
                    listSearchConfigCache.Add(list, configuration = UpdateListSearchConfiguration(list));
                }
            }

            if (list.Count == 0 || comparer.Compare(item, (T)list[configuration.LowerBound]) == -1)
            {
                return(new[] { -1, 0 });
            }

            if (comparer.Compare(item, (T)list[configuration.UpperBound]) == 1)
            {
                return(new[] { configuration.UpperBound, configuration.UpperBound + 1 });
            }

            return(FindIndexBinaryCore(list, item, comparer, configuration));
        }
        private static int GetBestStartPoint <T>(IList list, T item, IComparer <T> comparer, ListSearchConfiguration configuration)
        {
            int startPoint = configuration.UpperBound - configuration.InitialCutSize;

            for (int i = configuration.LowerBound; i <= configuration.UpperBound; i += configuration.SectionSize)
            {
                if (comparer.Compare(item, (T)list[i]) == -1)
                {
                    startPoint = i - configuration.InitialCutSize;
                    break;
                }
            }

            return(startPoint);
        }
        private static int[] FindIndexBinaryCore <T>(IList list, T item, IComparer <T> comparer, ListSearchConfiguration configuration)
        {
            int startPoint = GetBestStartPoint(list, item, comparer, configuration);

            int[] result            = { 0, startPoint };
            int   cutSize           = configuration.InitialCutSize;
            int   nextCompareResult = comparer.Compare(item, (T)list[result[1]]);

            while (true)
            {
                result[0] = result[1];

                if (nextCompareResult == 0)
                {
                    return(result);
                }

                if (cutSize > 1)
                {
                    cutSize /= 2;
                }

                result[1] += cutSize * nextCompareResult;

                int compareResult = nextCompareResult;
                nextCompareResult = result[1] < configuration.LowerBound ? 1 : comparer.Compare(item, (T)list[result[1]]);

                if (compareResult == 1 && nextCompareResult == -1 && result[1] - result[0] == 1)
                {
                    return(result);
                }
            }
        }