Generic Growable Array : Array Util « Collections Data Structure « C# / C Sharp






Generic Growable Array

  
//     Copyright (c) Microsoft Corporation.  All rights reserved.
// This file is best viewed using outline mode (Ctrl-M Ctrl-O)
//
// This program uses code hyperlinks available as part of the HyperAddin Visual Studio plug-in.
// It is available from http://www.codeplex.com/hyperAddin 
// 
using System;
using System.Collections.Generic;
using System.Text;
using System.Diagnostics;

namespace System.Collections.Generic
{
    /// <summary>
    /// A cheap version of List(T). The idea is to make it as cheap as if you did it 'by hand' using an array and
    /// a int which represents the logical charCount. It is a struct to avoid an extra pointer dereference, so this
    /// is really meant to be embeded in other structures.
    /// 
    /// Also made the Binary search is actually useful (by allowing the key to be something besides the element
    /// itself).
    /// </summary>
    public struct GrowableArray<T>
    {
        public GrowableArray(int initialSize)
        {
            array = new T[initialSize];
            arrayLength = 0;
        }
        public T this[int index]
        {
            get
            {
                Debug.Assert((uint)index < (uint)arrayLength);
                return array[index];
            }
            set
            {
                Debug.Assert((uint)index < (uint)arrayLength);
                array[index] = value;
            }
        }
        public int Count
        {
            get
            {
                return arrayLength;
            }
            set
            {
                if (value > arrayLength)
                {
                    if (value <= array.Length)
                    {
                        // Null out the entries.  
                        for (int i = arrayLength; i < value; i++)
                            array[i] = default(T);
                    }
                    else
                    {
                        T[] newArray = new T[value];
                        Array.Copy(array, newArray, array.Length);
                        array = newArray;
                    }
                }
                arrayLength = value;
            }
        }
        /// <summary>
        /// Add an item at the end of the array, growing as necessary. 
        /// </summary>
        /// <param name="item"></param>
        public void Add(T item)
        {
            if (array == null || arrayLength >= array.Length)
                Realloc();
            array[arrayLength++] = item;
        }
        /// <summary>
        /// Insert 'item' directly at 'index', shifting all items >= index up.  'index' can be code:Count in
        /// which case the item is appended to the end.  Larger indexes are not allowed. 
        /// </summary>
        public void Insert(int index, T item)
        {
            if ((uint)index > (uint)arrayLength)
                throw new IndexOutOfRangeException();
            if (array == null || arrayLength >= array.Length)
                Realloc();

            // Shift everything up to make room. 
            for (int idx = arrayLength; index < idx; --idx)
                array[idx] = array[idx - 1];

            // insert the element
            array[index] = item;
            arrayLength++;
        }
        public void RemoveRange(int index, int count)
        {
            if (count == 0)
                return;
            if (count < 0)
                throw new ArgumentException("count can't be negative");

            if ((uint)index >= (uint)arrayLength)
                throw new IndexOutOfRangeException();
            Debug.Assert(index + count <= arrayLength);     // If you violate this it does not hurt

            // Shift everything down. 
            for (int endIndex = index + count; endIndex < arrayLength; endIndex++)
                array[index++] = array[endIndex];

            arrayLength = index;
        }
        public override string ToString()
        {
            StringBuilder sb = new StringBuilder();
            sb.Append("GrowableArray(Count=").Append(Count).Append(", [").AppendLine();
            for (int i = 0; i < Count; i++)
                sb.Append("  ").Append(this[i].ToString()).AppendLine();
            sb.Append("  ])");
            return sb.ToString();
        }
        public delegate int Comparison<Key>(Key x, T elem);
        /// <summary>
        /// Sets 'index' to the the smallest index such that all elements with index > 'idx' are > key.  If
        /// index does not match any elements a new element should always be placed AFTER index.  Note that this
        /// means that index may be -1 if the new element belongs in the first position.  
        /// 
        /// return true if the return index matched exactly (success)
        /// </summary>
        public bool BinarySearch<Key>(Key key, out int index, Comparison<Key> comparison)
        {
            // binary search 
            int low = 0;
            int high = arrayLength;
            int lastLowCompare = -1;                // If this number == 0 we had a match. 

            if (high > 0)
            {
                // The invarient in this loop is that 
                //     [0..low) <= key < [high..Count)
                for (; ; )
                {
                    int mid = (low + high) / 2;
                    int compareResult = comparison(key, array[mid]);
                    if (compareResult >= 0)             // key >= array[mid], move low up
                    {
                        lastLowCompare = compareResult; // remember this result, as it indicates a sucessful match. 
                        if (mid == low)
                            break;
                        low = mid;
                    }
                    else                                // key < array[mid], move high down 
                    {
                        high = mid;
                        if (mid == low)
                            break;
                    }

                    // Note that if compareResults == 0, we don't return the match eagerly because there could be
                    // multiple elements that match. We want the match with the largest possible index, so we need
                    // to continue the search until the valid range drops to 0
                }
            }

            if (lastLowCompare < 0)            // key < array[low], subtract 1 to indicate that new element goes BEFORE low. 
            {
                Debug.Assert(low == 0);         // can only happen if it is the first element
                --low;
            }
            index = low;

            Debug.Assert(index == -1 || comparison(key, array[index]) >= 0);                 // element smaller or equal to key            
            Debug.Assert(index + 1 >= Count || comparison(key, array[index + 1]) < 0);       // The next element is strictly bigger.
            Debug.Assert((lastLowCompare != 0) || (comparison(key, array[index]) == 0));     // If we say there is a match, there is. 
            return (lastLowCompare == 0);
        }
        public void Sort(int index, int length, System.Comparison<T> comparison)
        {
            Debug.Assert(index + length <= arrayLength);
            if (length > 0)
                Array.Sort<T>(array, index, length, new FunctorComparer<T>(comparison));
        }
        public void Sort(System.Comparison<T> comparison)
        {
            if (array != null)
                Array.Sort<T>(array, 0, arrayLength, new FunctorComparer<T>(comparison));
        }

        /// <summary>
        /// Perform a linear search starting at 'startIndex'.  If found return true and the index in 'index'.
        /// It is legal that 'startIndex' is greater than the charCount, in which case, the search returns false
        /// immediately.   This allows a nice loop to find all items matching a pattern. 
        /// </summary>
        public bool Search<Key>(Key key, int startIndex, Comparison<Key> compare, ref int index)
        {
            for (int i = startIndex; i < arrayLength; i++)
            {
                if (compare(key, array[i]) == 0)
                {
                    index = i;
                    return true;
                }
            }
            return false;
        }
        #region private
        private void Realloc()
        {
            if (array == null)
            {
                array = new T[16];
            }
            else
            {
                int newLength = array.Length * 3 / 2 + 8;
                T[] newArray = new T[newLength];
                Array.Copy(array, newArray, array.Length);
                array = newArray;
            }
        }

        T[] array;
        int arrayLength;
        #endregion

        #region TESTING
        // Unit testing.  It is reasonable coverage, but concentrates on BinarySearch as that is the one that is
        // easy to get wrong.  
#if TESTING
   public static void TestGrowableArray()
    {
        GrowableArray<float> testArray = new GrowableArray<float>();
        for (float i = 1.1F; i < 10; i += 2)
        {
            int successes = TestBinarySearch(testArray);
            Debug.Assert(successes == ((int)i) / 2);
            testArray.Add(i);
        }

        for (float i = 0.1F; i < 11; i += 2)
        {
            int index;
            bool result = testArray.BinarySearch(i, out index, delegate(float key, float elem) { return (int)key - (int)elem; });
            Debug.Assert(!result);
            testArray.InsertAt(index + 1, i);
        }

        int lastSuccesses = TestBinarySearch(testArray);
        Debug.Assert(lastSuccesses == 11);

        for (float i = 0; i < 11; i += 1)
        {
            int index;
            bool result = testArray.BinarySearch(i, out index, delegate(float key, float elem) { return (int)key - (int)elem; });
            Debug.Assert(result);
            testArray.InsertAt(index + 1, i);
        }

        lastSuccesses = TestBinarySearch(testArray);
        Debug.Assert(lastSuccesses == 11);

        // We always get the last one when the equality comparision allows multiple items to match.  
        for (float i = 0; i < 11; i += 1)
        {
            int index;
            bool result = testArray.BinarySearch(i, out index, delegate(float key, float elem) { return (int)key - (int)elem; });
            Debug.Assert(result);
            Debug.Assert(i == testArray[index]);
        }
        Console.WriteLine("Done");
    }
    private static int TestBinarySearch(GrowableArray<float> testArray)
    {
        int successes = 0;
        for (int i = 0; i < 30; i++)
        {
            int index;
            if (testArray.BinarySearch(i, out index, delegate(float key, float elem) { return (int)key - (int)elem; }))
            {
                successes++;
                Debug.Assert((int)testArray[index] == i);
            }
            else
                Debug.Assert(index + 1 <= testArray.Count);
        }
        return successes;
}
#endif
        #endregion

        // This allows 'foreach' to work.  
        public GrowableArrayEnumerator GetEnumerator() { return new GrowableArrayEnumerator(this); }
        public struct GrowableArrayEnumerator
        {
            public T Current
            {
                get { return array[cur]; }
            }
            public bool MoveNext()
            {
                cur++;
                return cur < end;
            }

            #region private
            internal GrowableArrayEnumerator(GrowableArray<T> growableArray)
            {
                cur = -1;
                end = growableArray.arrayLength;
                array = growableArray.array;
            }
            int cur;
            int end;
            T[] array;
            #endregion
        }
    }

    internal class FunctorComparer<T> : IComparer<T>
    {
        public FunctorComparer(Comparison<T> comparison) { this.comparison = comparison; }
        public int Compare(T x, T y) { return comparison(x, y); }

        private Comparison<T> comparison;
    };
}

   
    
  








Related examples in the same category

1.Return the average of the given values
2.Return the percentage of a given value.
3.return the min value in the list of double
4.return the max value in the list of double
5.Returns a string representation of the sbyte array
6.Returns a string representation of the char array
7.Returns a string representation of the double array
8.Returns a string representation of the float array
9.Returns a string representation of the int array
10.Returns a string representation of the long array
11.Returns a string representation of the object array
12.Returns a string representation of the short value array
13.Returns a string representation of the bool value array
14.Ensures that the sbyte array cannot hold more than maxCapacity elements.
15.Ensures that the char array cannot hold more than maxCapacity elements.
16.Ensures that the double array cannot hold more than maxCapacity elements.
17.Ensures that the float array cannot hold more than maxCapacity elements.
18.Ensures that the int array cannot hold more than maxCapacity elements.
19.Ensures that the long array cannot hold more than maxCapacity elements.
20.Ensures that the object array cannot hold more than maxCapacity elements.
21.Ensures that the short array cannot hold more than maxCapacity elements.
22.Ensures that the bool array cannot hold more than maxCapacity elements.
23.Copy an array into another array.
24.Swap two elements in a array
25.foreach is used to display the contents of an array of integers.
26.Are two arrays equal.
27.Are thos two arrays having the save contents
28.Convert object array to string
29.Get array size
30.Convert array content to generic type array
31.Searches for the specified object and returns the index of the first occurrence within the entire one-dimensional System.Array.
32.Creates a new array with just the specified elements.
33.Array 2D
34.Get a array of object from a enum datatype.
35.Reinitializes an int array to the given value in an optimized way: intArraySet
36.Returns a Boolean indicating whether the Array is Empty (is Null or has a length of zero).
37.Places elements from an enumerable into an array.
38.Bit Array 2D
39.Counting the distribution of the values in an array.
40.Collection of static methods for operations on arrays
41.Char Array Writer
42.Computes the indices
43.Compare Array
44.Remove element from Array
45.Concatenate Array
46.Get the array slice between the two indexes
47.Find subarray in the source array.
48.Check if the array contains needle on specified position