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
3 years ago
|
//========= 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();
|
||
|
}
|
||
|
}
|
||
|
}
|