| File: System\Xml\XmlBinaryWriterSession.cs | Web Access |
| Project: src\runtime\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; using System.Collections.Generic; using System.Collections.ObjectModel; using System.Diagnostics; using System.Diagnostics.CodeAnalysis; using System.Runtime.Serialization; using System.Xml; namespace System.Xml { public class XmlBinaryWriterSession { private readonly PriorityDictionary<string, int> _strings; private readonly PriorityDictionary<IXmlDictionary, IntArray> _maps; private int _nextKey; public XmlBinaryWriterSession() { _nextKey = 0; _maps = new PriorityDictionary<IXmlDictionary, IntArray>(); _strings = new PriorityDictionary<string, int>(); } public virtual bool TryAdd(XmlDictionaryString value, out int key) { ArgumentNullException.ThrowIfNull(value); IntArray? keys; if (_maps.TryGetValue(value.Dictionary, out keys)) { key = (keys[value.Key] - 1); if (key != -1) { // If the key is already set, then something is wrong throw new InvalidOperationException(SR.XmlKeyAlreadyExists); } key = Add(value.Value); keys[value.Key] = (key + 1); return true; } key = Add(value.Value); keys = AddKeys(value.Dictionary, value.Key + 1); keys[value.Key] = (key + 1); return true; } private int Add(string s) { int key = _nextKey++; _strings.Add(s, key); return key; } private IntArray AddKeys(IXmlDictionary dictionary, int minCount) { IntArray keys = new IntArray(Math.Max(minCount, 16)); _maps.Add(dictionary, keys); return keys; } public void Reset() { _nextKey = 0; _maps.Clear(); _strings.Clear(); } internal bool TryLookup(XmlDictionaryString s, out int key) { IntArray? keys; if (_maps.TryGetValue(s.Dictionary, out keys)) { key = (keys[s.Key] - 1); if (key != -1) { return true; } } if (_strings.TryGetValue(s.Value, out key)) { keys ??= AddKeys(s.Dictionary, s.Key + 1); keys[s.Key] = (key + 1); return true; } key = -1; return false; } private sealed class PriorityDictionary<K, V> where K : class { private Dictionary<K, V>? _dictionary; private readonly Entry[] _list; private int _listCount; private int _now; public PriorityDictionary() { _list = new Entry[16]; } public void Clear() { _now = 0; _listCount = 0; Array.Clear(_list); _dictionary?.Clear(); } public bool TryGetValue(K key, [MaybeNullWhen(false)] out V value) { for (int i = 0; i < _listCount; i++) { if (_list[i].Key == key) { value = _list[i].Value; _list[i].Time = Now; return true; } } for (int i = 0; i < _listCount; i++) { if (_list[i].Key.Equals(key)) { value = _list[i].Value; _list[i].Time = Now; return true; } } if (_dictionary == null) { value = default(V); return false; } if (!_dictionary.TryGetValue(key, out value)) { return false; } int minIndex = 0; int minTime = _list[0].Time; for (int i = 1; i < _listCount; i++) { if (_list[i].Time < minTime) { minIndex = i; minTime = _list[i].Time; } } _list[minIndex].Key = key; _list[minIndex].Value = value; _list[minIndex].Time = Now; return true; } public void Add(K key, V value) { if (_listCount < _list.Length) { _list[_listCount].Key = key; _list[_listCount].Value = value; _listCount++; } else { if (_dictionary == null) { _dictionary = new Dictionary<K, V>(); for (int i = 0; i < _listCount; i++) { _dictionary.Add(_list[i].Key, _list[i].Value); } } _dictionary.Add(key, value); } } private int Now { get { if (++_now == int.MaxValue) { DecreaseAll(); } return _now; } } private void DecreaseAll() { for (int i = 0; i < _listCount; i++) { _list[i].Time /= 2; } _now /= 2; } private struct Entry { public K Key; public V Value; public int Time; } } private sealed class IntArray { private int[] _array; public IntArray(int size) { _array = new int[size]; } public int this[int index] { get { if (index >= _array.Length) return 0; return _array[index]; } set { if (index >= _array.Length) { int[] newArray = new int[Math.Max(index + 1, _array.Length * 2)]; Array.Copy(_array, newArray, _array.Length); _array = newArray; } _array[index] = value; } } } } }