//---------------------------------------------- // NGUI: Next-Gen UI kit // Copyright © 2011-2015 Tasharen Entertainment //---------------------------------------------- using UnityEngine; using System.Collections.Generic; using System.Diagnostics; /// /// This improved version of the System.Collections.Generic.List that doesn't release the buffer on Clear(), /// resulting in better performance and less garbage collection. /// PRO: BetterList performs faster than List when you Add and Remove items (although slower if you remove from the beginning). /// CON: BetterList performs worse when sorting the list. If your operations involve sorting, use the standard List instead. /// public class ObjBetterList where T : Object { /// /// 索引改变回调函数 /// private IndexChangeFunc _indexChangeFunc; /// /// Direct access to the buffer. Note that you should not use its 'Length' parameter, but instead use BetterList.size. /// private T[] _buffer; public T[] buffer { get { return _buffer; } } /// /// Direct access to the buffer's size. Note that it's only public for speed and efficiency. You shouldn't modify it. /// public int size = 0; public ObjBetterList() { } public ObjBetterList(int capacity) { _buffer = new T[capacity]; } /// /// For 'foreach' functionality. /// /// [DebuggerHidden] [DebuggerStepThrough] public IEnumerator GetEnumerator () { if (_buffer != null) { for (int i = 0; i < size; ++i) { yield return _buffer[i]; } } } /// /// Convenience function. I recommend using .buffer instead. /// [DebuggerHidden] public T this[int i] { get { return _buffer[i]; } set { var oldValue = _buffer[i]; if(oldValue != value) { _buffer[i] = value; //移除老的 DoIndexChanged(oldValue, -1); //添加新的 DoIndexChanged(value, i); } } } /// /// Helper function that expands the size of the array, maintaining the content. /// void AllocateMore () { T[] newList = (_buffer != null) ? new T[Mathf.Max(_buffer.Length << 1, 32)] : new T[32]; if (_buffer != null && size > 0) _buffer.CopyTo(newList, 0); _buffer = newList; } /// /// Trim the unnecessary memory, resizing the buffer to be of 'Length' size. /// Call this function only if you are sure that the buffer won't need to resize anytime soon. /// void Trim () { if (size > 0) { if (size < _buffer.Length) { T[] newList = new T[size]; for (int i = 0; i < size; ++i) newList[i] = _buffer[i]; _buffer = newList; } } else _buffer = null; } /// /// Clear the array by resetting its size to zero. Note that the memory is not actually released. /// public void Clear () { size = 0; } /// /// Clear the array and release the used memory. /// public void Release () { size = 0; _buffer = null; } /// /// Add the specified item to the end of the list. /// public void Add (T item) { if (_buffer == null || size == _buffer.Length) AllocateMore(); _buffer[size] = item; //添加新的 DoIndexChanged(item, size); ++size; } /// /// Insert an item at the specified index, pushing the entries back. /// public void Insert (int index, T item) { if (_buffer == null || size == _buffer.Length) AllocateMore(); if (index > -1 && index < size) { for (int i = size; i > index; --i) { _buffer[i] = _buffer[i - 1]; DoIndexChanged(_buffer[i], i); } _buffer[index] = item; DoIndexChanged(item, index); ++size; } else Add(item); } /// /// Returns 'true' if the specified item is within the list. /// public bool Contains (T item) { if (_buffer == null) return false; var hashCode = item.GetHashCode(); for (int i = 0; i < size; ++i) { if (_buffer[i].GetHashCode() == hashCode) { return true; } } return false; } /// /// Return the index of the specified item. /// public int IndexOf (T item) { if (_buffer == null) return -1; var hashCode = item.GetHashCode(); for (int i = 0; i < size; ++i) { if (_buffer[i].GetHashCode() == hashCode) { return i; } } return -1; } /// /// Remove the specified item from the list. Note that RemoveAt() is faster and is advisable if you already know the index. /// public bool Remove (T item) { if (_buffer != null && item != null) { var hashCode = item.GetHashCode(); for (int i = 0; i < size; ++i) { if (_buffer[i].GetHashCode() == hashCode) { --size; DoIndexChanged(_buffer[i], -1); _buffer[i] = default(T); for (int b = i; b < size; ++b) { _buffer[b] = _buffer[b + 1]; DoIndexChanged(_buffer[b], b); } _buffer[size] = default(T); return true; } } } return false; } /// /// Remove an item at the specified index. /// public void RemoveAt (int index) { if (_buffer != null && index > -1 && index < size) { --size; DoIndexChanged(_buffer[index], -1); _buffer[index] = default(T); for (int b = index; b < size; ++b) { _buffer[b] = _buffer[b + 1]; DoIndexChanged(_buffer[b], b); } _buffer[size] = default(T); } } /// /// Mimic List's ToArray() functionality, except that in this case the list is resized to match the current size. /// public T[] ToArray () { Trim(); return _buffer; } /// /// List.Sort equivalent. Manual sorting causes no GC allocations. /// [DebuggerHidden] [DebuggerStepThrough] public void Sort (CompareFunc comparer) { int start = 0; int max = size - 1; bool changed = true; while (changed) { changed = false; for (int i = start; i < max; ++i) { // Compare the two values if (comparer(_buffer[i], _buffer[i + 1]) > 0) { // Swap the values T temp = _buffer[i]; _buffer[i] = _buffer[i + 1]; _buffer[i + 1] = temp; DoIndexChanged(_buffer[i], i); DoIndexChanged(_buffer[i + 1], i + 1); changed = true; } else if (!changed) { // Nothing has changed -- we can start here next time start = (i == 0) ? 0 : i - 1; } } } } /// /// 索引改变回调函数 /// public void SetIndexChangeFunc(IndexChangeFunc func) { _indexChangeFunc = func; } private void DoIndexChanged(T item, int index) { if(_indexChangeFunc != null) { _indexChangeFunc(item, index); } } /// /// Comparison function should return -1 if left is less than right, 1 if left is greater than right, and 0 if they match. /// public delegate int CompareFunc (T left, T right); /// /// 索引改变回调 /// /// /// public delegate void IndexChangeFunc (T item, int index); }