File: System\Runtime\Serialization\ObjectReferenceStack.cs
Web Access
Project: src\src\libraries\System.Private.DataContractSerialization\src\System.Private.DataContractSerialization.csproj (System.Private.DataContractSerialization)
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
 
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Xml;
 
namespace System.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
            {
                _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)
                {
                    Debug.Fail("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)
                {
                    Debug.Fail("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;
        }
    }
}