//========= Copyright 2016-2018, HTC Corporation. All rights reserved. =========== using System; using System.Collections; using System.Collections.Generic; using System.Collections.ObjectModel; namespace HTC.UnityPlugin.Utility { public interface IIndexedTableReadOnly : IEnumerable> { int Count { get; } ICollection Keys { get; } ICollection Values { get; } TValue this[TKey key] { get; } TKey GetKeyByIndex(int index); TValue GetValueByIndex(int index); bool ContainsKey(TKey key); bool TryGetValue(TKey key, out TValue value); void CopyTo(KeyValuePair[] array, int arrayIndex); int IndexOf(TKey item); } public class IndexedTable : IDictionary, IIndexedTableReadOnly { private class ReadOnlyWrapper : IIndexedTableReadOnly { private IndexedTable m_container; public ReadOnlyWrapper(IndexedTable container) { m_container = container; } public TValue this[TKey key] { get { return m_container[key]; } } public int Count { get { return m_container.Count; } } public ICollection Keys { get { return m_container.Keys; } } public ICollection Values { get { return m_container.Values; } } public bool ContainsKey(TKey key) { return m_container.ContainsKey(key); } public void CopyTo(KeyValuePair[] array, int arrayIndex) { m_container.CopyTo(array, arrayIndex); } public IEnumerator> GetEnumerator() { return m_container.GetEnumerator(); } public int IndexOf(TKey item) { return m_container.IndexOf(item); } public TKey GetKeyByIndex(int index) { return m_container.GetKeyByIndex(index); } public TValue GetValueByIndex(int index) { return m_container.GetValueByIndex(index); } public bool TryGetValue(TKey key, out TValue value) { return m_container.TryGetValue(key, out value); } IEnumerator IEnumerable.GetEnumerator() { return ((IIndexedTableReadOnly)m_container).GetEnumerator(); } } protected readonly Dictionary m_Dictionary; protected readonly List m_KeyList; protected readonly List m_ValueList; protected IIndexedTableReadOnly m_readOnly; public IndexedTable() { m_Dictionary = new Dictionary(); m_KeyList = new List(); m_ValueList = new List(); } public IndexedTable(int capacity) { m_Dictionary = new Dictionary(capacity); m_KeyList = new List(capacity); m_ValueList = new List(capacity); } public int Count { get { return m_Dictionary.Count; } } public bool IsReadOnly { get { return false; } } public IIndexedTableReadOnly ReadOnly { get { return m_readOnly ?? (m_readOnly = new ReadOnlyWrapper(this)); } } public TKey GetKeyByIndex(int index) { if (index < 0 || index >= m_KeyList.Count) { UnityEngine.Debug.LogWarning("index=" + index + " m_Dictionary.Count=" + m_Dictionary.Count + " m_KeyList.Count=" + m_KeyList.Count + " m_ValueList.Count=" + m_ValueList.Count); string msg = "{ "; for (int i = 0; i < m_KeyList.Count; ++i) { msg += m_KeyList[i].ToString() + ","; } UnityEngine.Debug.LogWarning("KeyList=" + msg + " }"); } return m_KeyList[index]; } public TValue GetValueByIndex(int index) { return m_ValueList[index]; } public void SetValueByIndex(int index, TValue value) { m_ValueList[index] = value; } public KeyValuePair GetKeyValuePairByIndex(int index) { return new KeyValuePair(m_KeyList[index], m_ValueList[index]); } public ICollection Keys { get { return m_Dictionary.Keys; } } public ICollection Values { get { return new List(m_ValueList); } } public TValue this[TKey key] { get { return m_ValueList[m_Dictionary[key]]; } set { int index; if (m_Dictionary.TryGetValue(key, out index)) { m_ValueList[index] = value; } else { Add(key, value); } } } public void Add(TKey key, TValue value = default(TValue)) { m_Dictionary.Add(key, m_Dictionary.Count); m_KeyList.Add(key); m_ValueList.Add(value); } public bool AddUniqueKey(TKey key, TValue value = default(TValue)) { if (m_Dictionary.ContainsKey(key)) { return false; } Add(key, value); return true; } public bool ContainsKey(TKey key) { return m_Dictionary.ContainsKey(key); } public bool Remove(TKey key) { int index; if (!m_Dictionary.TryGetValue(key, out index)) { return false; } RemoveAt(index); return true; } public virtual void RemoveAt(int index) { m_Dictionary.Remove(m_KeyList[index]); if (index == m_KeyList.Count - 1) { m_KeyList.RemoveAt(index); m_ValueList.RemoveAt(index); } else { var replaceItemIndex = m_KeyList.Count - 1; var replaceItemKey = m_KeyList[replaceItemIndex]; var replaceItemValue = m_ValueList[replaceItemIndex]; m_KeyList[index] = replaceItemKey; m_ValueList[index] = replaceItemValue; m_Dictionary[replaceItemKey] = index; m_KeyList.RemoveAt(replaceItemIndex); m_ValueList.RemoveAt(replaceItemIndex); } } public bool TryGetValue(TKey key, out TValue value) { int index; if (m_Dictionary.TryGetValue(key, out index)) { value = m_ValueList[index]; return true; } else { value = default(TValue); return false; } } public void Add(KeyValuePair item) { Add(item.Key, item.Value); } public bool Contains(KeyValuePair item) { int index; if (!m_Dictionary.TryGetValue(item.Key, out index)) { return false; } return EqualityComparer>.Default.Equals(GetKeyValuePairByIndex(index), item); } public void CopyTo(KeyValuePair[] array, int arrayIndex) { if (array == null) { throw new ArgumentNullException("array is null."); } if (arrayIndex < 0) { throw new ArgumentOutOfRangeException("arrayIndex is less than 0."); } if (array.Length - arrayIndex < m_Dictionary.Count) { throw new ArgumentException("The number of elements in the source IndexedTable is greater than the available space from arrayIndex to the end of the destination array."); } for (int i = 0, imax = m_Dictionary.Count; i < imax; ++i) { array[i + arrayIndex] = new KeyValuePair(m_KeyList[i], m_ValueList[i]); } } public int IndexOf(TKey item) { int index; return m_Dictionary.TryGetValue(item, out index) ? index : -1; } public bool Remove(KeyValuePair item) { if (!Contains(item)) { return false; } return Remove(item.Key); } public void RemoveAll(Predicate> match) { var removed = 0; for (int i = 0, imax = m_Dictionary.Count; i < imax; ++i) { if (match(GetKeyValuePairByIndex(i))) { m_Dictionary.Remove(m_KeyList[i]); ++removed; } else { if (removed > 0) { m_Dictionary[m_KeyList[i]] = i - removed; m_KeyList[i - removed] = m_KeyList[i]; m_ValueList[i - removed] = m_ValueList[i]; } } } if (removed == 0) { return; } else if (removed == Count) { Clear(); } else { for (; removed > 0; --removed) { m_KeyList.RemoveAt(m_KeyList.Count - 1); m_ValueList.RemoveAt(m_ValueList.Count - 1); } } } private class Enumerator : IEnumerator> { private int iterator = -1; private IndexedTable container; public Enumerator(IndexedTable c) { container = c; } public KeyValuePair Current { get { return container.GetKeyValuePairByIndex(iterator); } } object IEnumerator.Current { get { return Current; } } public void Dispose() { container = null; } public bool MoveNext() { ++iterator; return iterator < container.Count; } public void Reset() { iterator = 0; } } public IEnumerator> GetEnumerator() { return new Enumerator(this); } IEnumerator IEnumerable.GetEnumerator() { return GetEnumerator(); } public void Clear() { m_Dictionary.Clear(); m_KeyList.Clear(); m_ValueList.Clear(); } public ReadOnlyCollection AsReadOnly() { return m_KeyList.AsReadOnly(); } } }