initial commit
This commit is contained in:
@@ -0,0 +1,191 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Runtime.CompilerServices;
|
||||
using ProtoBuf.Meta;
|
||||
|
||||
namespace ProtoBuf;
|
||||
|
||||
internal sealed class NetObjectCache
|
||||
{
|
||||
private sealed class ReferenceComparer : IEqualityComparer<object>
|
||||
{
|
||||
public static readonly ReferenceComparer Default = new ReferenceComparer();
|
||||
|
||||
private ReferenceComparer()
|
||||
{
|
||||
}
|
||||
|
||||
bool IEqualityComparer<object>.Equals(object x, object y)
|
||||
{
|
||||
return x == y;
|
||||
}
|
||||
|
||||
int IEqualityComparer<object>.GetHashCode(object obj)
|
||||
{
|
||||
return RuntimeHelpers.GetHashCode(obj);
|
||||
}
|
||||
}
|
||||
|
||||
internal const int Root = 0;
|
||||
|
||||
private MutableList underlyingList;
|
||||
|
||||
private object rootObject;
|
||||
|
||||
private int trapStartIndex;
|
||||
|
||||
private Dictionary<string, int> stringKeys;
|
||||
|
||||
private Dictionary<object, int> objectKeys;
|
||||
|
||||
private MutableList List => underlyingList ?? (underlyingList = new MutableList());
|
||||
|
||||
internal object GetKeyedObject(int key)
|
||||
{
|
||||
if (key-- == 0)
|
||||
{
|
||||
if (rootObject == null)
|
||||
{
|
||||
throw new ProtoException("No root object assigned");
|
||||
}
|
||||
return rootObject;
|
||||
}
|
||||
BasicList list = List;
|
||||
if (key < 0 || key >= list.Count)
|
||||
{
|
||||
throw new ProtoException("Internal error; a missing key occurred");
|
||||
}
|
||||
object obj = list[key];
|
||||
if (obj == null)
|
||||
{
|
||||
throw new ProtoException("A deferred key does not have a value yet");
|
||||
}
|
||||
return obj;
|
||||
}
|
||||
|
||||
internal void SetKeyedObject(int key, object value)
|
||||
{
|
||||
if (key-- == 0)
|
||||
{
|
||||
if (value == null)
|
||||
{
|
||||
throw new ArgumentNullException("value");
|
||||
}
|
||||
if (rootObject != null && rootObject != value)
|
||||
{
|
||||
throw new ProtoException("The root object cannot be reassigned");
|
||||
}
|
||||
rootObject = value;
|
||||
return;
|
||||
}
|
||||
MutableList list = List;
|
||||
if (key < list.Count)
|
||||
{
|
||||
object obj = list[key];
|
||||
if (obj == null)
|
||||
{
|
||||
list[key] = value;
|
||||
}
|
||||
else if (obj != value)
|
||||
{
|
||||
throw new ProtoException("Reference-tracked objects cannot change reference");
|
||||
}
|
||||
}
|
||||
else if (key != list.Add(value))
|
||||
{
|
||||
throw new ProtoException("Internal error; a key mismatch occurred");
|
||||
}
|
||||
}
|
||||
|
||||
internal int AddObjectKey(object value, out bool existing)
|
||||
{
|
||||
if (value == null)
|
||||
{
|
||||
throw new ArgumentNullException("value");
|
||||
}
|
||||
if (value == rootObject)
|
||||
{
|
||||
existing = true;
|
||||
return 0;
|
||||
}
|
||||
string text = value as string;
|
||||
BasicList list = List;
|
||||
int value2;
|
||||
if (text == null)
|
||||
{
|
||||
if (objectKeys == null)
|
||||
{
|
||||
objectKeys = new Dictionary<object, int>(ReferenceComparer.Default);
|
||||
value2 = -1;
|
||||
}
|
||||
else if (!objectKeys.TryGetValue(value, out value2))
|
||||
{
|
||||
value2 = -1;
|
||||
}
|
||||
}
|
||||
else if (stringKeys == null)
|
||||
{
|
||||
stringKeys = new Dictionary<string, int>();
|
||||
value2 = -1;
|
||||
}
|
||||
else if (!stringKeys.TryGetValue(text, out value2))
|
||||
{
|
||||
value2 = -1;
|
||||
}
|
||||
if (!(existing = value2 >= 0))
|
||||
{
|
||||
value2 = list.Add(value);
|
||||
if (text == null)
|
||||
{
|
||||
objectKeys.Add(value, value2);
|
||||
}
|
||||
else
|
||||
{
|
||||
stringKeys.Add(text, value2);
|
||||
}
|
||||
}
|
||||
return value2 + 1;
|
||||
}
|
||||
|
||||
internal void RegisterTrappedObject(object value)
|
||||
{
|
||||
if (rootObject == null)
|
||||
{
|
||||
rootObject = value;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (underlyingList == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
for (int i = trapStartIndex; i < underlyingList.Count; i++)
|
||||
{
|
||||
trapStartIndex = i + 1;
|
||||
if (underlyingList[i] == null)
|
||||
{
|
||||
underlyingList[i] = value;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
internal void Clear()
|
||||
{
|
||||
trapStartIndex = 0;
|
||||
rootObject = null;
|
||||
if (underlyingList != null)
|
||||
{
|
||||
underlyingList.Clear();
|
||||
}
|
||||
if (stringKeys != null)
|
||||
{
|
||||
stringKeys.Clear();
|
||||
}
|
||||
if (objectKeys != null)
|
||||
{
|
||||
objectKeys.Clear();
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user