您最多选择25个主题
主题必须以中文或者字母或数字开头,可以包含连字符 (-),并且长度不得超过35个字符
375 行
13 KiB
375 行
13 KiB
using System;
|
|
|
|
namespace UnityEngine.Experimental
|
|
{
|
|
public struct VectorArray<T>
|
|
{
|
|
public const uint k_InvalidIdx = uint.MaxValue;
|
|
private T[] m_array; // backing storage
|
|
private uint m_offset; // offset into backing storage
|
|
private uint m_count; // active slots, <= m_array.Length
|
|
private bool m_clearToDefault; // if true, freed up slots will be default initialized
|
|
|
|
public VectorArray(uint capacity, bool clearToDefault)
|
|
{
|
|
m_array = new T[capacity];
|
|
m_offset = 0;
|
|
m_count = capacity;
|
|
m_clearToDefault = clearToDefault;
|
|
}
|
|
|
|
public VectorArray(T[] array, uint offset, uint count, bool clearToDefault)
|
|
{
|
|
m_array = array;
|
|
m_offset = offset;
|
|
m_count = count;
|
|
m_clearToDefault = clearToDefault;
|
|
}
|
|
|
|
public VectorArray(ref VectorArray<T> vec, uint offset, uint count)
|
|
{
|
|
m_array = vec.m_array;
|
|
m_offset = vec.m_offset + offset;
|
|
m_count = count;
|
|
m_clearToDefault = vec.m_clearToDefault;
|
|
}
|
|
|
|
// Reset fill count, but keep storage
|
|
public void Reset()
|
|
{
|
|
if (m_clearToDefault)
|
|
{
|
|
for (uint i = 0; i < m_count; ++i)
|
|
this[i] = default(T);
|
|
}
|
|
m_count = 0;
|
|
}
|
|
|
|
// Reset fill count and reserve enough storage
|
|
public void Reset(uint capacity)
|
|
{
|
|
if (m_array.Length < (m_offset + capacity))
|
|
{
|
|
m_array = new T[capacity];
|
|
m_offset = 0;
|
|
m_count = 0;
|
|
}
|
|
else
|
|
Reset();
|
|
}
|
|
|
|
// Reserve additional storage
|
|
public void Reserve(uint capacity)
|
|
{
|
|
if (m_offset + m_count + capacity <= m_array.Length)
|
|
return;
|
|
|
|
if (m_count == 0)
|
|
{
|
|
m_array = new T[capacity];
|
|
}
|
|
else
|
|
{
|
|
T[] tmp = new T[m_count + capacity];
|
|
Array.Copy(m_array, m_offset, tmp, 0, m_count);
|
|
m_array = tmp;
|
|
}
|
|
m_offset = 0;
|
|
}
|
|
|
|
// Resize array, either by cutting off at the end, or adding potentially default initialized slots
|
|
// Resize will modify the count member as well, whereas reserve won't.
|
|
public void Resize(uint size)
|
|
{
|
|
if (size > m_count)
|
|
{
|
|
uint residue = size - m_count;
|
|
Reserve(residue);
|
|
}
|
|
else if (m_clearToDefault)
|
|
{
|
|
for (uint i = size; i < m_count; ++i)
|
|
this[i] = default(T);
|
|
}
|
|
m_count = size;
|
|
}
|
|
|
|
public delegate void Cleanup(T obj);
|
|
// Same as Resize(), with an additional delegate to do any cleanup on the potentially freed slots
|
|
public void Resize(uint size, Cleanup cleanupDelegate)
|
|
{
|
|
for (uint i = size; i < m_count; ++i)
|
|
cleanupDelegate(this[i]);
|
|
|
|
Resize(size);
|
|
}
|
|
|
|
// Same as Reset(), with an additional delegate to do any cleanup on the potentially freed slots
|
|
public void Reset(Cleanup cleanupDelegate)
|
|
{
|
|
for (uint i = 0; i < m_count; ++i)
|
|
cleanupDelegate(this[i]);
|
|
|
|
Reset();
|
|
}
|
|
|
|
// Same as Reset( uint capacity ), with an additional delegate to do any cleanup on the potentially freed slots
|
|
public void Reset(uint capacity, Cleanup cleanupDelegate)
|
|
{
|
|
for (uint i = 0; i < m_count; ++i)
|
|
cleanupDelegate(this[i]);
|
|
|
|
Reset(capacity);
|
|
}
|
|
|
|
// Add obj and reallocate if necessary. Returns the index where the object was added.
|
|
public uint Add(T obj)
|
|
{
|
|
Reserve(1);
|
|
uint idx = m_count;
|
|
this[idx] = obj;
|
|
m_count++;
|
|
return idx;
|
|
}
|
|
|
|
// Add multiple objects and reallocate if necessary. Returns the index where the first object was added.
|
|
public uint Add(T[] objs, uint count)
|
|
{
|
|
Reserve(count);
|
|
return AddUnchecked(objs, count);
|
|
}
|
|
|
|
public uint Add(ref VectorArray<T> vec)
|
|
{
|
|
Reserve(vec.Count());
|
|
return AddUnchecked(ref vec);
|
|
}
|
|
|
|
// Adds the object if it does not exist in the container, yet
|
|
public uint AddUnique(T obj)
|
|
{
|
|
Reserve(1);
|
|
return AddUniqueUnchecked(obj);
|
|
}
|
|
|
|
public uint AddUnique(T[] objs, uint count)
|
|
{
|
|
Reserve(count);
|
|
return AddUniqueUnchecked(objs, count);
|
|
}
|
|
|
|
public uint AddUnique(ref VectorArray<T> vec)
|
|
{
|
|
Reserve(vec.Count());
|
|
return AddUniqueUnchecked(ref vec);
|
|
}
|
|
|
|
// Add an object without doing size checks. Make sure to call Reserve( capacity ) before using this.
|
|
public uint AddUnchecked(T obj)
|
|
{
|
|
uint idx = m_count;
|
|
this[idx] = obj;
|
|
m_count++;
|
|
return idx;
|
|
}
|
|
|
|
// Add multiple objects without doing size checks. Make sure to call Reserve( capacity ) before using this.
|
|
public uint AddUnchecked(T[] objs, uint count)
|
|
{
|
|
uint idx = m_count;
|
|
Array.Copy(objs, 0, m_array, m_offset + idx, count);
|
|
m_count += count;
|
|
return idx;
|
|
}
|
|
|
|
public uint AddUnchecked(ref VectorArray<T> vec)
|
|
{
|
|
uint cnt = vec.Count();
|
|
uint idx = m_count;
|
|
Array.Copy(vec.m_array, vec.m_offset, m_array, m_offset + idx, cnt);
|
|
m_count += cnt;
|
|
return idx;
|
|
}
|
|
|
|
// Adds the object if it does not exist in the container, yet
|
|
public uint AddUniqueUnchecked(T obj)
|
|
{
|
|
if (!Contains(obj))
|
|
return Add(obj);
|
|
return k_InvalidIdx;
|
|
}
|
|
|
|
public uint AddUniqueUnchecked(T[] objs, uint count)
|
|
{
|
|
uint res = k_InvalidIdx;
|
|
for (uint i = 0; i < count; ++i)
|
|
{
|
|
uint tmp = AddUniqueUnchecked(objs[i]);
|
|
res = res <= tmp ? res : tmp;
|
|
}
|
|
return res;
|
|
}
|
|
|
|
public uint AddUniqueUnchecked(ref VectorArray<T> vec)
|
|
{
|
|
uint res = k_InvalidIdx;
|
|
for (uint i = 0, cnt = vec.Count(); i < cnt; ++i)
|
|
{
|
|
uint tmp = AddUniqueUnchecked(vec[i]);
|
|
res = res <= tmp ? res : tmp;
|
|
}
|
|
return res;
|
|
}
|
|
|
|
// Purge count number of elements from the end of the array.
|
|
public void Purge(uint count)
|
|
{
|
|
Resize(count > m_count ? 0 : (m_count - count));
|
|
}
|
|
|
|
// Same as Purge with an additional cleanup delegate.
|
|
public void Purge(uint count, Cleanup cleanupDelegate)
|
|
{
|
|
Resize(count > m_count ? 0 : (m_count - count), cleanupDelegate);
|
|
}
|
|
|
|
// Copies the active elements to the destination. destination.Length must be large enough to hold all values.
|
|
public void CopyTo(T[] destination, int destinationStart, out uint count)
|
|
{
|
|
count = m_count;
|
|
Array.Copy(m_array, m_offset, destination, destinationStart, count);
|
|
}
|
|
|
|
// Swaps two elements in the array doing bounds checks.
|
|
public void Swap(uint first, uint second)
|
|
{
|
|
if (first >= m_count || second >= m_count)
|
|
throw new System.ArgumentException("Swap indices are out of range.");
|
|
|
|
SwapUnchecked(first, second);
|
|
}
|
|
|
|
// Swaps two elements without any checks.
|
|
public void SwapUnchecked(uint first, uint second)
|
|
{
|
|
T tmp = this[first];
|
|
this[first] = this[second];
|
|
this[second] = tmp;
|
|
}
|
|
|
|
// Extracts information from objects contained in the array and stores them in the destination array.
|
|
// Conversion is performed by the extractor delegate for each object.
|
|
// The destination array must be large enough to hold all values.
|
|
// The output parameter count will contain the number of actual objects written out to the destination array.
|
|
public delegate U Extractor<U>(T obj);
|
|
public void ExtractTo<U>(U[] destination, int destinationStart, out uint count, Extractor<U> extractorDelegate)
|
|
{
|
|
if (destination.Length < m_count)
|
|
throw new System.ArgumentException("Destination array is too small for source array.");
|
|
|
|
count = m_count;
|
|
for (uint i = 0; i < m_count; ++i)
|
|
destination[destinationStart + i] = extractorDelegate(this[i]);
|
|
}
|
|
|
|
public void ExtractTo<U>(ref VectorArray<U> destination, Extractor<U> extractorDelegate)
|
|
{
|
|
destination.Reserve(m_count);
|
|
for (uint i = 0; i < m_count; ++i)
|
|
destination.AddUnchecked(extractorDelegate(this[i]));
|
|
}
|
|
|
|
// Cast to array. The output parameter will contain the array offset to valid members and the number of active elements.
|
|
// Accessing array elements outside of this interval will lead to undefined behavior.
|
|
public T[] AsArray(out uint offset, out uint count)
|
|
{
|
|
offset = m_offset;
|
|
count = m_count;
|
|
return m_array;
|
|
}
|
|
|
|
// Array access. No bounds checking here, make sure you know what you're doing.
|
|
public T this[uint index]
|
|
{
|
|
get { return m_array[m_offset + index]; }
|
|
set { m_array[m_offset + index] = value; }
|
|
}
|
|
|
|
// Returns the number of active elements in the vector.
|
|
public uint Count()
|
|
{
|
|
return m_count;
|
|
}
|
|
|
|
// Returns the total capacity of accessible backing storage
|
|
public uint CapacityTotal()
|
|
{
|
|
return (uint)m_array.Length - m_offset;
|
|
}
|
|
|
|
// Return the number of slots that can still be added before reallocation of the backing storage becomes necessary.
|
|
public uint CapacityAvailable()
|
|
{
|
|
return (uint)m_array.Length - m_offset - m_count;
|
|
}
|
|
|
|
// Default sort the active array content.
|
|
public void Sort()
|
|
{
|
|
Debug.Assert(m_count <= int.MaxValue && m_offset <= int.MaxValue);
|
|
Array.Sort(m_array, (int)m_offset, (int)m_count);
|
|
}
|
|
|
|
// Sort according to some comparer
|
|
public void Sort(System.Collections.Generic.IComparer<T> comparer)
|
|
{
|
|
Debug.Assert(m_count <= int.MaxValue && m_offset <= int.MaxValue);
|
|
Array.Sort(m_array, (int)m_offset, (int)m_count, comparer);
|
|
}
|
|
|
|
// Returns true if the element matches the designator according to the comparator. idx will hold the index to the first matched object in the array.
|
|
public delegate bool Comparator<U>(ref U designator, ref T obj);
|
|
public bool FindFirst<U>(out uint idx, ref U designator, Comparator<U> compareDelegate)
|
|
{
|
|
for (idx = 0; idx < m_count; ++idx)
|
|
{
|
|
if (compareDelegate(ref designator, ref m_array[m_offset + idx]))
|
|
return true;
|
|
}
|
|
idx = k_InvalidIdx;
|
|
return false;
|
|
}
|
|
|
|
// Returns true if the element matches the designator using the types native compare method. idx will hold the index to the first matched object in the array.
|
|
public bool FindFirst(out uint idx, ref T designator)
|
|
{
|
|
for (idx = 0; idx < m_count; ++idx)
|
|
{
|
|
if (System.Collections.Generic.EqualityComparer<T>.Default.Equals(m_array[m_offset + idx], designator))
|
|
return true;
|
|
}
|
|
idx = k_InvalidIdx;
|
|
return false;
|
|
}
|
|
|
|
// Returns true if the container already contains the element
|
|
public bool Contains(T designator)
|
|
{
|
|
uint idx;
|
|
return FindFirst(out idx, ref designator);
|
|
}
|
|
|
|
// Returns true if the container already contains the element
|
|
public bool Contains<U>(U designator, Comparator<U> compareDelegate)
|
|
{
|
|
uint idx;
|
|
return FindFirst(out idx, ref designator, compareDelegate);
|
|
}
|
|
|
|
// Returns a vector representing a subrange. Contents are shared, not duplicated.
|
|
public VectorArray<T> Subrange(uint offset, uint count)
|
|
{
|
|
return new VectorArray<T>(m_array, m_offset + offset, count, m_clearToDefault);
|
|
}
|
|
}
|
|
}
|