Files
2025-01-25 04:38:09 +08:00

333 lines
7.8 KiB
C#

//----------------------------------------------
// NGUI: Next-Gen UI kit
// Copyright © 2011-2015 Tasharen Entertainment
//----------------------------------------------
using UnityEngine;
using System.Collections.Generic;
using System.Diagnostics;
/// <summary>
/// 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.
/// </summary>
public class ObjBetterList<T> where T : Object
{
/// <summary>
/// 索引改变回调函数
/// </summary>
private IndexChangeFunc _indexChangeFunc;
/// <summary>
/// Direct access to the buffer. Note that you should not use its 'Length' parameter, but instead use BetterList.size.
/// </summary>
private T[] _buffer;
public T[] buffer
{
get
{
return _buffer;
}
}
/// <summary>
/// Direct access to the buffer's size. Note that it's only public for speed and efficiency. You shouldn't modify it.
/// </summary>
public int size = 0;
public ObjBetterList()
{
}
public ObjBetterList(int capacity)
{
_buffer = new T[capacity];
}
/// <summary>
/// For 'foreach' functionality.
/// </summary>
///
[DebuggerHidden]
[DebuggerStepThrough]
public IEnumerator<T> GetEnumerator ()
{
if (_buffer != null)
{
for (int i = 0; i < size; ++i)
{
yield return _buffer[i];
}
}
}
/// <summary>
/// Convenience function. I recommend using .buffer instead.
/// </summary>
[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);
}
}
}
/// <summary>
/// Helper function that expands the size of the array, maintaining the content.
/// </summary>
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;
}
/// <summary>
/// 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.
/// </summary>
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;
}
/// <summary>
/// Clear the array by resetting its size to zero. Note that the memory is not actually released.
/// </summary>
public void Clear () { size = 0; }
/// <summary>
/// Clear the array and release the used memory.
/// </summary>
public void Release () { size = 0; _buffer = null; }
/// <summary>
/// Add the specified item to the end of the list.
/// </summary>
public void Add (T item)
{
if (_buffer == null || size == _buffer.Length) AllocateMore();
_buffer[size] = item;
//添加新的
DoIndexChanged(item, size);
++size;
}
/// <summary>
/// Insert an item at the specified index, pushing the entries back.
/// </summary>
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);
}
/// <summary>
/// Returns 'true' if the specified item is within the list.
/// </summary>
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;
}
/// <summary>
/// Return the index of the specified item.
/// </summary>
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;
}
/// <summary>
/// Remove the specified item from the list. Note that RemoveAt() is faster and is advisable if you already know the index.
/// </summary>
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;
}
/// <summary>
/// Remove an item at the specified index.
/// </summary>
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);
}
}
/// <summary>
/// Mimic List's ToArray() functionality, except that in this case the list is resized to match the current size.
/// </summary>
public T[] ToArray () { Trim(); return _buffer; }
/// <summary>
/// List.Sort equivalent. Manual sorting causes no GC allocations.
/// </summary>
[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;
}
}
}
}
/// <summary>
/// 索引改变回调函数
/// </summary>
public void SetIndexChangeFunc(IndexChangeFunc func)
{
_indexChangeFunc = func;
}
private void DoIndexChanged(T item, int index)
{
if(_indexChangeFunc != null)
{
_indexChangeFunc(item, index);
}
}
/// <summary>
/// Comparison function should return -1 if left is less than right, 1 if left is greater than right, and 0 if they match.
/// </summary>
public delegate int CompareFunc (T left, T right);
/// <summary>
/// 索引改变回调
/// </summary>
/// <param name="item"></param>
/// <param name="index"></param>
public delegate void IndexChangeFunc (T item, int index);
}