public void CopyTo(T[] array, int arrayIndex, int count)
        {
            if (array == null)
            {
                throw new ArgumentNullException("array");
            }
            if (arrayIndex < 0)
            {
                throw new ArgumentOutOfRangeException("Index cannot be less than zero.");
            }
            if (count < 0)
            {
                throw new ArgumentOutOfRangeException("Count cannot be less than zero.");
            }
            if (arrayIndex > array.Length || count > (array.Length - arrayIndex))
            {
                throw new ArgumentException("Destination array is too small");
            }
            Contract.EndContractBlock();

            int p = arrayIndex;

            count = Math.Min(count, m_count);
            foreach (var item in ColaStore.IterateOrdered(count, m_levels, m_comparer, false))
            {
                array[p++] = item;
            }
            Contract.Assert(p == arrayIndex + count);
        }
        /// <summary>Find the largest element in the store</summary>
        /// <returns>Largest element found, or default(T) if the store is empty</returns>
        public T Max()
        {
            switch (m_count)
            {
            case 0: return(default(T));

            case 1: return(m_root[0]);

            case 2: return(m_levels[1][1]);

            default:
            {
                int level = ColaStore.LowestBit(m_count);
                int end   = ColaStore.HighestBit(m_count);
                T   max   = m_levels[level][0];
                while (level <= end)
                {
                    if (!IsFree(level) && m_comparer.Compare(max, m_levels[level][0]) < 0)
                    {
                        max = m_levels[level][0];
                    }
                    ++level;
                }
                return(max);
            }
            }
        }
        /// <summary>Finds the location of an element in the array</summary>
        /// <param name="value">Value of the element to search for.</param>
        /// <param name="offset">Receives the offset of the element inside the level if found; otherwise, 0.</param>
        /// <returns>Level that contains the element if found; otherwise, -1.</returns>
        public int Find(T value, out int offset, out T actualValue)
        {
            if ((m_count & 1) != 0)
            {
                // If someone gets the last inserted key, there is a 50% change that it is in the root
                // (if not, it will the the last one of the first non-empty level)
                if (m_comparer.Compare(value, m_root[0]) == 0)
                {
                    offset      = 0;
                    actualValue = m_root[0];
                    return(0);
                }
            }

            var levels = m_levels;

            for (int i = 1; i < levels.Length; i++)
            {
                if (IsFree(i))
                {                 // this segment is not allocated
                    continue;
                }

                int p = ColaStore.BinarySearch <T>(levels[i], 0, 1 << i, value, m_comparer);
                if (p >= 0)
                {
                    offset      = p;
                    actualValue = levels[i][p];
                    return(i);
                }
            }
            offset      = 0;
            actualValue = default(T);
            return(NOT_FOUND);
        }
        /// <summary>Remove the value at the specified location</summary>
        /// <param name="arrayIndex">Absolute index in the vector-array</param>
        /// <returns>Value that was removed</returns>
        public T RemoveAt(int arrayIndex)
        {
            Contract.Requires(arrayIndex >= 0 && arrayIndex <= this.Capacity);
            int offset, level = ColaStore.FromIndex(arrayIndex, out offset);

            return(RemoveAt(level, offset));
        }
        /// <summary>Insert a new element in the set, and returns its index.</summary>
        /// <param name="value">Value to insert. Warning: if the value already exists, the store will be corrupted !</param>
        /// <remarks>The index is the absolute index, as if all the levels where a single, contiguous, array (0 = root, 7 = first element of level 3)</remarks>
        public void Insert(T value)
        {
            if (IsFree(0))
            {             // half the inserts (when the count is even) can be done in the root
                m_root[0] = value;
            }
            else if (IsFree(1))
            {             // a quarter of the inserts only need to move the root and the value to level 1
                ColaStore.MergeSimple <T>(m_levels[1], m_root[0], value, m_comparer);
                m_root[0] = default(T);
            }
            else
            {             // we need to merge one or more levels
                var spare = GetSpare(0);
                if (object.ReferenceEquals(spare, m_root))
                {
                    Debugger.Break();
                }
                Contract.Assert(spare != null && spare.Length == 1);
                spare[0] = value;
                MergeCascade(1, m_root, spare);
                PutSpare(0, spare);
                m_root[0] = default(T);
            }
            ++m_count;

            CheckInvariants();
        }
Exemple #6
0
 void System.Collections.IEnumerator.Reset()
 {
     if (m_version != m_parent.m_version)
     {
         ColaStore.ThrowStoreVersionChanged();
     }
     m_iterator = new ColaStore.Enumerator <KeyValuePair <TKey, TValue> >(m_parent.m_items, m_iterator.Reverse);
 }
Exemple #7
0
 internal Enumerator(ColaStore <T> items, bool reverse)
 {
     m_items   = items;
     m_reverse = reverse;
     m_cursors = ColaStore.CreateCursors(m_items.Count, out m_min);
     m_max     = m_cursors.Length - 1;
     m_current = default(T);
 }
Exemple #8
0
            public bool MoveNext()
            {
                if (m_version != m_parent.m_version)
                {
                    ColaStore.ThrowStoreVersionChanged();
                }

                return(m_iterator.MoveNext());
            }
        /// <summary>Store a value at a specific location in the arrayh</summary>
        /// <param name="arrayIndex">Absolute index in the vector-array</param>
        /// <param name="value">Value to store</param>
        /// <returns>Previous value at that location</returns>
        public T SetAt(int arrayIndex, T value)
        {
            Contract.Assert(arrayIndex >= 0 && arrayIndex <= this.Capacity);

            int offset;
            int level = ColaStore.FromIndex(arrayIndex, out offset);

            return(SetAt(level, offset, value));
        }
Exemple #10
0
            internal Iterator(T[][] levels, int count, IComparer <T> comparer)
            {
                Contract.Requires(levels != null && count >= 0 && comparer != null);
                m_levels   = levels;
                m_count    = count;
                m_comparer = comparer;

                m_cursors = ColaStore.CreateCursors(m_count, out m_min);
            }
        public ColaOrderedSet(int capacity, IComparer <T> comparer)
        {
            if (capacity < 0)
            {
                throw new ArgumentOutOfRangeException("capacity", "Capacity cannot be less than zero.");
            }
            Contract.EndContractBlock();

            m_items = new ColaStore <T>(capacity, comparer ?? Comparer <T> .Default);
        }
 public ColaRangeSet(int capacity, IComparer <TKey> keyComparer)
 {
     m_comparer = keyComparer ?? Comparer <TKey> .Default;
     if (capacity == 0)
     {
         capacity = 15;
     }
     m_items  = new ColaStore <Entry>(capacity, new BeginKeyComparer(m_comparer));
     m_bounds = new Entry(default(TKey), default(TKey));
 }
        /// <summary>Find an element </summary>
        /// <param name="value"></param>
        /// <returns>The zero-based index of the first occurrence of <paramref name="value"/> within the entire list, if found; otherwise, –1.</returns>
        public int IndexOf(T value)
        {
            T   _;
            int offset, level = m_items.Find(value, out offset, out _);

            if (level >= 0)
            {
                return(ColaStore.MapLocationToOffset(m_items.Count, level, offset));
            }
            return(NOT_FOUND);
        }
 public ColaRangeDictionary(int capacity, IComparer <TKey> keyComparer, IComparer <TValue> valueComparer)
 {
     m_keyComparer   = keyComparer ?? Comparer <TKey> .Default;
     m_valueComparer = valueComparer ?? Comparer <TValue> .Default;
     if (capacity == 0)
     {
         capacity = 15;
     }
     m_items  = new ColaStore <Entry>(capacity, new BeginKeyComparer(m_keyComparer));
     m_bounds = new Entry(default(TKey), default(TKey), default(TValue));
 }
        /// <summary>Allocates a new store</summary>
        /// <param name="capacity">Initial capacity, or 0 for the default capacity</param>
        /// <param name="comparer">Comparer used to order the elements</param>
        public ColaStore(int capacity, IComparer <T> comparer)
        {
            if (capacity < 0)
            {
                throw new ArgumentOutOfRangeException("capacity", "Capacity cannot be less than zero.");
            }
            if (comparer == null)
            {
                throw new ArgumentNullException("comparer");
            }
            Contract.EndContractBlock();

            int levels;

            if (capacity == 0)
            {             // use the default capacity
                levels = INITIAL_LEVELS;
            }
            else
            {             // L levels will only store (2^L - 1)
                // note: there is no real penalty if the capacity was not correctly estimated, appart from the fact that all levels will not be contiguous in memory
                // 1 => 1
                // 2..3 => 2
                // 4..7 => 3
                levels = ColaStore.HighestBit(capacity) + 1;
            }
            // allocating more than 31 levels would mean having an array of length 2^31, which is not possible
            if (levels >= 31)
            {
                throw new ArgumentOutOfRangeException("capacity", "Cannot allocate more than 30 levels");
            }

            // pre-allocate the segments and spares at the same time, so that they are always at the same memory location
            var segments = new T[levels][];
            var spares   = new T[MAX_SPARE_ORDER][];

            for (int i = 0; i < segments.Length; i++)
            {
                segments[i] = new T[1 << i];
                if (i < spares.Length)
                {
                    spares[i] = new T[1 << i];
                }
            }

            m_levels = segments;
            m_root   = segments[0];
            m_spares = spares;
#if ENFORCE_INVARIANTS
            m_spareUsed = new bool[spares.Length];
#endif
            m_comparer = comparer;
        }
        /// <summary>Returns the smallest and largest element in the store</summary>
        /// <param name="min">Receives the value of the smallest element (or default(T) is the store is Empty)</param>
        /// <param name="max">Receives the value of the largest element (or default(T) is the store is Empty)</param>
        /// <remarks>If the store contains only one element, than min and max will be equal</remarks>
        public void GetBounds(out T min, out T max)
        {
            switch (m_count)
            {
            case 0:
            {
                min = default(T);
                max = default(T);
                break;
            }

            case 1:
            {
                min = m_root[0];
                max = min;
                break;
            }

            case 2:
            {
                min = m_levels[1][0];
                max = m_levels[1][1];
                break;
            }

            default:
            {
                int level   = ColaStore.LowestBit(m_count);
                int end     = ColaStore.HighestBit(m_count);
                var segment = m_levels[level];
                min = segment[0];
                max = segment[segment.Length - 1];
                while (level <= end)
                {
                    if (IsFree(level))
                    {
                        continue;
                    }
                    segment = m_levels[level];
                    if (m_comparer.Compare(min, segment[0]) > 0)
                    {
                        min = segment[0];
                    }
                    if (m_comparer.Compare(max, segment[segment.Length - 1]) < 0)
                    {
                        min = segment[segment.Length - 1];
                    }
                    ++level;
                }
                break;
            }
            }
        }
 public T this[int index]
 {
     get
     {
         if (index < 0 || index >= m_items.Count)
         {
             ThrowIndexOutOfRangeException();
         }
         int offset;
         int level = ColaStore.MapOffsetToLocation(m_items.Count, index, out offset);
         Contract.Assert(level >= 0);
         return(m_items.GetAt(level, offset));
     }
 }
        /// <summary>Pre-allocate memory in the store so that it can store a specified amount of items</summary>
        /// <param name="minimumRequired">Number of items that will be inserted in the store</param>
        public void EnsureCapacity(int minimumRequired)
        {
            int level = ColaStore.HighestBit(minimumRequired);

            if ((1 << level) < minimumRequired)
            {
                ++level;
            }

            if (level >= m_levels.Length)
            {
                Grow(level);
            }
        }
        public T RemoveAt(int arrayIndex)
        {
            if (arrayIndex < 0 || arrayIndex >= m_items.Count)
            {
                throw new ArgumentOutOfRangeException("arrayIndex", "Index is outside the array");
            }

            int offset;
            int level = ColaStore.MapOffsetToLocation(m_items.Count, arrayIndex, out offset);

            Contract.Assert(level >= 0 && offset >= 0 && offset < 1 << level);

            ++m_version;
            return(m_items.RemoveAt(level, offset));
        }
Exemple #20
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);
        }
Exemple #21
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);
            }
        private void MergeCascade(int level, T[] left, T[] right)
        {
            Contract.Requires(level > 0, "level");
            Contract.Requires(left != null && left.Length == (1 << (level - 1)), "left");
            Contract.Requires(right != null && right.Length == (1 << (level - 1)), "right");

            if (IsFree(level))
            {             // target level is empty
                if (level >= m_levels.Length)
                {
                    Grow(level);
                }
                Contract.Assert(level < m_levels.Length);

                ColaStore.MergeSort(m_levels[level], left, right, m_comparer);
            }
            else if (IsFree(level + 1))
            {             // the next level is empty
                if (level + 1 >= m_levels.Length)
                {
                    Grow(level + 1);
                }
                Contract.Assert(level + 1 < m_levels.Length);

                var spare = GetSpare(level);
                ColaStore.MergeSort(spare, left, right, m_comparer);
                var next = m_levels[level];
                ColaStore.MergeSort(m_levels[level + 1], next, spare, m_comparer);
                Array.Clear(next, 0, next.Length);
                PutSpare(level, spare);
            }
            else
            {             // both are full, need to do a cascade merge
                Contract.Assert(level < m_levels.Length);

                // merge N and N +1
                var spare = GetSpare(level);
                ColaStore.MergeSort(spare, left, right, m_comparer);

                // and cascade to N + 2 ...
                var next = m_levels[level];
                MergeCascade(level + 1, next, spare);
                Array.Clear(next, 0, next.Length);
                PutSpare(level, spare);
            }
        }
Exemple #23
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);
        }
Exemple #24
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]);
                }
            }
        }
Exemple #25
0
            public bool MoveNext()
            {
                int pos;

                if (m_reverse)
                {
                    pos = ColaStore.IterateFindPrevious(m_items.Levels, m_cursors, m_min, m_max, m_items.Comparer, out m_current);
                }
                else
                {
                    pos = ColaStore.IterateFindNext(m_items.Levels, m_cursors, m_min, m_max, m_items.Comparer, out m_current);
                }

                if (pos == NOT_FOUND)
                {                 // that was the last item!
                    return(false);
                }

                // update the bounds if necessary
                if (pos == m_max)
                {
                    if (m_cursors[m_max] == NOT_FOUND)
                    {
                        --m_max;
                    }
                }
                else if (pos == m_min)
                {
                    if (m_cursors[m_min] == NOT_FOUND)
                    {
                        ++m_min;
                    }
                }

                return(true);
            }
        /// <summary>Insert two elements in the set.</summary>
        public void InsertItems(T first, T second)
        {
            Contract.Requires(m_comparer.Compare(first, second) != 0, "Cannot insert the same value twice");

            if (IsFree(1))
            {
                ColaStore.MergeSimple <T>(m_levels[1], first, second, m_comparer);
            }
            else
            {
                //Console.WriteLine("InsertItems([2]) Cascade");
                var spare = GetSpare(1);
                spare[0] = first;
                spare[1] = second;
                var segment = m_levels[1];
                MergeCascade(2, segment, spare);
                segment[0] = default(T);
                segment[1] = default(T);
                PutSpare(1, spare);
            }
            m_count += 2;

            CheckInvariants();
        }
Exemple #27
0
 void System.Collections.IEnumerator.Reset()
 {
     m_cursors = ColaStore.CreateCursors(m_items.Count, out m_min);
     m_max     = m_cursors.Length - 1;
     m_current = default(T);
 }
Exemple #28
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;
                        }
                    }
                }
            }
        }
Exemple #29
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;
                    }
                }
            }
        }
Exemple #30
0
 public ColaOrderedDictionary(int capacity, IComparer <TKey> keyComparer, IEqualityComparer <TValue> valueComparer)
 {
     m_keyComparer   = keyComparer ?? Comparer <TKey> .Default;
     m_valueComparer = valueComparer ?? EqualityComparer <TValue> .Default;
     m_items         = new ColaStore <KeyValuePair <TKey, TValue> >(capacity, new KeyOnlyComparer(m_keyComparer));
 }