277 lines
4.5 KiB
C#
277 lines
4.5 KiB
C#
using System;
|
|
using System.Collections;
|
|
|
|
namespace ProtoBuf.Meta;
|
|
|
|
internal class BasicList : IEnumerable
|
|
{
|
|
public struct NodeEnumerator : IEnumerator
|
|
{
|
|
private int position;
|
|
|
|
private readonly Node node;
|
|
|
|
public object Current => node[position];
|
|
|
|
internal NodeEnumerator(Node node)
|
|
{
|
|
position = -1;
|
|
this.node = node;
|
|
}
|
|
|
|
void IEnumerator.Reset()
|
|
{
|
|
position = -1;
|
|
}
|
|
|
|
public bool MoveNext()
|
|
{
|
|
int length = node.Length;
|
|
if (position <= length)
|
|
{
|
|
return ++position < length;
|
|
}
|
|
return false;
|
|
}
|
|
}
|
|
|
|
internal sealed class Node
|
|
{
|
|
private readonly object[] data;
|
|
|
|
private int length;
|
|
|
|
public object this[int index]
|
|
{
|
|
get
|
|
{
|
|
if (index >= 0 && index < length)
|
|
{
|
|
return data[index];
|
|
}
|
|
throw new ArgumentOutOfRangeException("index");
|
|
}
|
|
set
|
|
{
|
|
if (index >= 0 && index < length)
|
|
{
|
|
data[index] = value;
|
|
return;
|
|
}
|
|
throw new ArgumentOutOfRangeException("index");
|
|
}
|
|
}
|
|
|
|
public int Length => length;
|
|
|
|
internal Node(object[] data, int length)
|
|
{
|
|
this.data = data;
|
|
this.length = length;
|
|
}
|
|
|
|
public void RemoveLastWithMutate()
|
|
{
|
|
if (length == 0)
|
|
{
|
|
throw new InvalidOperationException();
|
|
}
|
|
length--;
|
|
}
|
|
|
|
public Node Append(object value)
|
|
{
|
|
int num = length + 1;
|
|
object[] array;
|
|
if (data == null)
|
|
{
|
|
array = new object[10];
|
|
}
|
|
else if (length == data.Length)
|
|
{
|
|
array = new object[data.Length * 2];
|
|
Array.Copy(data, array, length);
|
|
}
|
|
else
|
|
{
|
|
array = data;
|
|
}
|
|
array[length] = value;
|
|
return new Node(array, num);
|
|
}
|
|
|
|
public Node Trim()
|
|
{
|
|
if (length == 0 || length == data.Length)
|
|
{
|
|
return this;
|
|
}
|
|
object[] destinationArray = new object[length];
|
|
Array.Copy(data, destinationArray, length);
|
|
return new Node(destinationArray, length);
|
|
}
|
|
|
|
internal int IndexOfString(string value)
|
|
{
|
|
for (int i = 0; i < length; i++)
|
|
{
|
|
if (value == (string)data[i])
|
|
{
|
|
return i;
|
|
}
|
|
}
|
|
return -1;
|
|
}
|
|
|
|
internal int IndexOfReference(object instance)
|
|
{
|
|
for (int i = 0; i < length; i++)
|
|
{
|
|
if (instance == data[i])
|
|
{
|
|
return i;
|
|
}
|
|
}
|
|
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 delegate bool MatchPredicate(object value, object ctx);
|
|
|
|
internal sealed class Group
|
|
{
|
|
public readonly int First;
|
|
|
|
public readonly BasicList Items;
|
|
|
|
public Group(int first)
|
|
{
|
|
First = first;
|
|
Items = new BasicList();
|
|
}
|
|
}
|
|
|
|
private static readonly Node nil = new Node(null, 0);
|
|
|
|
protected Node head = nil;
|
|
|
|
public object this[int index] => head[index];
|
|
|
|
public int Count => head.Length;
|
|
|
|
public void CopyTo(Array array, int offset)
|
|
{
|
|
head.CopyTo(array, offset);
|
|
}
|
|
|
|
public int Add(object value)
|
|
{
|
|
return (head = head.Append(value)).Length - 1;
|
|
}
|
|
|
|
public void Trim()
|
|
{
|
|
head = head.Trim();
|
|
}
|
|
|
|
IEnumerator IEnumerable.GetEnumerator()
|
|
{
|
|
return new NodeEnumerator(head);
|
|
}
|
|
|
|
public NodeEnumerator GetEnumerator()
|
|
{
|
|
return new NodeEnumerator(head);
|
|
}
|
|
|
|
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 bool Contains(object value)
|
|
{
|
|
NodeEnumerator enumerator = GetEnumerator();
|
|
while (enumerator.MoveNext())
|
|
{
|
|
object current = enumerator.Current;
|
|
if (object.Equals(current, value))
|
|
{
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
internal static BasicList GetContiguousGroups(int[] keys, object[] values)
|
|
{
|
|
if (keys == null)
|
|
{
|
|
throw new ArgumentNullException("keys");
|
|
}
|
|
if (values == null)
|
|
{
|
|
throw new ArgumentNullException("values");
|
|
}
|
|
if (values.Length < keys.Length)
|
|
{
|
|
throw new ArgumentException("Not all keys are covered by values", "values");
|
|
}
|
|
BasicList basicList = new BasicList();
|
|
Group obj = null;
|
|
for (int i = 0; i < keys.Length; i++)
|
|
{
|
|
if (i == 0 || keys[i] != keys[i - 1])
|
|
{
|
|
obj = null;
|
|
}
|
|
if (obj == null)
|
|
{
|
|
obj = new Group(keys[i]);
|
|
basicList.Add(obj);
|
|
}
|
|
obj.Items.Add(values[i]);
|
|
}
|
|
return basicList;
|
|
}
|
|
}
|