| File: System\Text\RegularExpressions\Symbolic\SparseIntMap.cs | Web Access |
| Project: src\runtime\src\libraries\System.Text.RegularExpressions\src\System.Text.RegularExpressions.csproj (System.Text.RegularExpressions) |
// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. using System.Collections.Generic; using System.Diagnostics; namespace System.Text.RegularExpressions.Symbolic { /// <summary>An insertion-ordered map that supports small int keys.</summary> /// <remarks>Uses a sparse array of the same size as the space of keys for efficient lookups.</remarks> internal sealed class SparseIntMap<T> where T : struct { private const int InitialCapacity = 16; private readonly List<KeyValuePair<int, T>> _dense = new(); private int[] _sparse = new int[InitialCapacity]; /// <summary>Remove all entries. Does not decrease capacity.</summary> public void Clear() => _dense.Clear(); /// <summary>Number of entries in the map.</summary> public int Count => _dense.Count; /// <summary>Get the internal list of entries. Do not modify.</summary> public List<KeyValuePair<int, T>> Values => _dense; /// <summary>Find or add an entry matching the key.</summary> /// <param name="key">the key to find or add</param> /// <param name="index">will be set to the index of the matching entry</param> /// <returns>whether a new entry was added</returns> public bool Add(int key, out int index) { int[] sparse = _sparse; if ((uint)key < (uint)sparse.Length) { List<KeyValuePair<int, T>> dense = _dense; int idx = sparse[key]; if (idx < dense.Count) { int entryKey = dense[idx].Key; Debug.Assert(entryKey < sparse.Length); if (key == entryKey) { index = idx; return false; } } sparse[key] = index = _dense.Count; dense.Add(new KeyValuePair<int, T>(key, default)); return true; } return GrowAndAdd(key, out index); } /// <summary>Find or add an entry matching a key and then set the value of the entry.</summary> public bool Add(int key, T value) { bool added = Add(key, out int index); Update(index, key, value); return added; } /// <summary>Set the value of the entry at the index.</summary> public void Update(int index, int key, T value) { Debug.Assert(0 <= index && index < _dense.Count); Debug.Assert(_dense[index].Key == key); _dense[index] = new KeyValuePair<int, T>(key, value); } private bool GrowAndAdd(int key, out int index) { int newLength = key + 1; Debug.Assert(newLength > _sparse.Length); // At least double the size to amortize memory allocations newLength = Math.Max(2 * _sparse.Length, newLength); Array.Resize(ref _sparse, newLength); _sparse[key] = index = _dense.Count; _dense.Add(new KeyValuePair<int, T>(key, default)); return true; } } }