You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
319 lines
8.6 KiB
C#
319 lines
8.6 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using System.Runtime.InteropServices;
|
|
|
|
namespace UnityEngine.Formats.Alembic.Sdk
|
|
{
|
|
class PinnedObject<T> : IDisposable
|
|
{
|
|
T m_data;
|
|
GCHandle m_gch;
|
|
|
|
public PinnedObject(T data)
|
|
{
|
|
m_data = data;
|
|
m_gch = GCHandle.Alloc(m_data, GCHandleType.Pinned);
|
|
}
|
|
|
|
public T Object { get { return m_data; } }
|
|
public IntPtr Pointer { get { return m_gch.AddrOfPinnedObject(); } }
|
|
|
|
|
|
public void Dispose()
|
|
{
|
|
Dispose(true);
|
|
GC.SuppressFinalize(this);
|
|
}
|
|
|
|
protected virtual void Dispose(bool disposing)
|
|
{
|
|
if (disposing)
|
|
{
|
|
if (m_gch.IsAllocated)
|
|
m_gch.Free();
|
|
}
|
|
}
|
|
|
|
public static implicit operator IntPtr(PinnedObject<T> v)
|
|
{
|
|
return v == null ? IntPtr.Zero : v.Pointer;
|
|
}
|
|
|
|
internal static IntPtr ToIntPtr(PinnedObject<T> v) { return v; }
|
|
}
|
|
|
|
|
|
class PinnedArray<T> : IDisposable, IEnumerable<T> where T : struct
|
|
{
|
|
T[] m_data;
|
|
GCHandle m_gch;
|
|
|
|
public PinnedArray(int size)
|
|
{
|
|
m_data = new T[size];
|
|
m_gch = GCHandle.Alloc(m_data, GCHandleType.Pinned);
|
|
}
|
|
|
|
public PinnedArray(T[] data, bool clone = false)
|
|
{
|
|
if (data == null) { return; }
|
|
m_data = clone ? (T[])data.Clone() : data;
|
|
m_gch = GCHandle.Alloc(m_data, GCHandleType.Pinned);
|
|
}
|
|
|
|
public int Length { get { return m_data.Length; } }
|
|
public T this[int i]
|
|
{
|
|
get { return m_data[i]; }
|
|
set { m_data[i] = value; }
|
|
}
|
|
|
|
public T[] GetArray() { return m_data; }
|
|
public IntPtr Pointer { get { return m_data.Length == 0 ? IntPtr.Zero : m_gch.AddrOfPinnedObject(); } }
|
|
|
|
public PinnedArray<T> Clone() { return new PinnedArray<T>((T[])m_data.Clone()); }
|
|
public bool Assign(T[] source)
|
|
{
|
|
if (source != null && m_data.Length == source.Length)
|
|
{
|
|
System.Array.Copy(source, m_data, m_data.Length);
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
public void Dispose()
|
|
{
|
|
Dispose(true);
|
|
GC.SuppressFinalize(this);
|
|
}
|
|
|
|
protected virtual void Dispose(bool disposing)
|
|
{
|
|
if (disposing)
|
|
{
|
|
if (m_gch.IsAllocated)
|
|
m_gch.Free();
|
|
}
|
|
}
|
|
|
|
public IEnumerator<T> GetEnumerator()
|
|
{
|
|
return (IEnumerator<T>)m_data.GetEnumerator();
|
|
}
|
|
|
|
System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
|
|
{
|
|
return GetEnumerator();
|
|
}
|
|
|
|
public static implicit operator IntPtr(PinnedArray<T> v) { return v == null ? IntPtr.Zero : v.Pointer; }
|
|
internal static IntPtr ToIntPtr(PinnedArray<T> v) { return v; }
|
|
}
|
|
|
|
#region dirty
|
|
internal static class PinnedListImpl
|
|
{
|
|
class ListData
|
|
{
|
|
public object items;
|
|
public int size;
|
|
}
|
|
[StructLayout(LayoutKind.Explicit)]
|
|
struct Caster
|
|
{
|
|
[FieldOffset(0)] public object list;
|
|
[FieldOffset(0)] public ListData data;
|
|
}
|
|
|
|
internal static T[] GetInternalArray<T>(List<T> list) where T : struct
|
|
{
|
|
if (list == null)
|
|
{
|
|
return null;
|
|
}
|
|
var caster = new Caster();
|
|
caster.list = list;
|
|
return (T[])caster.data.items;
|
|
}
|
|
|
|
internal static List<T> CreateIntrusiveList<T>(T[] data) where T : struct
|
|
{
|
|
if (data == null)
|
|
{
|
|
return null;
|
|
}
|
|
|
|
var ret = new List<T>();
|
|
var caster = new Caster();
|
|
caster.list = ret;
|
|
caster.data.items = data;
|
|
caster.data.size = data.Length;
|
|
return ret;
|
|
}
|
|
|
|
internal static void SetCount<T>(List<T> list, int count) where T : struct
|
|
{
|
|
if (list == null)
|
|
{
|
|
return;
|
|
}
|
|
|
|
var caster = new Caster();
|
|
caster.list = list;
|
|
caster.data.size = count;
|
|
}
|
|
}
|
|
#endregion
|
|
|
|
|
|
// Pinned"List" but assume size is fixed (== functionality is same as PinnedArray).
|
|
// this class is intended to pass to Mesh.GetNormals(), Mesh.SetNormals(), and C++ functions.
|
|
class PinnedList<T> : IDisposable, IEnumerable<T> where T : struct
|
|
{
|
|
List<T> m_list;
|
|
T[] m_data;
|
|
GCHandle m_gch;
|
|
|
|
public PinnedList(int size = 0)
|
|
{
|
|
m_data = new T[size];
|
|
m_list = PinnedListImpl.CreateIntrusiveList(m_data);
|
|
m_gch = GCHandle.Alloc(m_data, GCHandleType.Pinned);
|
|
}
|
|
|
|
public PinnedList(T[] data, bool clone = false)
|
|
{
|
|
if (data == null)
|
|
{
|
|
return;
|
|
}
|
|
|
|
m_data = clone ? (T[])data.Clone() : data;
|
|
m_list = PinnedListImpl.CreateIntrusiveList(m_data);
|
|
m_gch = GCHandle.Alloc(m_data, GCHandleType.Pinned);
|
|
}
|
|
|
|
public PinnedList(List<T> data, bool clone = false)
|
|
{
|
|
m_list = clone ? new List<T>(data) : data;
|
|
m_data = PinnedListImpl.GetInternalArray(m_list);
|
|
m_gch = GCHandle.Alloc(m_data, GCHandleType.Pinned);
|
|
}
|
|
|
|
public int Capacity { get { return m_data.Length; } }
|
|
public int Count { get { return m_list.Count; } }
|
|
public T this[int i]
|
|
{
|
|
get { return m_data[i]; }
|
|
set { m_data[i] = value; }
|
|
}
|
|
|
|
public T[] GetArray() { return m_data; }
|
|
public List<T> List { get { return m_list; } }
|
|
public IntPtr Pointer { get { return Count == 0 ? IntPtr.Zero : m_gch.AddrOfPinnedObject(); } }
|
|
|
|
public void LockList(Action<List<T>> body)
|
|
{
|
|
if (body == null)
|
|
{
|
|
return;
|
|
}
|
|
|
|
if (m_gch.IsAllocated)
|
|
m_gch.Free();
|
|
body(m_list);
|
|
m_data = PinnedListImpl.GetInternalArray(m_list);
|
|
m_gch = GCHandle.Alloc(m_data, GCHandleType.Pinned);
|
|
}
|
|
|
|
public void Resize(int size)
|
|
{
|
|
if (size > m_data.Length)
|
|
{
|
|
LockList(l => {
|
|
l.Capacity = size;
|
|
});
|
|
}
|
|
PinnedListImpl.SetCount(m_list, size);
|
|
}
|
|
|
|
public void ResizeDiscard(int size)
|
|
{
|
|
if (size > m_data.Length)
|
|
{
|
|
if (m_gch.IsAllocated)
|
|
m_gch.Free();
|
|
m_data = new T[size];
|
|
m_list = PinnedListImpl.CreateIntrusiveList(m_data);
|
|
m_gch = GCHandle.Alloc(m_data, GCHandleType.Pinned);
|
|
}
|
|
else
|
|
{
|
|
PinnedListImpl.SetCount(m_list, size);
|
|
}
|
|
}
|
|
|
|
public void Clear()
|
|
{
|
|
if (m_data.Length > 0)
|
|
PinnedListImpl.SetCount(m_list, 0);
|
|
}
|
|
|
|
public PinnedList<T> Clone()
|
|
{
|
|
return new PinnedList<T>(m_list, true);
|
|
}
|
|
|
|
public void Assign(T[] source)
|
|
{
|
|
if (source == null)
|
|
{
|
|
return;
|
|
}
|
|
ResizeDiscard(source.Length);
|
|
System.Array.Copy(source, m_data, source.Length);
|
|
}
|
|
|
|
public void Assign(List<T> sourceList)
|
|
{
|
|
if (sourceList == null)
|
|
{
|
|
return;
|
|
}
|
|
var sourceData = PinnedListImpl.GetInternalArray(sourceList);
|
|
var count = sourceList.Count;
|
|
ResizeDiscard(count);
|
|
System.Array.Copy(sourceData, m_data, count);
|
|
}
|
|
|
|
public void Dispose()
|
|
{
|
|
Dispose(true);
|
|
GC.SuppressFinalize(this);
|
|
}
|
|
|
|
protected virtual void Dispose(bool disposing)
|
|
{
|
|
if (disposing)
|
|
{
|
|
if (m_gch.IsAllocated)
|
|
m_gch.Free();
|
|
}
|
|
}
|
|
|
|
public IEnumerator<T> GetEnumerator()
|
|
{
|
|
return (IEnumerator<T>)m_data.GetEnumerator();
|
|
}
|
|
|
|
System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
|
|
{
|
|
return GetEnumerator();
|
|
}
|
|
|
|
public static implicit operator IntPtr(PinnedList<T> v) { return v == null ? IntPtr.Zero : v.Pointer; }
|
|
internal static IntPtr ToIntPtr(PinnedList<T> v) { return v; }
|
|
}
|
|
}
|