Exemplo n.º 1
0
        /// <summary>Search for the smallest element that is larger than a reference element</summary>
        /// <param name="value">Reference element</param>
        /// <param name="orEqual">If true, return the position of the value itself if it is found. If false, return the position of the closest value that is smaller.</param>
        /// <param name="offset">Receive the offset within the level of the next element, or 0 if not found</param>
        /// <param name="result">Receive the value of the next element, or default(T) if not found</param>
        /// <returns>Level of the next element, or -1 if <param name="result"/> was already the largest</returns>
        public static int FindNext <T>(T[][] levels, int count, T value, bool orEqual, IComparer <T> comparer, out int offset, out T result)
        {
            int level     = NOT_FOUND;
            T   min       = default(T);
            int minOffset = 0;

            // scan each segment for a value that would be larger, keep track of the smallest found
            for (int i = 0; i < levels.Length; i++)
            {
                if (ColaStore.IsFree(i, count))
                {
                    continue;
                }

                var segment = levels[i];
                int pos     = ColaStore.BinarySearch <T>(segment, 0, segment.Length, value, comparer);
                if (pos >= 0)
                {                 // we found an exact match in this segment
                    if (orEqual)
                    {
                        offset = pos;
                        result = segment[pos];
                        return(i);
                    }

                    // the next item in this segment should be larger
                    ++pos;
                }
                else
                {                 // we found where it would be stored in this segment
                    pos = ~pos;
                }

                if (pos < segment.Length)
                {
                    if (level == NOT_FOUND || comparer.Compare(segment[pos], min) < 0)
                    {                     // we found a better candidate
                        min       = segment[pos];
                        level     = i;
                        minOffset = pos;
                    }
                }
            }

            offset = minOffset;
            result = min;
            return(level);
        }
Exemplo n.º 2
0
            private void Debug_Dump(string label = null)
            {
                Trace.WriteLine("* Cursor State: " + label);
                for (int i = m_min; i < m_cursors.Length; i++)
                {
                    if (ColaStore.IsFree(i, m_count))
                    {
                        Trace.WriteLine("  - L" + i + ": unallocated");
                        continue;
                    }

                    int p = m_cursors[i];
                    Trace.WriteLine("  - L" + i + ": " + p + " [" + (1 << i) + "] = " + (p < 0 ? "<BEFORE>" : (p >= (1 << i)) ? "<AFTER>" : ("" + m_levels[i][p])));
                }
                Trace.WriteLine(" > Current at " + m_currentLevel + " : " + m_current);
            }
Exemplo n.º 3
0
        /// <summary>Search for the largest element that is smaller than a reference element</summary>
        /// <param name="value">Reference element</param>
        /// <param name="orEqual">If true, return the position of the value itself if it is found. If false, return the position of the closest value that is smaller.</param>
        /// <param name="offset">Receive the offset within the level of the previous element, or 0 if not found</param>
        /// <param name="result">Receive the value of the previous element, or default(T) if not found</param>
        /// <returns>Level of the previous element, or -1 if <param name="result"/> was already the smallest</returns>
        public static int FindPrevious <T>(T[][] levels, int count, T value, bool orEqual, IComparer <T> comparer, out int offset, out T result)
        {
            int level     = NOT_FOUND;
            T   max       = default(T);
            int maxOffset = 0;

            // scan each segment for a value that would be smaller, keep track of the smallest found
            for (int i = 0; i < levels.Length; i++)
            {
                if (ColaStore.IsFree(i, count))
                {
                    continue;
                }

                var segment = levels[i];
                int pos     = ColaStore.BinarySearch <T>(segment, 0, segment.Length, value, comparer);
                // the previous item in this segment should be smaller
                if (pos < 0)
                {                 // it is not
                    pos = ~pos;
                }
                else if (orEqual)
                {                 // we found an exact match in this segment
                    offset = pos;
                    result = segment[pos];
                    return(i);
                }

                --pos;

                if (pos >= 0)
                {
                    if (level == NOT_FOUND || comparer.Compare(segment[pos], max) > 0)
                    {                     // we found a better candidate
                        max       = segment[pos];
                        level     = i;
                        maxOffset = pos;
                    }
                }
            }

            offset = maxOffset;
            result = max;
            return(level);
        }
Exemplo n.º 4
0
        /// <summary>Iterate over all the values in the set, without any order guarantee</summary>
        internal static IEnumerable <T> IterateUnordered <T>(int count, T[][] inputs)
        {
            Contract.Requires(count >= 0 && inputs != null && count < (1 << inputs.Length));

            for (int i = 0; i < inputs.Length; i++)
            {
                if (ColaStore.IsFree(i, count))
                {
                    continue;
                }
                var segment = inputs[i];
                Contract.Assert(segment != null && segment.Length == 1 << i);
                for (int j = 0; j < segment.Length; j++)
                {
                    yield return(segment[j]);
                }
            }
        }
Exemplo n.º 5
0
        /// <summary>Iterate over all the values in the set, using their natural order</summary>
        internal static IEnumerable <T> IterateOrdered <T>(int count, T[][] inputs, IComparer <T> comparer, bool reverse)
        {
            Contract.Requires(count >= 0 && inputs != null && comparer != null && count < (1 << inputs.Length));
            // NOT TESTED !!!!!
            // NOT TESTED !!!!!
            // NOT TESTED !!!!!

            Contract.Requires(count >= 0 && inputs != null && comparer != null);

            // We will use a list of N cursors, set to the start of their respective levels.
            // A each turn, look for the smallest key referenced by the cursors, return that one, and advance its cursor.
            // Once a cursor is past the end of its level, it is set to -1 and is ignored for the rest of the operation

            if (count > 0)
            {
                // setup the cursors, with the empty levels already marked as completed
                var cursors = new int[inputs.Length];
                for (int i = 0; i < cursors.Length; i++)
                {
                    if (ColaStore.IsFree(i, count))
                    {
                        cursors[i] = NOT_FOUND;
                    }
                }

                // pre compute the first/last active level
                int min = ColaStore.LowestBit(count);
                int max = ColaStore.HighestBit(count);

                while (count-- > 0)
                {
                    T   item;
                    int pos;
                    if (reverse)
                    {
                        pos = IterateFindPrevious(inputs, cursors, min, max, comparer, out item);
                    }
                    else
                    {
                        pos = IterateFindNext(inputs, cursors, min, max, comparer, out item);
                    }

                    if (pos == NOT_FOUND)
                    {                     // we unexpectedly ran out of stuff before the end ?
                        //TODO: should we fail or stop here ?
                        throw new InvalidOperationException("Not enough data in the source arrays to fill the output array");
                    }
                    yield return(item);

                    // update the bounds if needed
                    if (pos == max)
                    {
                        if (cursors[max] == NOT_FOUND)
                        {
                            --max;
                        }
                    }
                    else if (pos == min)
                    {
                        if (cursors[min] == NOT_FOUND)
                        {
                            ++min;
                        }
                    }
                }
            }
        }
Exemplo n.º 6
0
        public static IEnumerable <T> FindBetween <T>(T[][] levels, int count, T begin, bool beginOrEqual, T end, bool endOrEqual, int limit, IComparer <T> comparer)
        {
            if (limit > 0)
            {
                for (int i = 0; i < levels.Length; i++)
                {
                    if (ColaStore.IsFree(i, count))
                    {
                        continue;
                    }

                    var segment = levels[i];

                    int to = ColaStore.BinarySearch <T>(segment, 0, segment.Length, end, comparer);
                    if (to >= 0)
                    {
                        if (!endOrEqual)
                        {
                            to--;
                        }
                    }
                    else
                    {
                        to = ~to;
                    }
                    if (to < 0 || to >= segment.Length)
                    {
                        continue;
                    }

                    int from = ColaStore.BinarySearch <T>(segment, 0, segment.Length, begin, comparer);
                    if (from >= 0)
                    {
                        if (!beginOrEqual)
                        {
                            ++from;
                        }
                    }
                    else
                    {
                        from = ~from;
                    }
                    if (from >= segment.Length)
                    {
                        continue;
                    }

                    if (from > to)
                    {
                        continue;
                    }

                    for (int j = from; j <= to && limit > 0; j++)
                    {
                        yield return(segment[j]);

                        --limit;
                    }
                    if (limit <= 0)
                    {
                        break;
                    }
                }
            }
        }
        /// <summary>Insert one or more new elements in the set.</summary>
        /// <param name="values">Array of elements to insert. Warning: if a value already exist, the store will be corrupted !</param>
        /// <param name="ordered">If true, the entries in <paramref name="values"/> are guaranteed to already be sorted (using the store default comparer).</param>
        /// <remarks>The best performances are achieved when inserting a number of items that is a power of 2. The worst performances are when doubling the size of a store that is full.
        /// Warning: if <paramref name="ordered"/> is true but <paramref name="values"/> is not sorted, or is sorted using a different comparer, then the store will become corrupted !
        /// </remarks>
        public void InsertItems(List <T> values, bool ordered = false)
        {
            if (values == null)
            {
                throw new ArgumentNullException("values");
            }

            int count = values.Count;

            T[] segment, spare;

            if (count < 2)
            {
                if (count == 1)
                {
                    Insert(values[0]);
                }
                return;
            }

            if (count == 2)
            {
                if (IsFree(1))
                {
                    segment = m_levels[1];
                    if (ordered)
                    {
                        segment[0] = values[0];
                        segment[1] = values[1];
                    }
                    else
                    {
                        ColaStore.MergeSimple <T>(segment, values[0], values[1], m_comparer);
                    }
                }
                else
                {
                    spare    = GetSpare(1);
                    spare[0] = values[0];
                    spare[1] = values[1];
                    segment  = m_levels[1];
                    MergeCascade(2, segment, spare);
                    segment[0] = default(T);
                    segment[1] = default(T);
                    PutSpare(1, spare);
                }
            }
            else
            {
                // Inserting a size that is a power of 2 is very simple:
                // * either the corresponding level is empty, in that case we just copy the items and do a quicksort
                // * or it is full, then we just need to do a cascade merge
                // For non-power of 2s, we can split decompose them into a suite of power of 2s and insert them one by one

                int min = ColaStore.LowestBit(count);
                int max = ColaStore.HighestBit(count);

                if (max >= m_levels.Length)
                {                 // we need to allocate new levels
                    Grow(max);
                }

                int p = 0;
                for (int i = min; i <= max; i++)
                {
                    if (ColaStore.IsFree(i, count))
                    {
                        continue;
                    }

                    segment = m_levels[i];
                    if (IsFree(i))
                    {                     // the target level is free, we can copy and sort in place
                        values.CopyTo(p, segment, 0, segment.Length);
                        if (!ordered)
                        {
                            Array.Sort(segment, 0, segment.Length, m_comparer);
                        }
                        p       += segment.Length;
                        m_count += segment.Length;
                    }
                    else
                    {                     // the target level is used, we will have to do a cascade merge, using a spare
                        spare = GetSpare(i);
                        values.CopyTo(p, spare, 0, spare.Length);
                        if (!ordered)
                        {
                            Array.Sort(spare, 0, spare.Length, m_comparer);
                        }
                        p += segment.Length;
                        MergeCascade(i + 1, segment, spare);
                        Array.Clear(segment, 0, segment.Length);
                        PutSpare(i, spare);
                        m_count += segment.Length;
                    }
                }
                Contract.Assert(p == count);
            }

            CheckInvariants();
        }