aboutsummaryrefslogblamecommitdiff
path: root/csharp/src/ProtocolBuffers/Collections/RepeatedField.cs
blob: 0cd5cf808308ce920c2567330ad4651bd982fdca (plain) (tree)
1
2
3
4
5
6
7
8







                                                                                 




















                                                                   






                                                        












                                                                                        



                           

                         



                                    
                                       



                                                     




                                                                



                                  

                                      
             





                                                                          

         
                                                  









                                                                          
                                             
                                                                                       

                                                                    







                                                          
                                                             





                                      
                                                          
         
                                        



                                                     
                                   






                                                   













                                                                         


                                         
                                           
             
                                                          



                        















                                                                       
                                           
             
                                                               












                                                        













                                                                       







                                                        






                                                                      



                                       






                                                                          



                                







                                                                   

               



                                                                   



                                                             

























































































                                                                           



             
using System;
using System.Collections;
using System.Collections.Generic;

namespace Google.Protobuf.Collections
{
    public sealed class RepeatedField<T> : IList<T>, IEquatable<RepeatedField<T>>
    {
        private const int MinArraySize = 8;
        private T[] array = null;
        private int count = 0;

        private void EnsureSize(int size)
        {
            if (array == null)
            {
                array = new T[Math.Max(size, MinArraySize)];
            }
            else
            {
                if (array.Length < size)
                {
                    int newSize = Math.Max(array.Length * 2, size);
                    var tmp = new T[newSize];
                    Array.Copy(array, 0, tmp, 0, array.Length);
                    array = tmp;
                }
            }
        }

        public void Add(T item)
        {
            if (item == null)
            {
                throw new ArgumentNullException("item");
            }
            EnsureSize(count + 1);
            array[count++] = item;
        }

        /// <summary>
        /// Hack to allow us to add enums easily... will only work with int-based types.
        /// </summary>
        /// <param name="readEnum"></param>
        internal void AddInt32(int item)
        {
            EnsureSize(count + 1);
            int[] castArray = (int[]) (object) array;
            castArray[count++] = item;
        }

        public void Clear()
        {
            array = null;
            count = 0;
        }

        public bool Contains(T item)
        {
            return IndexOf(item) != -1;
        }

        public void CopyTo(T[] array, int arrayIndex)
        {
            if (this.array == null)
            {
                return;
            }
            Array.Copy(this.array, 0, array, arrayIndex, count);
        }

        public bool Remove(T item)
        {
            int index = IndexOf(item);
            if (index == -1)
            {
                return false;
            }            
            Array.Copy(array, index + 1, array, index, count - index - 1);
            count--;
            array[count] = default(T);
            return true;
        }

        public int Count { get { return count; } }

        // TODO(jonskeet): If we implement freezing, make this reflect it.
        public bool IsReadOnly { get { return false; } }

        public void Add(RepeatedField<T> values)
        {
            if (values == null)
            {
                throw new ArgumentNullException("values");
            }
            EnsureSize(count + values.count);
            // We know that all the values will be valid, because it's a RepeatedField.
            Array.Copy(values.array, 0, array, count, values.count);
            count += values.count;
        }

        public void Add(IEnumerable<T> values)
        {
            if (values == null)
            {
                throw new ArgumentNullException("values");
            }
            // TODO: Check for ICollection and get the Count?
            foreach (T item in values)
            {
                Add(item);
            }
        }

        public RepeatedField<T>.Enumerator GetEnumerator()
        {
            return new Enumerator(this);
        }

        IEnumerator<T> IEnumerable<T>.GetEnumerator()
        {
            return GetEnumerator();
        }

        public override bool Equals(object obj)
        {
            return Equals(obj as RepeatedField<T>);
        }

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

        /// <summary>
        /// Returns an enumerator of the values in this list as integers.
        /// Used for enum types.
        /// </summary>
        internal Int32Enumerator GetInt32Enumerator()
        {
            return new Int32Enumerator((int[])(object)array, count);
        }

        public override int GetHashCode()
        {
            int hash = 23;
            for (int i = 0; i < count; i++)
            {
                hash = hash * 31 + array[i].GetHashCode();
            }
            return hash;
        }

        public bool Equals(RepeatedField<T> other)
        {
            if (ReferenceEquals(other, null))
            {
                return false;
            }
            if (ReferenceEquals(other, this))
            {
                return true;
            }
            if (other.Count != this.Count)
            {
                return false;
            }
            // TODO(jonskeet): Does this box for enums?
            EqualityComparer<T> comparer = EqualityComparer<T>.Default;
            for (int i = 0; i < count; i++)
            {
                if (!comparer.Equals(array[i], other.array[i]))
                {
                    return false;
                }
            }
            return true;
        }

        public int IndexOf(T item)
        {
            if (item == null)
            {
                throw new ArgumentNullException("item");
            }
            if (array == null)
            {
                return -1;
            }
            // TODO(jonskeet): Does this box for enums?
            EqualityComparer<T> comparer = EqualityComparer<T>.Default;
            for (int i = 0; i < count; i++)
            {
                if (comparer.Equals(array[i], item))
                {
                    return i;
                }
            }
            return -1;
        }

        public void Insert(int index, T item)
        {
            if (item == null)
            {
                throw new ArgumentNullException("item");
            }
            if (index < 0 || index > count)
            {
                throw new ArgumentOutOfRangeException("index");
            }
            EnsureSize(count + 1);
            Array.Copy(array, index, array, index + 1, count - index);
            count++;
        }

        public void RemoveAt(int index)
        {
            if (index < 0 || index >= count)
            {
                throw new ArgumentOutOfRangeException("index");
            }
            Array.Copy(array, index + 1, array, index, count - index - 1);
            count--;
            array[count] = default(T);
        }

        public T this[int index]
        {
            get
            {
                if (index < 0 || index >= count)
                {
                    throw new ArgumentOutOfRangeException("index");
                }
                return array[index];
            }
            set
            {
                if (index < 0 || index >= count)
                {
                    throw new ArgumentOutOfRangeException("index");
                }
                if (value == null)
                {
                    throw new ArgumentNullException("value");
                }
                array[index] = value;
            }
        }

        public struct Enumerator : IEnumerator<T>
        {
            private int index;
            private readonly RepeatedField<T> field;

            public Enumerator(RepeatedField<T> field)
            {
                this.field = field;
                this.index = -1;
            }

            public bool MoveNext()
            {
                if (index + 1 >= field.Count)
                {
                    return false;
                }
                index++;
                return true;
            }

            public void Reset()
            {
                index = -1;
            }

            public T Current
            {
                get
                {
                    if (index == -1 || index >= field.count)
                    {
                        throw new InvalidOperationException();
                    }
                    return field.array[index];
                }
            }

            object IEnumerator.Current
            {
                get { return Current; }
            }

            public void Dispose()
            {
            }
        }

        internal struct Int32Enumerator : IEnumerator<int>
        {
            private int index;
            private readonly int[] array;
            private readonly int count;

            public Int32Enumerator(int[] array, int count)
            {
                this.array = array;
                this.index = -1;
                this.count = count;
            }

            public bool MoveNext()
            {
                if (index + 1 >= count)
                {
                    return false;
                }
                index++;
                return true;
            }

            public void Reset()
            {
                index = -1;
            }

            // No guard here, as we're only going to use this internally...
            public int Current { get { return array[index]; } }

            object IEnumerator.Current
            {
                get { return Current; }
            }

            public void Dispose()
            {
            }
        }
    }
}