using System; namespace Nordeus.DataStructures { #if !UNITY_WEBPLAYER using System.Runtime.InteropServices; using UnityEngine; /// /// This struct is used to access the hidden .Net fields of the Array type. /// [StructLayout(LayoutKind.Sequential, Pack = 1)] internal struct ArrayHeader { /// /// Array type. /// public UIntPtr type; /// /// Array length. /// public UIntPtr length; } #endif /// /// Highly specialized, unsafe-code-calling class which can alter the perceived length of the underlying buffer in runtime without /// copying the array. See the AsArrayOfLength method docs for more details. /// /// /// Since this class is abstract, you need to use a subclass which implements the functionality of your desired buffer type. /// Unfortunately, due to a limitation in C#'s unsafe code implementation, you cannot use arbitrary classes as type arguments, since /// the buffer elements have to be of a blittable type, and there's no way to enforce blittability through type parameter constraints. /// (And no, "where T: struct" doesn't cut it.) /// /// /// Note: This class is NOT thread-safe! /// example usage: /// verts.AsArrayOfLength(verts.size, (buffer) => /// { /// mesh.vertices = buffer; /// }); /// /// /// public abstract class VaryingList : BufferedList { /// /// The action delegate which will be invoked with the list's buffer (with its size modified) as a parameter. /// /// The underlying buffer with its size changed for the duration of this delegate's invokation. public delegate void ArrayAction(T[] array); #if !UNITY_WEBPLAYER /// /// Changes the perceived length of the underlying integer buffer for the duration of the invokation. The /// perceived buffer size is changed to and then the callback is invoked. During /// that time, the code in the callback sees the buffer as having the given . /// When the callback returns, the buffer's perceived size is returned to its normal value. /// /// Note: This method is NOT thread safe! Do not expect delayed actions to perceive the buffer as having the given length, /// since the length will be returned to normal as soon as the action delegate finishes. /// The length with which the underlying list buffer will be perceived. If it is less than zero, the action is /// not performed and this method exits immediately. If it is larger than the actual buffer size, this method acts as if it's the /// same as the buffer size. /// The action delegate during whose invokation the buffer will have a modified length. If it is null, this /// method exits immediately. public unsafe void AsArrayOfLength(int length, ArrayAction action) { //if (action == null || length <= 0) return; if (length <= 0) return; if (length > size) length = size; void* pBuffer = GetBufferPointer(); // Get the header ArrayHeader* header = (ArrayHeader*)pBuffer - 1; // Change the length UIntPtr originalLength = header->length; header->length = new UIntPtr((ulong)length); // Do stuff with the changed array if (action != null) { action(buffer); } // Revert back to old length header->length = originalLength; } /// /// Gets the buffer pointer. This is the only piece of information a subclass needs to provide to this class. The buffer has to /// contain only blittable types, and the compiler prevents unsafe code from operating on generic type arguments, so this method is /// a workaround for that. /// /// The buffer pointer. public abstract unsafe void* GetBufferPointer(); #endif /// /// Set return array with trimed-out free space. For non-web build we use unsafe code to change buffer duration /// in array header. /// public void TrimBuffer(ArrayAction action) { #if !UNITY_WEBPLAYER AsArrayOfLength(size, action); #else T[] bufferCopy = new T[size]; Array.Copy(buffer, bufferCopy, size); action(bufferCopy); #endif } } /// /// The implementation of for the integer element type. /// public class VaryingIntList : VaryingList { #if !UNITY_WEBPLAYER public override unsafe void* GetBufferPointer() { fixed (void* pBuffer = buffer) { return pBuffer; } } #endif } /// /// The implementation of for the element type. /// public class VaryingVector2List : VaryingList { #if !UNITY_WEBPLAYER public override unsafe void* GetBufferPointer() { fixed (void* pBuffer = buffer) { return pBuffer; } } #endif } /// /// The implementation of for the element type. /// public class VaryingVector3List : VaryingList { #if !UNITY_WEBPLAYER public override unsafe void* GetBufferPointer() { fixed (void* pBuffer = buffer) { return pBuffer; } } #endif } /// /// The implementation of for the element type. /// public class VaryingVector4List : VaryingList { #if !UNITY_WEBPLAYER public override unsafe void* GetBufferPointer() { fixed (void* pBuffer = buffer) { return pBuffer; } } #endif } /// /// The implementation of for the element type. /// public class VaryingColor32List : VaryingList { #if !UNITY_WEBPLAYER public override unsafe void* GetBufferPointer() { fixed (void* pBuffer = buffer) { return pBuffer; } } #endif } /// /// The implementation of for the element type. /// public class VaryingColorList : VaryingList { #if !UNITY_WEBPLAYER public override unsafe void* GetBufferPointer() { fixed (void* pBuffer = buffer) { return pBuffer; } } #endif } }