267 lines
		
	
	
		
			8.0 KiB
		
	
	
	
		
			C#
		
	
	
		
		
			
		
	
	
			267 lines
		
	
	
		
			8.0 KiB
		
	
	
	
		
			C#
		
	
	
| 
								 | 
							
								using System;
							 | 
						|||
| 
								 | 
							
								using System.Collections;
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								namespace ProtoBuf.Meta
							 | 
						|||
| 
								 | 
							
								{
							 | 
						|||
| 
								 | 
							
								    internal sealed class MutableList : BasicList
							 | 
						|||
| 
								 | 
							
								    {
							 | 
						|||
| 
								 | 
							
								        /*  Like BasicList, but allows existing values to be changed
							 | 
						|||
| 
								 | 
							
								         */
							 | 
						|||
| 
								 | 
							
								        public new object this[int index]
							 | 
						|||
| 
								 | 
							
								        {
							 | 
						|||
| 
								 | 
							
								            get { return head[index]; }
							 | 
						|||
| 
								 | 
							
								            set { head[index] = value; }
							 | 
						|||
| 
								 | 
							
								        }
							 | 
						|||
| 
								 | 
							
								        public void RemoveLast()
							 | 
						|||
| 
								 | 
							
								        {
							 | 
						|||
| 
								 | 
							
								            head.RemoveLastWithMutate();
							 | 
						|||
| 
								 | 
							
								        }
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								        public void Clear()
							 | 
						|||
| 
								 | 
							
								        {
							 | 
						|||
| 
								 | 
							
								            head.Clear();
							 | 
						|||
| 
								 | 
							
								        }
							 | 
						|||
| 
								 | 
							
								    }
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								    internal class BasicList : IEnumerable
							 | 
						|||
| 
								 | 
							
								    {
							 | 
						|||
| 
								 | 
							
								        /* Requirements:
							 | 
						|||
| 
								 | 
							
								         *   - Fast access by index
							 | 
						|||
| 
								 | 
							
								         *   - Immutable in the tail, so a node can be read (iterated) without locking
							 | 
						|||
| 
								 | 
							
								         *   - Lock-free tail handling must match the memory mode; struct for Node
							 | 
						|||
| 
								 | 
							
								         *     wouldn't work as "read" would not be atomic
							 | 
						|||
| 
								 | 
							
								         *   - Only operation required is append, but this shouldn't go out of its
							 | 
						|||
| 
								 | 
							
								         *     way to be inefficient
							 | 
						|||
| 
								 | 
							
								         *   - Assume that the caller is handling thread-safety (to co-ordinate with
							 | 
						|||
| 
								 | 
							
								         *     other code); no attempt to be thread-safe
							 | 
						|||
| 
								 | 
							
								         *   - Assume that the data is private; internal data structure is allowed to
							 | 
						|||
| 
								 | 
							
								         *     be mutable (i.e. array is fine as long as we don't screw it up)
							 | 
						|||
| 
								 | 
							
								         */
							 | 
						|||
| 
								 | 
							
								        private static readonly Node nil = new Node(null, 0);
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								        public void CopyTo(Array array, int offset)
							 | 
						|||
| 
								 | 
							
								        {
							 | 
						|||
| 
								 | 
							
								            head.CopyTo(array, offset);
							 | 
						|||
| 
								 | 
							
								        }
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								        protected Node head = nil;
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								        public int Add(object value)
							 | 
						|||
| 
								 | 
							
								        {
							 | 
						|||
| 
								 | 
							
								            return (head = head.Append(value)).Length - 1;
							 | 
						|||
| 
								 | 
							
								        }
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								        public object this[int index] => head[index];
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								        //public object TryGet(int index)
							 | 
						|||
| 
								 | 
							
								        //{
							 | 
						|||
| 
								 | 
							
								        //    return head.TryGet(index);
							 | 
						|||
| 
								 | 
							
								        //}
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								        public void Trim() { head = head.Trim(); }
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								        public int Count => head.Length;
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								        IEnumerator IEnumerable.GetEnumerator() => new NodeEnumerator(head);
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								        public NodeEnumerator GetEnumerator() => new NodeEnumerator(head);
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								        public struct NodeEnumerator : IEnumerator
							 | 
						|||
| 
								 | 
							
								        {
							 | 
						|||
| 
								 | 
							
								            private int position;
							 | 
						|||
| 
								 | 
							
								            private readonly Node node;
							 | 
						|||
| 
								 | 
							
								            internal NodeEnumerator(Node node)
							 | 
						|||
| 
								 | 
							
								            {
							 | 
						|||
| 
								 | 
							
								                this.position = -1;
							 | 
						|||
| 
								 | 
							
								                this.node = node;
							 | 
						|||
| 
								 | 
							
								            }
							 | 
						|||
| 
								 | 
							
								            void IEnumerator.Reset() { position = -1; }
							 | 
						|||
| 
								 | 
							
								            public object Current { get { return node[position]; } }
							 | 
						|||
| 
								 | 
							
								            public bool MoveNext()
							 | 
						|||
| 
								 | 
							
								            {
							 | 
						|||
| 
								 | 
							
								                int len = node.Length;
							 | 
						|||
| 
								 | 
							
								                return (position <= len) && (++position < len);
							 | 
						|||
| 
								 | 
							
								            }
							 | 
						|||
| 
								 | 
							
								        }
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								        internal sealed class Node
							 | 
						|||
| 
								 | 
							
								        {
							 | 
						|||
| 
								 | 
							
								            public object this[int index]
							 | 
						|||
| 
								 | 
							
								            {
							 | 
						|||
| 
								 | 
							
								                get
							 | 
						|||
| 
								 | 
							
								                {
							 | 
						|||
| 
								 | 
							
								                    if (index >= 0 && index < length)
							 | 
						|||
| 
								 | 
							
								                    {
							 | 
						|||
| 
								 | 
							
								                        return data[index];
							 | 
						|||
| 
								 | 
							
								                    }
							 | 
						|||
| 
								 | 
							
								                    throw new ArgumentOutOfRangeException(nameof(index));
							 | 
						|||
| 
								 | 
							
								                }
							 | 
						|||
| 
								 | 
							
								                set
							 | 
						|||
| 
								 | 
							
								                {
							 | 
						|||
| 
								 | 
							
								                    if (index >= 0 && index < length)
							 | 
						|||
| 
								 | 
							
								                    {
							 | 
						|||
| 
								 | 
							
								                        data[index] = value;
							 | 
						|||
| 
								 | 
							
								                    }
							 | 
						|||
| 
								 | 
							
								                    else
							 | 
						|||
| 
								 | 
							
								                    {
							 | 
						|||
| 
								 | 
							
								                        throw new ArgumentOutOfRangeException(nameof(index));
							 | 
						|||
| 
								 | 
							
								                    }
							 | 
						|||
| 
								 | 
							
								                }
							 | 
						|||
| 
								 | 
							
								            }
							 | 
						|||
| 
								 | 
							
								            //public object TryGet(int index)
							 | 
						|||
| 
								 | 
							
								            //{
							 | 
						|||
| 
								 | 
							
								            //    return (index >= 0 && index < length) ? data[index] : null;
							 | 
						|||
| 
								 | 
							
								            //}
							 | 
						|||
| 
								 | 
							
								            private readonly object[] data;
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								            private int length;
							 | 
						|||
| 
								 | 
							
								            public int Length => length;
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								            internal Node(object[] data, int length)
							 | 
						|||
| 
								 | 
							
								            {
							 | 
						|||
| 
								 | 
							
								                Helpers.DebugAssert((data == null && length == 0) ||
							 | 
						|||
| 
								 | 
							
								                    (data != null && length > 0 && length <= data.Length));
							 | 
						|||
| 
								 | 
							
								                this.data = data;
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								                this.length = length;
							 | 
						|||
| 
								 | 
							
								            }
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								            public void RemoveLastWithMutate()
							 | 
						|||
| 
								 | 
							
								            {
							 | 
						|||
| 
								 | 
							
								                if (length == 0) throw new InvalidOperationException();
							 | 
						|||
| 
								 | 
							
								                length -= 1;
							 | 
						|||
| 
								 | 
							
								            }
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								            public Node Append(object value)
							 | 
						|||
| 
								 | 
							
								            {
							 | 
						|||
| 
								 | 
							
								                object[] newData;
							 | 
						|||
| 
								 | 
							
								                int newLength = length + 1;
							 | 
						|||
| 
								 | 
							
								                if (data == null)
							 | 
						|||
| 
								 | 
							
								                {
							 | 
						|||
| 
								 | 
							
								                    newData = new object[10];
							 | 
						|||
| 
								 | 
							
								                }
							 | 
						|||
| 
								 | 
							
								                else if (length == data.Length)
							 | 
						|||
| 
								 | 
							
								                {
							 | 
						|||
| 
								 | 
							
								                    newData = new object[data.Length * 2];
							 | 
						|||
| 
								 | 
							
								                    Array.Copy(data, newData, length);
							 | 
						|||
| 
								 | 
							
								                }
							 | 
						|||
| 
								 | 
							
								                else
							 | 
						|||
| 
								 | 
							
								                {
							 | 
						|||
| 
								 | 
							
								                    newData = data;
							 | 
						|||
| 
								 | 
							
								                }
							 | 
						|||
| 
								 | 
							
								                newData[length] = value;
							 | 
						|||
| 
								 | 
							
								                return new Node(newData, newLength);
							 | 
						|||
| 
								 | 
							
								            }
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								            public Node Trim()
							 | 
						|||
| 
								 | 
							
								            {
							 | 
						|||
| 
								 | 
							
								                if (length == 0 || length == data.Length) return this;
							 | 
						|||
| 
								 | 
							
								                object[] newData = new object[length];
							 | 
						|||
| 
								 | 
							
								                Array.Copy(data, newData, length);
							 | 
						|||
| 
								 | 
							
								                return new Node(newData, length);
							 | 
						|||
| 
								 | 
							
								            }
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								            internal int IndexOfString(string value)
							 | 
						|||
| 
								 | 
							
								            {
							 | 
						|||
| 
								 | 
							
								                for (int i = 0; i < length; i++)
							 | 
						|||
| 
								 | 
							
								                {
							 | 
						|||
| 
								 | 
							
								                    if ((string)value == (string)data[i]) return i;
							 | 
						|||
| 
								 | 
							
								                }
							 | 
						|||
| 
								 | 
							
								                return -1;
							 | 
						|||
| 
								 | 
							
								            }
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								            internal int IndexOfReference(object instance)
							 | 
						|||
| 
								 | 
							
								            {
							 | 
						|||
| 
								 | 
							
								                for (int i = 0; i < length; i++)
							 | 
						|||
| 
								 | 
							
								                {
							 | 
						|||
| 
								 | 
							
								                    if ((object)instance == (object)data[i]) return i;
							 | 
						|||
| 
								 | 
							
								                } // ^^^ (object) above should be preserved, even if this was typed; needs
							 | 
						|||
| 
								 | 
							
								                  // to be a reference check
							 | 
						|||
| 
								 | 
							
								                return -1;
							 | 
						|||
| 
								 | 
							
								            }
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								            internal int IndexOf(MatchPredicate predicate, object ctx)
							 | 
						|||
| 
								 | 
							
								            {
							 | 
						|||
| 
								 | 
							
								                for (int i = 0; i < length; i++)
							 | 
						|||
| 
								 | 
							
								                {
							 | 
						|||
| 
								 | 
							
								                    if (predicate(data[i], ctx)) return i;
							 | 
						|||
| 
								 | 
							
								                }
							 | 
						|||
| 
								 | 
							
								                return -1;
							 | 
						|||
| 
								 | 
							
								            }
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								            internal void CopyTo(Array array, int offset)
							 | 
						|||
| 
								 | 
							
								            {
							 | 
						|||
| 
								 | 
							
								                if (length > 0)
							 | 
						|||
| 
								 | 
							
								                {
							 | 
						|||
| 
								 | 
							
								                    Array.Copy(data, 0, array, offset, length);
							 | 
						|||
| 
								 | 
							
								                }
							 | 
						|||
| 
								 | 
							
								            }
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								            internal void Clear()
							 | 
						|||
| 
								 | 
							
								            {
							 | 
						|||
| 
								 | 
							
								                if (data != null)
							 | 
						|||
| 
								 | 
							
								                {
							 | 
						|||
| 
								 | 
							
								                    Array.Clear(data, 0, data.Length);
							 | 
						|||
| 
								 | 
							
								                }
							 | 
						|||
| 
								 | 
							
								                length = 0;
							 | 
						|||
| 
								 | 
							
								            }
							 | 
						|||
| 
								 | 
							
								        }
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								        internal int IndexOf(MatchPredicate predicate, object ctx)
							 | 
						|||
| 
								 | 
							
								        {
							 | 
						|||
| 
								 | 
							
								            return head.IndexOf(predicate, ctx);
							 | 
						|||
| 
								 | 
							
								        }
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								        internal int IndexOfString(string value)
							 | 
						|||
| 
								 | 
							
								        {
							 | 
						|||
| 
								 | 
							
								            return head.IndexOfString(value);
							 | 
						|||
| 
								 | 
							
								        }
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								        internal int IndexOfReference(object instance)
							 | 
						|||
| 
								 | 
							
								        {
							 | 
						|||
| 
								 | 
							
								            return head.IndexOfReference(instance);
							 | 
						|||
| 
								 | 
							
								        }
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								        internal delegate bool MatchPredicate(object value, object ctx);
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								        internal bool Contains(object value)
							 | 
						|||
| 
								 | 
							
								        {
							 | 
						|||
| 
								 | 
							
								            foreach (object obj in this)
							 | 
						|||
| 
								 | 
							
								            {
							 | 
						|||
| 
								 | 
							
								                if (object.Equals(obj, value)) return true;
							 | 
						|||
| 
								 | 
							
								            }
							 | 
						|||
| 
								 | 
							
								            return false;
							 | 
						|||
| 
								 | 
							
								        }
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								        internal sealed class Group
							 | 
						|||
| 
								 | 
							
								        {
							 | 
						|||
| 
								 | 
							
								            public readonly int First;
							 | 
						|||
| 
								 | 
							
								            public readonly BasicList Items;
							 | 
						|||
| 
								 | 
							
								            public Group(int first)
							 | 
						|||
| 
								 | 
							
								            {
							 | 
						|||
| 
								 | 
							
								                this.First = first;
							 | 
						|||
| 
								 | 
							
								                this.Items = new BasicList();
							 | 
						|||
| 
								 | 
							
								            }
							 | 
						|||
| 
								 | 
							
								        }
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								        internal static BasicList GetContiguousGroups(int[] keys, object[] values)
							 | 
						|||
| 
								 | 
							
								        {
							 | 
						|||
| 
								 | 
							
								            if (keys == null) throw new ArgumentNullException(nameof(keys));
							 | 
						|||
| 
								 | 
							
								            if (values == null) throw new ArgumentNullException(nameof(values));
							 | 
						|||
| 
								 | 
							
								            if (values.Length < keys.Length) throw new ArgumentException("Not all keys are covered by values", nameof(values));
							 | 
						|||
| 
								 | 
							
								            BasicList outer = new BasicList();
							 | 
						|||
| 
								 | 
							
								            Group group = null;
							 | 
						|||
| 
								 | 
							
								            for (int i = 0; i < keys.Length; i++)
							 | 
						|||
| 
								 | 
							
								            {
							 | 
						|||
| 
								 | 
							
								                if (i == 0 || keys[i] != keys[i - 1]) { group = null; }
							 | 
						|||
| 
								 | 
							
								                if (group == null)
							 | 
						|||
| 
								 | 
							
								                {
							 | 
						|||
| 
								 | 
							
								                    group = new Group(keys[i]);
							 | 
						|||
| 
								 | 
							
								                    outer.Add(group);
							 | 
						|||
| 
								 | 
							
								                }
							 | 
						|||
| 
								 | 
							
								                group.Items.Add(values[i]);
							 | 
						|||
| 
								 | 
							
								            }
							 | 
						|||
| 
								 | 
							
								            return outer;
							 | 
						|||
| 
								 | 
							
								        }
							 | 
						|||
| 
								 | 
							
								    }
							 | 
						|||
| 
								 | 
							
								}
							 |