349 lines
		
	
	
		
			8.6 KiB
		
	
	
	
		
			C#
		
	
	
	
			
		
		
	
	
			349 lines
		
	
	
		
			8.6 KiB
		
	
	
	
		
			C#
		
	
	
	
| namespace SRF
 | |
| {
 | |
|     using System;
 | |
|     using System.Collections;
 | |
|     using System.Collections.Generic;
 | |
|     using System.Collections.ObjectModel;
 | |
|     using UnityEngine;
 | |
| 
 | |
|     /// <summary>
 | |
|     /// IList implementation which does not release the buffer when clearing/removing elements. Based on the NGUI BetterList
 | |
|     /// </summary>
 | |
|     [Serializable]
 | |
|     public class SRList<T> : IList<T>, ISerializationCallbackReceiver
 | |
|     {
 | |
|         [SerializeField] private T[] _buffer;
 | |
|         [SerializeField] private int _count;
 | |
|         private EqualityComparer<T> _equalityComparer;
 | |
|         private ReadOnlyCollection<T> _readOnlyWrapper;
 | |
|         public SRList() {}
 | |
| 
 | |
|         public SRList(int capacity)
 | |
|         {
 | |
|             Buffer = new T[capacity];
 | |
|         }
 | |
| 
 | |
|         /// <summary>
 | |
|         /// Create a new list with the range of values. Contains a foreach loop, which will allocate garbage when used with most
 | |
|         /// generic collection types.
 | |
|         /// </summary>
 | |
|         public SRList(IEnumerable<T> source)
 | |
|         {
 | |
|             AddRange(source);
 | |
|         }
 | |
| 
 | |
|         public T[] Buffer
 | |
|         {
 | |
|             get { return _buffer; }
 | |
|             private set { _buffer = value; }
 | |
|         }
 | |
| 
 | |
|         private EqualityComparer<T> EqualityComparer
 | |
|         {
 | |
|             get
 | |
|             {
 | |
|                 if (_equalityComparer == null)
 | |
|                 {
 | |
|                     _equalityComparer = EqualityComparer<T>.Default;
 | |
|                 }
 | |
| 
 | |
|                 return _equalityComparer;
 | |
|             }
 | |
|         }
 | |
| 
 | |
|         public int Count
 | |
|         {
 | |
|             get { return _count; }
 | |
|             private set { _count = value; }
 | |
|         }
 | |
| 
 | |
|         public IEnumerator<T> GetEnumerator()
 | |
|         {
 | |
|             if (Buffer != null)
 | |
|             {
 | |
|                 for (var i = 0; i < Count; ++i)
 | |
|                 {
 | |
|                     yield return Buffer[i];
 | |
|                 }
 | |
|             }
 | |
|         }
 | |
| 
 | |
|         IEnumerator IEnumerable.GetEnumerator()
 | |
|         {
 | |
|             return GetEnumerator();
 | |
|         }
 | |
| 
 | |
|         public void Add(T item)
 | |
|         {
 | |
|             if (Buffer == null || Count == Buffer.Length)
 | |
|             {
 | |
|                 Expand();
 | |
|             }
 | |
| 
 | |
|             Buffer[Count++] = item;
 | |
|         }
 | |
| 
 | |
|         public void Clear()
 | |
|         {
 | |
|             Count = 0;
 | |
|         }
 | |
| 
 | |
|         public bool Contains(T item)
 | |
|         {
 | |
|             if (Buffer == null)
 | |
|             {
 | |
|                 return false;
 | |
|             }
 | |
| 
 | |
|             for (var i = 0; i < Count; ++i)
 | |
|             {
 | |
|                 if (EqualityComparer.Equals(Buffer[i], item))
 | |
|                 {
 | |
|                     return true;
 | |
|                 }
 | |
|             }
 | |
| 
 | |
|             return false;
 | |
|         }
 | |
| 
 | |
|         public void CopyTo(T[] array, int arrayIndex)
 | |
|         {
 | |
|             Trim();
 | |
|             Buffer.CopyTo(array, arrayIndex);
 | |
|         }
 | |
| 
 | |
|         public bool Remove(T item)
 | |
|         {
 | |
|             if (Buffer == null)
 | |
|             {
 | |
|                 return false;
 | |
|             }
 | |
| 
 | |
|             var index = IndexOf(item);
 | |
| 
 | |
|             if (index < 0)
 | |
|             {
 | |
|                 return false;
 | |
|             }
 | |
| 
 | |
|             RemoveAt(index);
 | |
| 
 | |
|             return true;
 | |
|         }
 | |
| 
 | |
|         public bool IsReadOnly
 | |
|         {
 | |
|             get { return false; }
 | |
|         }
 | |
| 
 | |
|         public int IndexOf(T item)
 | |
|         {
 | |
|             if (Buffer == null)
 | |
|             {
 | |
|                 return -1;
 | |
|             }
 | |
| 
 | |
|             for (var i = 0; i < Count; ++i)
 | |
|             {
 | |
|                 if (EqualityComparer.Equals(Buffer[i], item))
 | |
|                 {
 | |
|                     return i;
 | |
|                 }
 | |
|             }
 | |
| 
 | |
|             return -1;
 | |
|         }
 | |
| 
 | |
|         public void Insert(int index, T item)
 | |
|         {
 | |
|             if (Buffer == null || Count == Buffer.Length)
 | |
|             {
 | |
|                 Expand();
 | |
|             }
 | |
| 
 | |
|             if (index < Count)
 | |
|             {
 | |
|                 for (var i = Count; i > index; --i)
 | |
|                 {
 | |
|                     Buffer[i] = Buffer[i - 1];
 | |
|                 }
 | |
|                 Buffer[index] = item;
 | |
|                 ++Count;
 | |
|             }
 | |
|             else
 | |
|             {
 | |
|                 Add(item);
 | |
|             }
 | |
|         }
 | |
| 
 | |
|         public void RemoveAt(int index)
 | |
|         {
 | |
|             if (Buffer != null && index < Count)
 | |
|             {
 | |
|                 --Count;
 | |
|                 Buffer[index] = default(T);
 | |
|                 for (var b = index; b < Count; ++b)
 | |
|                 {
 | |
|                     Buffer[b] = Buffer[b + 1];
 | |
|                 }
 | |
|             }
 | |
|         }
 | |
| 
 | |
|         public T this[int index]
 | |
|         {
 | |
|             get
 | |
|             {
 | |
|                 if (Buffer == null)
 | |
|                 {
 | |
|                     throw new IndexOutOfRangeException();
 | |
|                 }
 | |
| 
 | |
|                 return Buffer[index];
 | |
|             }
 | |
|             set
 | |
|             {
 | |
|                 if (Buffer == null)
 | |
|                 {
 | |
|                     throw new IndexOutOfRangeException();
 | |
|                 }
 | |
| 
 | |
|                 Buffer[index] = value;
 | |
|             }
 | |
|         }
 | |
| 
 | |
|         public void OnBeforeSerialize()
 | |
|         {
 | |
|             Debug.Log("[OnBeforeSerialize] Count: {0}".Fmt(_count));
 | |
|             // Clean buffer of unused elements before serializing
 | |
|             Clean();
 | |
|         }
 | |
| 
 | |
|         public void OnAfterDeserialize()
 | |
|         {
 | |
|             Debug.Log("[OnAfterDeserialize] Count: {0}".Fmt(_count));
 | |
|         }
 | |
| 
 | |
|         /// <summary>
 | |
|         /// Add range of values to the list. Contains a foreach loop, which will allocate garbage when used with most
 | |
|         /// generic collection types.
 | |
|         /// </summary>
 | |
|         /// <param name="range"></param>
 | |
|         public void AddRange(IEnumerable<T> range)
 | |
|         {
 | |
|             foreach (var item in range)
 | |
|             {
 | |
|                 Add(item);
 | |
|             }
 | |
|         }
 | |
| 
 | |
|         /// <summary>
 | |
|         /// Clear the list, optionally setting each element to default(T)
 | |
|         /// </summary>
 | |
|         public void Clear(bool clean)
 | |
|         {
 | |
|             Clear();
 | |
| 
 | |
|             if (!clean)
 | |
|             {
 | |
|                 return;
 | |
|             }
 | |
| 
 | |
|             Clean();
 | |
|         }
 | |
| 
 | |
|         public void Clean()
 | |
|         {
 | |
|             if (Buffer == null)
 | |
|             {
 | |
|                 return;
 | |
|             }
 | |
| 
 | |
|             for (var i = Count; i < _buffer.Length; i++)
 | |
|             {
 | |
|                 _buffer[i] = default(T);
 | |
|             }
 | |
|         }
 | |
| 
 | |
|         /// <summary>
 | |
|         /// Get a read-only wrapper of this list. This is cached, so very little cost after first called.
 | |
|         /// </summary>
 | |
|         /// <returns></returns>
 | |
|         public ReadOnlyCollection<T> AsReadOnly()
 | |
|         {
 | |
|             if (_readOnlyWrapper == null)
 | |
|             {
 | |
|                 _readOnlyWrapper = new ReadOnlyCollection<T>(this);
 | |
|             }
 | |
| 
 | |
|             return _readOnlyWrapper;
 | |
|         }
 | |
| 
 | |
|         /// <summary>
 | |
|         /// Helper function that expands the size of the array, maintaining the content.
 | |
|         /// </summary>
 | |
|         private void Expand()
 | |
|         {
 | |
|             var newList = (Buffer != null) ? new T[Mathf.Max(Buffer.Length << 1, 32)] : new T[32];
 | |
| 
 | |
|             if (Buffer != null && Count > 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>
 | |
|         public void Trim()
 | |
|         {
 | |
|             if (Count > 0)
 | |
|             {
 | |
|                 if (Count >= Buffer.Length)
 | |
|                 {
 | |
|                     return;
 | |
|                 }
 | |
| 
 | |
|                 var newList = new T[Count];
 | |
| 
 | |
|                 for (var i = 0; i < Count; ++i)
 | |
|                 {
 | |
|                     newList[i] = Buffer[i];
 | |
|                 }
 | |
| 
 | |
|                 Buffer = newList;
 | |
|             }
 | |
|             else
 | |
|             {
 | |
|                 Buffer = new T[0];
 | |
|             }
 | |
|         }
 | |
| 
 | |
|         /// <summary>
 | |
|         /// List.Sort equivalent.
 | |
|         /// </summary>
 | |
|         public void Sort(Comparison<T> comparer)
 | |
|         {
 | |
|             var changed = true;
 | |
| 
 | |
|             while (changed)
 | |
|             {
 | |
|                 changed = false;
 | |
| 
 | |
|                 for (var i = 1; i < Count; ++i)
 | |
|                 {
 | |
|                     if (comparer.Invoke(Buffer[i - 1], Buffer[i]) > 0)
 | |
|                     {
 | |
|                         var temp = Buffer[i];
 | |
|                         Buffer[i] = Buffer[i - 1];
 | |
|                         Buffer[i - 1] = temp;
 | |
|                         changed = true;
 | |
|                     }
 | |
|                 }
 | |
|             }
 | |
|         }
 | |
|     }
 | |
| }
 |