//---------------------------------------------- // 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 BetterList { #if UNITY_FLASH List mList = new List(); /// /// Direct access to the buffer. Note that you should not use its 'Length' parameter, but instead use BetterList.size. /// public T this[int i] { get { return mList[i]; } set { mList[i] = value; } } /// /// Compatibility with the non-flash syntax. /// public List buffer { get { return mList; } } /// /// 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 { get { return mList.Count; } } /// /// For 'foreach' functionality. /// public IEnumerator GetEnumerator () { return mList.GetEnumerator(); } /// /// Clear the array by resetting its size to zero. Note that the memory is not actually released. /// public void Clear () { mList.Clear(); } /// /// Clear the array and release the used memory. /// public void Release () { mList.Clear(); } /// /// Add the specified item to the end of the list. /// public void Add (T item) { mList.Add(item); } /// /// Insert an item at the specified index, pushing the entries back. /// public void Insert (int index, T item) { if (index > -1 && index < mList.Count) mList.Insert(index, item); else mList.Add(item); } /// /// Returns 'true' if the specified item is within the list. /// public bool Contains (T item) { return mList.Contains(item); } /// /// Return the index of the specified item. /// public int IndexOf (T item) { return mList.IndexOf(item); } /// /// 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) { return mList.Remove(item); } /// /// Remove an item at the specified index. /// public void RemoveAt (int index) { mList.RemoveAt(index); } /// /// Remove an item from the end. /// public T Pop () { if (buffer != null && size != 0) { T val = buffer[mList.Count - 1]; mList.RemoveAt(mList.Count - 1); return val; } return default(T); } /// /// Mimic List's ToArray() functionality, except that in this case the list is resized to match the current size. /// public T[] ToArray () { return mList.ToArray(); } /// /// List.Sort equivalent. /// public void Sort (System.Comparison comparer) { mList.Sort(comparer); } #else public BetterList() { } public BetterList(int capacity) { _buffer = new T[capacity]; } /// /// 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; /// /// 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 { _buffer[i] = value; } } /// /// 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; } /// /// 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]; _buffer[index] = item; ++size; } else Add(item); } /// /// Returns 'true' if the specified item is within the list. /// public bool Contains (T item) { if (_buffer == null) return false; for (int i = 0; i < size; ++i) if (_buffer[i].Equals(item)) return true; return false; } /// /// Return the index of the specified item. /// public int IndexOf (T item) { if (_buffer == null) return -1; for (int i = 0; i < size; ++i) if (_buffer[i].Equals(item)) 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) { EqualityComparer comp = EqualityComparer.Default; for (int i = 0; i < size; ++i) { if (comp.Equals(_buffer[i], item)) { --size; _buffer[i] = default(T); for (int b = i; b < size; ++b) _buffer[b] = _buffer[b + 1]; _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; _buffer[index] = default(T); for (int b = index; b < size; ++b) _buffer[b] = _buffer[b + 1]; _buffer[size] = default(T); } } /// /// Remove an item from the end. /// public T Pop () { if (_buffer != null && size != 0) { T val = _buffer[--size]; _buffer[size] = default(T); return val; } return 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; } //class Comparer : System.Collections.IComparer //{ // public System.Comparison func; // public int Compare (object x, object y) { return func((T)x, (T)y); } //} //Comparer mComp = new Comparer(); /// /// List.Sort equivalent. Doing Array.Sort causes GC allocations. /// //public void Sort (System.Comparison comparer) //{ // if (size > 0) // { // mComp.func = comparer; // System.Array.Sort(buffer, 0, size, mComp); // } //} /// /// 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; changed = true; } else if (!changed) { // Nothing has changed -- we can start here next time start = (i == 0) ? 0 : i - 1; } } } } public void AddRange(BetterList temp) { if (size + temp.size > _buffer.Length) { System.Array.Resize(ref _buffer, size + temp.size); } if (temp._buffer == null) return; System.Array.Copy(temp._buffer, 0, _buffer, size, temp.size); size += temp.size; } /// /// 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); #endif }