.NET: Jitsu.Collections.Specialized.ByteVector

This C# class implements a strongly-typed collection of bytes.  The internal representation is a simple byte[], so the performance characteristics will be more akin to a "vector" than a "list", to use STL terminology.  This implementation is optimized for value-types, as it goes to great length to avoid the overhead of boxing and unboxing -- at the expense, perhaps, of being able to efficiently insert/remove items into/from the middle of the list..

using System;
using System.Collections;

using T = System.Byte;

namespace Jitsu.Collections.Specialized
{
    [Serializable]
    public sealed class ByteVector : ICollection, IList, IEnumerable, ICloneable
    {
        const int DefaultMinimumCapacity = 16;

        T[] m_array = new T[DefaultMinimumCapacity];
        int m_count = 0;
        int m_version = 0;

        //
        // Initialization

        public ByteVector()
        { }

        public ByteVector(ByteVector collection)
        { AddRange(collection); }

        public ByteVector(T[] array)
        { AddRange(array); }

        //
        // Interface (type-safe ICollection)

        public int Count
        {
            get
            { return m_count; }
        }

        public void CopyTo(T[] array)
        {
            this.CopyTo(array, 0);
        }

        public void CopyTo(T[] array, int start)
        {
            if (m_count > array.GetUpperBound(0)+1-start)
                throw new System.ArgumentException("Destination array was not long enough.");

            // for (int i=0; i < m_count; ++i) array[start+i] = m_array[i];
            Array.Copy(m_array, 0, array, start, m_count); 
        }

        // Interface (type-safe IList)

        public T this[int index]
        {
            get
            {
                ValidateIndex(index); // throws
                return m_array[index]; 
            }
            set
            {
                ValidateIndex(index); // throws

                ++m_version; 
                m_array[index] = value; 
            }
        }

        public int Add(T item)
        {
            if (NeedsGrowth())
                Grow();

            ++m_version;
            m_array[m_count] = item;

            return m_count++;
        }

        public void Clear()
        {
            ++m_version;
            m_array = new T[DefaultMinimumCapacity];
            m_count = 0;
        }

        public bool Contains(T item)
        {
            return ((IndexOf(item) == -1)?false:true);
        }

        public int IndexOf(T item)
        {
            for (int i=0; i < m_count; ++i)
                if (m_array[i].Equals(item))
                    return i;
            return -1;
        }

        public void Insert(int position, T item)
        {
            ValidateIndex(position,true); // throws

            if (NeedsGrowth())
                Grow();

            ++m_version;
            // for (int i=m_count; i > position; --i) m_array[i] = m_array[i-1];
            Array.Copy(m_array, position, m_array, position+1, m_count-position);

            m_array[position] = item;
            m_count++;
        }

        public void Remove(T item)
        {
            int index = IndexOf(item);
            if (index < 0)
                throw new System.ArgumentException("Cannot remove the specified item because it was not found in the specified Collection.");

            RemoveAt(index);
        }

        public void RemoveAt(int index)
        {
            ValidateIndex(index); // throws

            ++m_version;
            m_count--;
            // for (int i=index; i < m_count; ++i) m_array[i] = m_array[i+1];
            Array.Copy(m_array, index+1, m_array, index, m_count-index);

            if (NeedsTrimming())
                Trim();
        }

        //
        // Interface (type-safe IEnumerable)

        public Enumerator GetEnumerator()
        {
            return new Enumerator(this);
        }

        public class Enumerator : IEnumerator
        {
            private ByteVector m_collection;
            private int m_index;
            private int m_version;

            //
            // Initialization

            internal Enumerator(ByteVector tc)
            {
                m_collection = tc;
                m_index = -1;
                m_version = tc.m_version;
            }

            //
            // Interface

            public T Current
            {
                get
                { return m_collection[m_index]; }
            }

            public bool MoveNext()
            {
                if (m_version != m_collection.m_version)
                    throw new System.InvalidOperationException("Collection was modified; enumeration operation may not execute.");

                ++m_index;
                return (m_index < m_collection.Count)?true:false;
            }

            public void Reset()
            {
                if (m_version != m_collection.m_version)
                    throw new System.InvalidOperationException("Collection was modified; enumeration operation may not execute.");

                m_index = -1;
            }

            //
            // Implementation

            object IEnumerator.Current
            {
                get
                { return (object)(this.Current); }
            }

        }

        //
        // Interface (type-safe ICloneable)

        public ByteVector Clone()
        {
            ByteVector tc = new ByteVector();
            tc.AddRange(this);
            tc.Capacity = this.m_array.Length;
            tc.m_version = this.m_version;
            return tc;
        }

        //
        // Interface (just mimicing some nice features of ArrayList)

        public int Capacity
        {
            get
            { return m_array.Length; }
            set
            {
                if (value < m_count) value = m_count;
                if (value < DefaultMinimumCapacity) value = DefaultMinimumCapacity;

                if (m_array.Length == value) return;

                ++m_version;

                T[] temp = new T[value];
                // for (int i=0; i < m_count; ++i) temp[i] = m_array[i];
                Array.Copy(m_array, 0, temp, 0, m_count); 
                m_array = temp;
            }
        }

        public void AddRange(ByteVector collection)
        {
            // for (int i=0; i < collection.Count; ++i) Add(collection[i]);

            ++m_version;

            Capacity += collection.Count;
            Array.Copy(collection.m_array, 0, this.m_array, m_count, collection.m_count);
            m_count += collection.Count;
        }

        public void AddRange(T[] array)
        {
            // for (int i=0; i < array.Length; ++i) Add(array[i]);

            ++m_version;

            Capacity += array.Length;
            Array.Copy(array, 0, this.m_array, m_count, array.Length);
            m_count += array.Length;
        }

        //
        // Implementation

        private void ValidateIndex(int index)
        {
            ValidateIndex(index,false);
        }

        private void ValidateIndex(int index, bool allowEqualEnd)
        {
            int max = (allowEqualEnd)?(m_count):(m_count-1);
            if (index < 0 || index > max)
                throw new System.ArgumentOutOfRangeException("Index was out of range.  Must be non-negative and less than the size of the collection.", (object)index, "Specified argument was out of the range of valid values.");
        }

        private bool NeedsGrowth()
        {
            return (m_count >= Capacity);
        }

        private void Grow()
        {
            if (NeedsGrowth())
                Capacity = m_count*2;
        }

        private bool NeedsTrimming()
        {
            return (m_count <= Capacity/2);
        }

        private void Trim()
        {
            if (NeedsTrimming())
                Capacity = m_count;
        }

        bool ICollection.IsSynchronized
        {
            get
            { return m_array.IsSynchronized; }
        }

        object ICollection.SyncRoot
        {
            get
            { return m_array.SyncRoot; }
        }

        void ICollection.CopyTo(Array array, int start)
        {
            this.CopyTo((T[])array, start);
        }

        bool IList.IsFixedSize
        {
            get
            { return false; }
        }

        bool IList.IsReadOnly
        {
            get
            { return false; }
        }

        object IList.this[int index]
        {
            get
            { return (object)this[index]; }
            set
            { this[index] = (T)value; }
        }

        int IList.Add(object item)
        {
            return this.Add((T)item);
        }

        bool IList.Contains(object item)
        {
            return this.Contains((T)item);
        }

        int IList.IndexOf(object item)
        {
            return this.IndexOf((T)item);
        }

        void IList.Insert(int position, object item)
        {
            this.Insert(position, (T)item);
        }

        void IList.Remove(object item)
        {
            this.Remove((T)item);
        }

        IEnumerator IEnumerable.GetEnumerator()
        {
            return (IEnumerator)(this.GetEnumerator());
        }

        object ICloneable.Clone()
        {
            return (object)(this.Clone());
        }

    }
}

Updated: Thu, 06 May 2004 03:08:45 GMT