Files
NetDataContractSerializer/Compat.Private.Serialization/Compat/Runtime/Serialization/ObjectReferenceStack.cs
2019-08-29 23:24:07 +03:00

115 lines
3.2 KiB
C#

using System;
using System.Collections.Generic;
namespace Compat.Runtime.Serialization
{
internal struct ObjectReferenceStack
{
private const int MaximumArraySize = 16;
private const int InitialArraySize = 4;
private int count;
private object[] objectArray;
private bool[] isReferenceArray;
private Dictionary<object, object> objectDictionary;
internal void Push(object obj)
{
if (objectArray == null)
{
objectArray = new object[InitialArraySize];
objectArray[count++] = obj;
}
else if (count < MaximumArraySize)
{
if (count == objectArray.Length)
{
Array.Resize<object>(ref objectArray, objectArray.Length * 2);
}
objectArray[count++] = obj;
}
else
{
if (objectDictionary == null)
{
objectDictionary = new Dictionary<object, object>();
}
objectDictionary.Add(obj, null);
count++;
}
}
internal void EnsureSetAsIsReference(object obj)
{
if (count == 0)
{
return;
}
if (count > MaximumArraySize)
{
if (objectDictionary == null)
{
Fx.Assert("Object reference stack in invalid state");
}
objectDictionary.Remove(obj);
}
else
{
if ((objectArray != null) && objectArray[count - 1] == obj)
{
if (isReferenceArray == null)
{
isReferenceArray = new bool[objectArray.Length];
}
else if (count >= isReferenceArray.Length)
{
Array.Resize<bool>(ref isReferenceArray, objectArray.Length);
}
isReferenceArray[count - 1] = true;
}
}
}
internal void Pop(object obj)
{
if (count > MaximumArraySize)
{
if (objectDictionary == null)
{
Fx.Assert("Object reference stack in invalid state");
}
objectDictionary.Remove(obj);
}
count--;
}
internal bool Contains(object obj)
{
int currentCount = count;
if (currentCount > MaximumArraySize)
{
if (objectDictionary != null && objectDictionary.ContainsKey(obj))
{
return true;
}
currentCount = MaximumArraySize;
}
for (int i = (currentCount - 1); i >= 0; i--)
{
if (Object.ReferenceEquals(obj, objectArray[i]) && isReferenceArray != null && !isReferenceArray[i])
{
return true;
}
}
return false;
}
internal int Count => count;
}
}