using System; using System.Collections; using System.Collections.Generic; using System.Runtime.InteropServices; namespace UTJ.FbxExporter { public class PinnedList : IDisposable, IEnumerable, IEnumerable { public PinnedList(int size = 0) { this.m_data = new T[size]; this.m_list = PinnedList.ListCreateIntrusive(this.m_data); this.m_gch = GCHandle.Alloc(this.m_data, GCHandleType.Pinned); } public PinnedList(T[] data, bool clone = false) { this.m_data = ((!clone) ? data : ((T[])data.Clone())); this.m_list = PinnedList.ListCreateIntrusive(this.m_data); this.m_gch = GCHandle.Alloc(this.m_data, GCHandleType.Pinned); } public PinnedList(List data, bool clone = false) { this.m_list = ((!clone) ? data : new List(data)); this.m_data = PinnedList.ListGetInternalArray(this.m_list); this.m_gch = GCHandle.Alloc(this.m_data, GCHandleType.Pinned); } public static T[] ListGetInternalArray(List list) { PinnedList.Caster caster = default(PinnedList.Caster); caster.list = list; return caster.data.items; } public static List ListCreateIntrusive(T[] data) { List list = new List(); PinnedList.Caster caster = default(PinnedList.Caster); caster.list = list; caster.data.items = data; caster.data.size = data.Length; return list; } public static void ListSetCount(List list, int count) { PinnedList.Caster caster = default(PinnedList.Caster); caster.list = list; caster.data.size = count; } public int Capacity { get { return this.m_data.Length; } } public int Count { get { return this.m_list.Count; } } public T this[int i] { get { return this.m_data[i]; } set { this.m_data[i] = value; } } public T[] Array { get { return this.m_data; } } public List List { get { return this.m_list; } } public IntPtr Pointer { get { return (this.Count != 0) ? this.m_gch.AddrOfPinnedObject() : IntPtr.Zero; } } public void LockList(Action> body) { if (this.m_gch.IsAllocated) { this.m_gch.Free(); } body(this.m_list); this.m_data = PinnedList.ListGetInternalArray(this.m_list); this.m_gch = GCHandle.Alloc(this.m_data, GCHandleType.Pinned); } public void Resize(int size) { if (size > this.m_data.Length) { this.LockList(delegate(List l) { l.Capacity = size; }); } PinnedList.ListSetCount(this.m_list, size); } public void ResizeDiscard(int size) { if (size > this.m_data.Length) { if (this.m_gch.IsAllocated) { this.m_gch.Free(); } this.m_data = new T[size]; this.m_list = PinnedList.ListCreateIntrusive(this.m_data); this.m_gch = GCHandle.Alloc(this.m_data, GCHandleType.Pinned); } else { PinnedList.ListSetCount(this.m_list, size); } } public void Clear() { if (this.m_data.Length > 0) { PinnedList.ListSetCount(this.m_list, 0); } } public PinnedList Clone() { return new PinnedList(this.m_list, true); } public void Assign(T[] source) { this.ResizeDiscard(source.Length); System.Array.Copy(source, this.m_data, source.Length); } public void Assign(List sourceList) { T[] sourceArray = PinnedList.ListGetInternalArray(sourceList); int count = sourceList.Count; this.ResizeDiscard(count); System.Array.Copy(sourceArray, this.m_data, count); } public void Dispose() { this.Dispose(true); GC.SuppressFinalize(this); } protected virtual void Dispose(bool disposing) { if (disposing && this.m_gch.IsAllocated) { this.m_gch.Free(); } } public IEnumerator GetEnumerator() { return (IEnumerator)this.m_data.GetEnumerator(); } IEnumerator IEnumerable.GetEnumerator() { return this.GetEnumerator(); } public static implicit operator IntPtr(PinnedList v) { return (v != null) ? v.Pointer : IntPtr.Zero; } public static implicit operator T[](PinnedList v) { return (v != null) ? v.Array : null; } public static implicit operator List(PinnedList v) { return (v != null) ? v.List : null; } private List m_list; private T[] m_data; private GCHandle m_gch; private class ListData { public T[] items; public int size; } [StructLayout(LayoutKind.Explicit)] private struct Caster { [FieldOffset(0)] public List list; [FieldOffset(0)] public PinnedList.ListData data; } } }