You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
331 lines
10 KiB
331 lines
10 KiB
//========= 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<TKey, TValue> : IEnumerable<KeyValuePair<TKey, TValue>> |
|
{ |
|
int Count { get; } |
|
ICollection<TKey> Keys { get; } |
|
ICollection<TValue> 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<TKey, TValue>[] array, int arrayIndex); |
|
int IndexOf(TKey item); |
|
} |
|
|
|
public class IndexedTable<TKey, TValue> : IDictionary<TKey, TValue>, IIndexedTableReadOnly<TKey, TValue> |
|
{ |
|
private class ReadOnlyWrapper : IIndexedTableReadOnly<TKey, TValue> |
|
{ |
|
private IndexedTable<TKey, TValue> m_container; |
|
|
|
public ReadOnlyWrapper(IndexedTable<TKey, TValue> container) { m_container = container; } |
|
|
|
public TValue this[TKey key] { get { return m_container[key]; } } |
|
|
|
public int Count { get { return m_container.Count; } } |
|
|
|
public ICollection<TKey> Keys { get { return m_container.Keys; } } |
|
|
|
public ICollection<TValue> Values { get { return m_container.Values; } } |
|
|
|
public bool ContainsKey(TKey key) { return m_container.ContainsKey(key); } |
|
|
|
public void CopyTo(KeyValuePair<TKey, TValue>[] array, int arrayIndex) { m_container.CopyTo(array, arrayIndex); } |
|
|
|
public IEnumerator<KeyValuePair<TKey, TValue>> 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<TKey, TValue>)m_container).GetEnumerator(); } |
|
} |
|
|
|
protected readonly Dictionary<TKey, int> m_Dictionary; |
|
protected readonly List<TKey> m_KeyList; |
|
protected readonly List<TValue> m_ValueList; |
|
protected IIndexedTableReadOnly<TKey, TValue> m_readOnly; |
|
|
|
public IndexedTable() |
|
{ |
|
m_Dictionary = new Dictionary<TKey, int>(); |
|
m_KeyList = new List<TKey>(); |
|
m_ValueList = new List<TValue>(); |
|
} |
|
|
|
public IndexedTable(int capacity) |
|
{ |
|
m_Dictionary = new Dictionary<TKey, int>(capacity); |
|
m_KeyList = new List<TKey>(capacity); |
|
m_ValueList = new List<TValue>(capacity); |
|
} |
|
|
|
public int Count { get { return m_Dictionary.Count; } } |
|
|
|
public bool IsReadOnly { get { return false; } } |
|
|
|
public IIndexedTableReadOnly<TKey, TValue> 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<TKey, TValue> GetKeyValuePairByIndex(int index) |
|
{ |
|
return new KeyValuePair<TKey, TValue>(m_KeyList[index], m_ValueList[index]); |
|
} |
|
|
|
public ICollection<TKey> Keys { get { return m_Dictionary.Keys; } } |
|
|
|
public ICollection<TValue> Values { get { return new List<TValue>(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<TKey, TValue> item) |
|
{ |
|
Add(item.Key, item.Value); |
|
} |
|
|
|
public bool Contains(KeyValuePair<TKey, TValue> item) |
|
{ |
|
int index; |
|
if (!m_Dictionary.TryGetValue(item.Key, out index)) { return false; } |
|
return EqualityComparer<KeyValuePair<TKey, TValue>>.Default.Equals(GetKeyValuePairByIndex(index), item); |
|
} |
|
|
|
public void CopyTo(KeyValuePair<TKey, TValue>[] 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<TKey, TValue> 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<TKey, TValue>(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<TKey, TValue> item) |
|
{ |
|
if (!Contains(item)) { return false; } |
|
return Remove(item.Key); |
|
} |
|
|
|
public void RemoveAll(Predicate<KeyValuePair<TKey, TValue>> 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<KeyValuePair<TKey, TValue>> |
|
{ |
|
private int iterator = -1; |
|
private IndexedTable<TKey, TValue> container; |
|
|
|
public Enumerator(IndexedTable<TKey, TValue> c) { container = c; } |
|
|
|
public KeyValuePair<TKey, TValue> 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<KeyValuePair<TKey, TValue>> GetEnumerator() |
|
{ |
|
return new Enumerator(this); |
|
} |
|
|
|
IEnumerator IEnumerable.GetEnumerator() |
|
{ |
|
return GetEnumerator(); |
|
} |
|
|
|
public void Clear() |
|
{ |
|
m_Dictionary.Clear(); |
|
m_KeyList.Clear(); |
|
m_ValueList.Clear(); |
|
} |
|
|
|
public ReadOnlyCollection<TKey> AsReadOnly() |
|
{ |
|
return m_KeyList.AsReadOnly(); |
|
} |
|
} |
|
} |