724 lines
16 KiB
C#
724 lines
16 KiB
C#
using System;
|
|
|
|
namespace System.Collections.Generic
|
|
{
|
|
// Token: 0x02000010 RID: 16
|
|
internal class RBTree : IEnumerable, IEnumerable<RBTree.Node>
|
|
{
|
|
// Token: 0x0600005C RID: 92 RVA: 0x00003348 File Offset: 0x00001548
|
|
public RBTree(object hlp)
|
|
{
|
|
this.hlp = hlp;
|
|
}
|
|
|
|
// Token: 0x0600005D RID: 93 RVA: 0x00003358 File Offset: 0x00001558
|
|
IEnumerator<RBTree.Node> IEnumerable<RBTree.Node>.GetEnumerator()
|
|
{
|
|
return this.GetEnumerator();
|
|
}
|
|
|
|
// Token: 0x0600005E RID: 94 RVA: 0x00003368 File Offset: 0x00001568
|
|
IEnumerator IEnumerable.GetEnumerator()
|
|
{
|
|
return this.GetEnumerator();
|
|
}
|
|
|
|
// Token: 0x0600005F RID: 95 RVA: 0x00003378 File Offset: 0x00001578
|
|
private static List<RBTree.Node> alloc_path()
|
|
{
|
|
if (RBTree.cached_path == null)
|
|
{
|
|
return new List<RBTree.Node>();
|
|
}
|
|
List<RBTree.Node> list = RBTree.cached_path;
|
|
RBTree.cached_path = null;
|
|
return list;
|
|
}
|
|
|
|
// Token: 0x06000060 RID: 96 RVA: 0x000033A4 File Offset: 0x000015A4
|
|
private static void release_path(List<RBTree.Node> path)
|
|
{
|
|
if (RBTree.cached_path == null || RBTree.cached_path.Capacity < path.Capacity)
|
|
{
|
|
path.Clear();
|
|
RBTree.cached_path = path;
|
|
}
|
|
}
|
|
|
|
// Token: 0x06000061 RID: 97 RVA: 0x000033D4 File Offset: 0x000015D4
|
|
public void Clear()
|
|
{
|
|
this.root = null;
|
|
this.version += 1U;
|
|
}
|
|
|
|
// Token: 0x06000062 RID: 98 RVA: 0x000033EC File Offset: 0x000015EC
|
|
public RBTree.Node Intern<T>(T key, RBTree.Node new_node)
|
|
{
|
|
if (this.root == null)
|
|
{
|
|
if (new_node == null)
|
|
{
|
|
new_node = ((RBTree.INodeHelper<T>)this.hlp).CreateNode(key);
|
|
}
|
|
this.root = new_node;
|
|
this.root.IsBlack = true;
|
|
this.version += 1U;
|
|
return this.root;
|
|
}
|
|
List<RBTree.Node> list = RBTree.alloc_path();
|
|
int num = this.find_key<T>(key, list);
|
|
RBTree.Node node = list[list.Count - 1];
|
|
if (node == null)
|
|
{
|
|
if (new_node == null)
|
|
{
|
|
new_node = ((RBTree.INodeHelper<T>)this.hlp).CreateNode(key);
|
|
}
|
|
node = this.do_insert(num, new_node, list);
|
|
}
|
|
RBTree.release_path(list);
|
|
return node;
|
|
}
|
|
|
|
// Token: 0x06000063 RID: 99 RVA: 0x00003494 File Offset: 0x00001694
|
|
public RBTree.Node Remove<T>(T key)
|
|
{
|
|
if (this.root == null)
|
|
{
|
|
return null;
|
|
}
|
|
List<RBTree.Node> list = RBTree.alloc_path();
|
|
int num = this.find_key<T>(key, list);
|
|
RBTree.Node node = null;
|
|
if (num == 0)
|
|
{
|
|
node = this.do_remove(list);
|
|
}
|
|
RBTree.release_path(list);
|
|
return node;
|
|
}
|
|
|
|
// Token: 0x06000064 RID: 100 RVA: 0x000034D4 File Offset: 0x000016D4
|
|
public RBTree.Node Lookup<T>(T key)
|
|
{
|
|
RBTree.INodeHelper<T> nodeHelper = (RBTree.INodeHelper<T>)this.hlp;
|
|
RBTree.Node node;
|
|
int num;
|
|
for (node = this.root; node != null; node = ((num >= 0) ? node.right : node.left))
|
|
{
|
|
num = nodeHelper.Compare(key, node);
|
|
if (num == 0)
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
return node;
|
|
}
|
|
|
|
// Token: 0x17000015 RID: 21
|
|
// (get) Token: 0x06000065 RID: 101 RVA: 0x00003530 File Offset: 0x00001730
|
|
public int Count
|
|
{
|
|
get
|
|
{
|
|
return (int)((this.root != null) ? this.root.Size : 0U);
|
|
}
|
|
}
|
|
|
|
// Token: 0x17000016 RID: 22
|
|
public RBTree.Node this[int index]
|
|
{
|
|
get
|
|
{
|
|
if (index < 0 || index >= this.Count)
|
|
{
|
|
throw new IndexOutOfRangeException("index");
|
|
}
|
|
RBTree.Node node = this.root;
|
|
while (node != null)
|
|
{
|
|
int num = (int)((node.left != null) ? node.left.Size : 0U);
|
|
if (index == num)
|
|
{
|
|
return node;
|
|
}
|
|
if (index < num)
|
|
{
|
|
node = node.left;
|
|
}
|
|
else
|
|
{
|
|
index -= num + 1;
|
|
node = node.right;
|
|
}
|
|
}
|
|
throw new SystemException("Internal Error: index calculation");
|
|
}
|
|
}
|
|
|
|
// Token: 0x06000067 RID: 103 RVA: 0x000035E0 File Offset: 0x000017E0
|
|
public RBTree.NodeEnumerator GetEnumerator()
|
|
{
|
|
return new RBTree.NodeEnumerator(this);
|
|
}
|
|
|
|
// Token: 0x06000068 RID: 104 RVA: 0x000035E8 File Offset: 0x000017E8
|
|
private int find_key<T>(T key, List<RBTree.Node> path)
|
|
{
|
|
RBTree.INodeHelper<T> nodeHelper = (RBTree.INodeHelper<T>)this.hlp;
|
|
int num = 0;
|
|
RBTree.Node node = this.root;
|
|
if (path != null)
|
|
{
|
|
path.Add(this.root);
|
|
}
|
|
while (node != null)
|
|
{
|
|
num = nodeHelper.Compare(key, node);
|
|
if (num == 0)
|
|
{
|
|
return num;
|
|
}
|
|
RBTree.Node node2;
|
|
if (num < 0)
|
|
{
|
|
node2 = node.right;
|
|
node = node.left;
|
|
}
|
|
else
|
|
{
|
|
node2 = node.left;
|
|
node = node.right;
|
|
}
|
|
if (path != null)
|
|
{
|
|
path.Add(node2);
|
|
path.Add(node);
|
|
}
|
|
}
|
|
return num;
|
|
}
|
|
|
|
// Token: 0x06000069 RID: 105 RVA: 0x00003678 File Offset: 0x00001878
|
|
private RBTree.Node do_insert(int in_tree_cmp, RBTree.Node current, List<RBTree.Node> path)
|
|
{
|
|
path[path.Count - 1] = current;
|
|
RBTree.Node node = path[path.Count - 3];
|
|
if (in_tree_cmp < 0)
|
|
{
|
|
node.left = current;
|
|
}
|
|
else
|
|
{
|
|
node.right = current;
|
|
}
|
|
for (int i = 0; i < path.Count - 2; i += 2)
|
|
{
|
|
path[i].Size += 1U;
|
|
}
|
|
if (!node.IsBlack)
|
|
{
|
|
this.rebalance_insert(path);
|
|
}
|
|
if (!this.root.IsBlack)
|
|
{
|
|
throw new SystemException("Internal error: root is not black");
|
|
}
|
|
this.version += 1U;
|
|
return current;
|
|
}
|
|
|
|
// Token: 0x0600006A RID: 106 RVA: 0x00003728 File Offset: 0x00001928
|
|
private RBTree.Node do_remove(List<RBTree.Node> path)
|
|
{
|
|
int num = path.Count - 1;
|
|
RBTree.Node node = path[num];
|
|
if (node.left != null)
|
|
{
|
|
RBTree.Node node2 = RBTree.right_most(node.left, node.right, path);
|
|
node.SwapValue(node2);
|
|
if (node2.left != null)
|
|
{
|
|
RBTree.Node left = node2.left;
|
|
path.Add(null);
|
|
path.Add(left);
|
|
node2.SwapValue(left);
|
|
}
|
|
}
|
|
else if (node.right != null)
|
|
{
|
|
RBTree.Node right = node.right;
|
|
path.Add(null);
|
|
path.Add(right);
|
|
node.SwapValue(right);
|
|
}
|
|
num = path.Count - 1;
|
|
node = path[num];
|
|
if (node.Size != 1U)
|
|
{
|
|
throw new SystemException("Internal Error: red-black violation somewhere");
|
|
}
|
|
path[num] = null;
|
|
this.node_reparent((num != 0) ? path[num - 2] : null, node, 0U, null);
|
|
for (int i = 0; i < path.Count - 2; i += 2)
|
|
{
|
|
path[i].Size -= 1U;
|
|
}
|
|
if (num != 0 && node.IsBlack)
|
|
{
|
|
this.rebalance_delete(path);
|
|
}
|
|
if (this.root != null && !this.root.IsBlack)
|
|
{
|
|
throw new SystemException("Internal Error: root is not black");
|
|
}
|
|
this.version += 1U;
|
|
return node;
|
|
}
|
|
|
|
// Token: 0x0600006B RID: 107 RVA: 0x00003890 File Offset: 0x00001A90
|
|
private void rebalance_insert(List<RBTree.Node> path)
|
|
{
|
|
int num = path.Count - 1;
|
|
while (path[num - 3] != null && !path[num - 3].IsBlack)
|
|
{
|
|
RBTree.Node node = path[num - 2];
|
|
bool flag = true;
|
|
path[num - 3].IsBlack = flag;
|
|
node.IsBlack = flag;
|
|
num -= 4;
|
|
if (num == 0)
|
|
{
|
|
return;
|
|
}
|
|
path[num].IsBlack = false;
|
|
if (path[num - 2].IsBlack)
|
|
{
|
|
return;
|
|
}
|
|
}
|
|
this.rebalance_insert__rotate_final(num, path);
|
|
}
|
|
|
|
// Token: 0x0600006C RID: 108 RVA: 0x0000391C File Offset: 0x00001B1C
|
|
private void rebalance_delete(List<RBTree.Node> path)
|
|
{
|
|
int num = path.Count - 1;
|
|
for (;;)
|
|
{
|
|
RBTree.Node node = path[num - 1];
|
|
if (!node.IsBlack)
|
|
{
|
|
num = this.ensure_sibling_black(num, path);
|
|
node = path[num - 1];
|
|
}
|
|
if ((node.left != null && !node.left.IsBlack) || (node.right != null && !node.right.IsBlack))
|
|
{
|
|
break;
|
|
}
|
|
node.IsBlack = false;
|
|
num -= 2;
|
|
if (num == 0)
|
|
{
|
|
return;
|
|
}
|
|
if (!path[num].IsBlack)
|
|
{
|
|
goto Block_5;
|
|
}
|
|
}
|
|
this.rebalance_delete__rotate_final(num, path);
|
|
return;
|
|
Block_5:
|
|
path[num].IsBlack = true;
|
|
}
|
|
|
|
// Token: 0x0600006D RID: 109 RVA: 0x000039CC File Offset: 0x00001BCC
|
|
private void rebalance_insert__rotate_final(int curpos, List<RBTree.Node> path)
|
|
{
|
|
RBTree.Node node = path[curpos];
|
|
RBTree.Node node2 = path[curpos - 2];
|
|
RBTree.Node node3 = path[curpos - 4];
|
|
uint size = node3.Size;
|
|
bool flag = node2 == node3.left;
|
|
bool flag2 = node == node2.left;
|
|
RBTree.Node node4;
|
|
if (flag && flag2)
|
|
{
|
|
node3.left = node2.right;
|
|
node2.right = node3;
|
|
node4 = node2;
|
|
}
|
|
else if (flag && !flag2)
|
|
{
|
|
node3.left = node.right;
|
|
node.right = node3;
|
|
node2.right = node.left;
|
|
node.left = node2;
|
|
node4 = node;
|
|
}
|
|
else if (!flag && flag2)
|
|
{
|
|
node3.right = node.left;
|
|
node.left = node3;
|
|
node2.left = node.right;
|
|
node.right = node2;
|
|
node4 = node;
|
|
}
|
|
else
|
|
{
|
|
node3.right = node2.left;
|
|
node2.left = node3;
|
|
node4 = node2;
|
|
}
|
|
node3.FixSize();
|
|
node3.IsBlack = false;
|
|
if (node4 != node2)
|
|
{
|
|
node2.FixSize();
|
|
}
|
|
node4.IsBlack = true;
|
|
this.node_reparent((curpos != 4) ? path[curpos - 6] : null, node3, size, node4);
|
|
}
|
|
|
|
// Token: 0x0600006E RID: 110 RVA: 0x00003B10 File Offset: 0x00001D10
|
|
private void rebalance_delete__rotate_final(int curpos, List<RBTree.Node> path)
|
|
{
|
|
RBTree.Node node = path[curpos - 1];
|
|
RBTree.Node node2 = path[curpos - 2];
|
|
uint size = node2.Size;
|
|
bool isBlack = node2.IsBlack;
|
|
RBTree.Node node3;
|
|
if (node2.right == node)
|
|
{
|
|
if (node.right == null || node.right.IsBlack)
|
|
{
|
|
RBTree.Node left = node.left;
|
|
node2.right = left.left;
|
|
left.left = node2;
|
|
node.left = left.right;
|
|
left.right = node;
|
|
node3 = left;
|
|
}
|
|
else
|
|
{
|
|
node2.right = node.left;
|
|
node.left = node2;
|
|
node.right.IsBlack = true;
|
|
node3 = node;
|
|
}
|
|
}
|
|
else if (node.left == null || node.left.IsBlack)
|
|
{
|
|
RBTree.Node right = node.right;
|
|
node2.left = right.right;
|
|
right.right = node2;
|
|
node.right = right.left;
|
|
right.left = node;
|
|
node3 = right;
|
|
}
|
|
else
|
|
{
|
|
node2.left = node.right;
|
|
node.right = node2;
|
|
node.left.IsBlack = true;
|
|
node3 = node;
|
|
}
|
|
node2.FixSize();
|
|
node2.IsBlack = true;
|
|
if (node3 != node)
|
|
{
|
|
node.FixSize();
|
|
}
|
|
node3.IsBlack = isBlack;
|
|
this.node_reparent((curpos != 2) ? path[curpos - 4] : null, node2, size, node3);
|
|
}
|
|
|
|
// Token: 0x0600006F RID: 111 RVA: 0x00003C88 File Offset: 0x00001E88
|
|
private int ensure_sibling_black(int curpos, List<RBTree.Node> path)
|
|
{
|
|
RBTree.Node node = path[curpos];
|
|
RBTree.Node node2 = path[curpos - 1];
|
|
RBTree.Node node3 = path[curpos - 2];
|
|
uint size = node3.Size;
|
|
bool flag;
|
|
if (node3.right == node2)
|
|
{
|
|
node3.right = node2.left;
|
|
node2.left = node3;
|
|
flag = true;
|
|
}
|
|
else
|
|
{
|
|
node3.left = node2.right;
|
|
node2.right = node3;
|
|
flag = false;
|
|
}
|
|
node3.FixSize();
|
|
node3.IsBlack = false;
|
|
node2.IsBlack = true;
|
|
this.node_reparent((curpos != 2) ? path[curpos - 4] : null, node3, size, node2);
|
|
if (curpos + 1 == path.Count)
|
|
{
|
|
path.Add(null);
|
|
path.Add(null);
|
|
}
|
|
path[curpos - 2] = node2;
|
|
path[curpos - 1] = ((!flag) ? node2.left : node2.right);
|
|
path[curpos] = node3;
|
|
path[curpos + 1] = ((!flag) ? node3.left : node3.right);
|
|
path[curpos + 2] = node;
|
|
return curpos + 2;
|
|
}
|
|
|
|
// Token: 0x06000070 RID: 112 RVA: 0x00003DA4 File Offset: 0x00001FA4
|
|
private void node_reparent(RBTree.Node orig_parent, RBTree.Node orig, uint orig_size, RBTree.Node updated)
|
|
{
|
|
if (updated != null && updated.FixSize() != orig_size)
|
|
{
|
|
throw new SystemException("Internal error: rotation");
|
|
}
|
|
if (orig == this.root)
|
|
{
|
|
this.root = updated;
|
|
}
|
|
else if (orig == orig_parent.left)
|
|
{
|
|
orig_parent.left = updated;
|
|
}
|
|
else
|
|
{
|
|
if (orig != orig_parent.right)
|
|
{
|
|
throw new SystemException("Internal error: path error");
|
|
}
|
|
orig_parent.right = updated;
|
|
}
|
|
}
|
|
|
|
// Token: 0x06000071 RID: 113 RVA: 0x00003E28 File Offset: 0x00002028
|
|
private static RBTree.Node right_most(RBTree.Node current, RBTree.Node sibling, List<RBTree.Node> path)
|
|
{
|
|
for (;;)
|
|
{
|
|
path.Add(sibling);
|
|
path.Add(current);
|
|
if (current.right == null)
|
|
{
|
|
break;
|
|
}
|
|
sibling = current.left;
|
|
current = current.right;
|
|
}
|
|
return current;
|
|
}
|
|
|
|
// Token: 0x0400003D RID: 61
|
|
private RBTree.Node root;
|
|
|
|
// Token: 0x0400003E RID: 62
|
|
private object hlp;
|
|
|
|
// Token: 0x0400003F RID: 63
|
|
private uint version;
|
|
|
|
// Token: 0x04000040 RID: 64
|
|
[ThreadStatic]
|
|
private static List<RBTree.Node> cached_path;
|
|
|
|
// Token: 0x02000011 RID: 17
|
|
public interface INodeHelper<T>
|
|
{
|
|
// Token: 0x06000072 RID: 114
|
|
int Compare(T key, RBTree.Node node);
|
|
|
|
// Token: 0x06000073 RID: 115
|
|
RBTree.Node CreateNode(T key);
|
|
}
|
|
|
|
// Token: 0x02000012 RID: 18
|
|
public abstract class Node
|
|
{
|
|
// Token: 0x06000074 RID: 116 RVA: 0x00003E6C File Offset: 0x0000206C
|
|
public Node()
|
|
{
|
|
this.size_black = 2U;
|
|
}
|
|
|
|
// Token: 0x17000017 RID: 23
|
|
// (get) Token: 0x06000075 RID: 117 RVA: 0x00003E7C File Offset: 0x0000207C
|
|
// (set) Token: 0x06000076 RID: 118 RVA: 0x00003E8C File Offset: 0x0000208C
|
|
public bool IsBlack
|
|
{
|
|
get
|
|
{
|
|
return (this.size_black & 1U) == 1U;
|
|
}
|
|
set
|
|
{
|
|
this.size_black = ((!value) ? (this.size_black & 4294967294U) : (this.size_black | 1U));
|
|
}
|
|
}
|
|
|
|
// Token: 0x17000018 RID: 24
|
|
// (get) Token: 0x06000077 RID: 119 RVA: 0x00003EBC File Offset: 0x000020BC
|
|
// (set) Token: 0x06000078 RID: 120 RVA: 0x00003EC8 File Offset: 0x000020C8
|
|
public uint Size
|
|
{
|
|
get
|
|
{
|
|
return this.size_black >> 1;
|
|
}
|
|
set
|
|
{
|
|
this.size_black = (value << 1) | (this.size_black & 1U);
|
|
}
|
|
}
|
|
|
|
// Token: 0x06000079 RID: 121 RVA: 0x00003EDC File Offset: 0x000020DC
|
|
public uint FixSize()
|
|
{
|
|
this.Size = 1U;
|
|
if (this.left != null)
|
|
{
|
|
this.Size += this.left.Size;
|
|
}
|
|
if (this.right != null)
|
|
{
|
|
this.Size += this.right.Size;
|
|
}
|
|
return this.Size;
|
|
}
|
|
|
|
// Token: 0x0600007A RID: 122
|
|
public abstract void SwapValue(RBTree.Node other);
|
|
|
|
// Token: 0x04000041 RID: 65
|
|
private const uint black_mask = 1U;
|
|
|
|
// Token: 0x04000042 RID: 66
|
|
private const int black_shift = 1;
|
|
|
|
// Token: 0x04000043 RID: 67
|
|
public RBTree.Node left;
|
|
|
|
// Token: 0x04000044 RID: 68
|
|
public RBTree.Node right;
|
|
|
|
// Token: 0x04000045 RID: 69
|
|
private uint size_black;
|
|
}
|
|
|
|
// Token: 0x02000013 RID: 19
|
|
public struct NodeEnumerator : IEnumerator, IDisposable, IEnumerator<RBTree.Node>
|
|
{
|
|
// Token: 0x0600007B RID: 123 RVA: 0x00003F3C File Offset: 0x0000213C
|
|
internal NodeEnumerator(RBTree tree)
|
|
{
|
|
this.tree = tree;
|
|
this.version = tree.version;
|
|
this.pennants = null;
|
|
}
|
|
|
|
// Token: 0x17000019 RID: 25
|
|
// (get) Token: 0x0600007C RID: 124 RVA: 0x00003F58 File Offset: 0x00002158
|
|
object IEnumerator.Current
|
|
{
|
|
get
|
|
{
|
|
this.check_current();
|
|
return this.Current;
|
|
}
|
|
}
|
|
|
|
// Token: 0x0600007D RID: 125 RVA: 0x00003F68 File Offset: 0x00002168
|
|
public void Reset()
|
|
{
|
|
this.check_version();
|
|
this.pennants = null;
|
|
}
|
|
|
|
// Token: 0x1700001A RID: 26
|
|
// (get) Token: 0x0600007E RID: 126 RVA: 0x00003F78 File Offset: 0x00002178
|
|
public RBTree.Node Current
|
|
{
|
|
get
|
|
{
|
|
return this.pennants.Peek();
|
|
}
|
|
}
|
|
|
|
// Token: 0x0600007F RID: 127 RVA: 0x00003F88 File Offset: 0x00002188
|
|
public bool MoveNext()
|
|
{
|
|
this.check_version();
|
|
RBTree.Node node;
|
|
if (this.pennants == null)
|
|
{
|
|
if (this.tree.root == null)
|
|
{
|
|
return false;
|
|
}
|
|
this.pennants = new Stack<RBTree.Node>();
|
|
node = this.tree.root;
|
|
}
|
|
else
|
|
{
|
|
if (this.pennants.Count == 0)
|
|
{
|
|
return false;
|
|
}
|
|
RBTree.Node node2 = this.pennants.Pop();
|
|
node = node2.right;
|
|
}
|
|
while (node != null)
|
|
{
|
|
this.pennants.Push(node);
|
|
node = node.left;
|
|
}
|
|
return this.pennants.Count != 0;
|
|
}
|
|
|
|
// Token: 0x06000080 RID: 128 RVA: 0x00004028 File Offset: 0x00002228
|
|
public void Dispose()
|
|
{
|
|
this.tree = null;
|
|
this.pennants = null;
|
|
}
|
|
|
|
// Token: 0x06000081 RID: 129 RVA: 0x00004038 File Offset: 0x00002238
|
|
private void check_version()
|
|
{
|
|
if (this.tree == null)
|
|
{
|
|
throw new ObjectDisposedException("enumerator");
|
|
}
|
|
if (this.version != this.tree.version)
|
|
{
|
|
throw new InvalidOperationException("tree modified");
|
|
}
|
|
}
|
|
|
|
// Token: 0x06000082 RID: 130 RVA: 0x00004074 File Offset: 0x00002274
|
|
internal void check_current()
|
|
{
|
|
this.check_version();
|
|
if (this.pennants == null)
|
|
{
|
|
throw new InvalidOperationException("state invalid before the first MoveNext()");
|
|
}
|
|
}
|
|
|
|
// Token: 0x04000046 RID: 70
|
|
private RBTree tree;
|
|
|
|
// Token: 0x04000047 RID: 71
|
|
private uint version;
|
|
|
|
// Token: 0x04000048 RID: 72
|
|
private Stack<RBTree.Node> pennants;
|
|
}
|
|
}
|
|
}
|