Example #1
0
 public void GetArrays(out Vector3[] vertices, out Vector3[] normals, out Color32[] colors, out int[] indices)
 {
     vertices = NoAllocHelpers.ExtractArrayFromListT(Vertices);
     normals  = NoAllocHelpers.ExtractArrayFromListT(Normals);
     colors   = NoAllocHelpers.ExtractArrayFromListT(Colors);
     indices  = NoAllocHelpers.ExtractArrayFromListT(Indices);
 }
Example #2
0
        public unsafe void LateUpdate()
        {
            var vertices = this.instance.vertices.cpuReference;

            fixed(Vector3 *pVertices = vertices)
            {
                UnsafeUtility.MemCpy(this.splineVertices.GetUnsafePtr(), (void *)pVertices, UnsafeUtility.SizeOf <Vector3>() * vertices.Length);
            }

            handle = new PositionUpdateJob()
            {
                normals      = this.normals,
                segments     = this.segments,
                hairVertices = this.splineVertices,
                vertices     = this.triVertices,
                facing       = this.facing.position,
                hairWidth    = this.hairWidth,
                worldToLocal = this.transform.worldToLocalMatrix
            }.Schedule(this.segments.Length, 16);

            JobHandle.ScheduleBatchedJobs();
            handle.Complete();
            NoAllocHelpers.SetMesh(this.mesh, this.triVertices, null, this.normals);
            this.mesh.UploadMeshData(false);
        }
Example #3
0
        public void ResizeListCorrectCount()
        {
            var list = new List <int>(5);

            NoAllocHelpers.ResizeList(list, 3);
            Assert.AreEqual(3, list.Count);
        }
        /// <summary>Erases tiles and GameObjects from given bounds within the selected layers.</summary>
        /// <param name="gridLayout">Grid to erase data from.</param>
        /// <param name="brushTarget">Target of the erase operation. By default the currently selected GameObject.</param>
        /// <param name="position">The bounds to erase data from.</param>
        public override void BoxErase(GridLayout gridLayout, GameObject brushTarget, BoundsInt position)
        {
            if (brushTarget == null)
            {
                return;
            }

            Tilemap map = brushTarget.GetComponent <Tilemap>();

            if (map == null)
            {
                return;
            }

            int count    = 0;
            var identity = Matrix4x4.identity;
            var listSize = Math.Abs(position.size.x * position.size.y * position.size.z);

            if (m_TileChangeDataList == null || m_TileChangeDataList.Capacity != listSize)
            {
                m_TileChangeDataList = new List <TileChangeData>(listSize);
            }
            m_TileChangeDataList.Clear();
            foreach (Vector3Int location in position.allPositionsWithin)
            {
                m_TileChangeDataList.Add(new TileChangeData {
                    position = location, tile = null, transform = identity, color = Color.white
                });
            }
            var tileChangeData = NoAllocHelpers.ExtractArrayFromListT(m_TileChangeDataList);

            map.SetTiles(tileChangeData, false);
        }
Example #5
0
        void TransformShadows(LayerSubMesh mesh)
        {
            if (mesh.uvs.Count == 0)
            {
                return;
            }

            var rot       = Rot4.FromAngleFlat(target);
            var uvs       = mesh.uvs;
            var vertsc    = mesh.verts.Count;
            var origVerts = NoAllocHelpers.ExtractArrayFromListT(mesh.verts);

            Util.ResizeIfNeeded(ref tempVerts, vertsc);

            for (int i = 0; i <= vertsc - 5; i += 5)
            {
                var offset = uvs[i / 10];
                if (offset == Vector3.zero)
                {
                    Array.Copy(origVerts, i, tempVerts, i, 5);
                    continue;
                }

                var r = offset.RotatedBy(rot) - offset;

                tempVerts[i]     = origVerts[i] + r;
                tempVerts[i + 1] = origVerts[i + 1] + r;
                tempVerts[i + 2] = origVerts[i + 2] + r;
                tempVerts[i + 3] = origVerts[i + 3] + r;
                tempVerts[i + 4] = origVerts[i + 4] + r;
            }

            mesh.mesh.SetVertices(tempVerts, vertsc);
        }
 public static unsafe void *GetUnsafePtr <T>(this List <T> list, out ulong gcHandle)
     where T : struct
 {
     return(UnsafeUtility.PinGCArrayAndGetDataAddress(
                NoAllocHelpers.ExtractArrayFromListT(list),
                out gcHandle
                ));
 }
Example #7
0
 public void SetIndexCount(int count)
 {
     if (count > Indices.Capacity)
     {
         Indices.Capacity = count;
     }
     NoAllocHelpers.ResizeList(Indices, count);
 }
 public static Mesh.MeshDataArray AcquireReadOnlyMeshData(List <Mesh> meshes)
 {
     if (meshes == null)
     {
         throw new ArgumentNullException(nameof(meshes), "Mesh list is null");
     }
     return(new Mesh.MeshDataArray(NoAllocHelpers.ExtractArrayFromListT(meshes), meshes.Count, false));
 }
Example #9
0
 public static void CopyTo <T>(List <T> dst, List <T> src) where T : unmanaged
 {
     dst.Capacity = src.Count;
     NoAllocHelpers.ResizeList(dst, src.Count);
     using (dst.ViewAsNativeArray(out var dstArray))
         using (src.ViewAsNativeArray(out var srcArray))
             dstArray.CopyFrom(srcArray);
 }
Example #10
0
        public static void ResizeList <T>(List <T> list, int count)
        {
            if (list.Capacity < count)
            {
                list.Capacity = count;
            }

            NoAllocHelpers.ResizeList(list, count);
        }
Example #11
0
    public static unsafe List <int> V128Filter(List <int> src, int target)
    {
        var dst = new List <int>(src.Count);

        using var srcDispose = src.ViewAsNativeArray(out var srcArray);
        using var dstDispose = dst.ViewAsNativeArray(out var dstArray);
        V128Filter((int *)srcArray.GetUnsafeReadOnlyPtr(), srcArray.Length, target, (int *)dstArray.GetUnsafePtr(), out var dstCount);
        NoAllocHelpers.ResizeList(dst, dstCount);
        return(dst);
    }
Example #12
0
    public static unsafe List <int> V128Filter(List <int> list, int greaterThan, int lessThan)
    {
        var dst = new List <int>(list.Count);

        using var srcDispose = list.ViewAsNativeArray(out var srcArray);
        using var dstDispose = dst.ViewAsNativeArray(out var dstArray);
        V128Filter((int *)srcArray.GetUnsafeReadOnlyPtr(), srcArray.Length, greaterThan, lessThan, (int *)dstArray.GetUnsafePtr(), out var dstCount);
        NoAllocHelpers.ResizeList(dst, dstCount);
        return(dst);
    }
Example #13
0
    public static unsafe List <u32> V128ForLoop(List <u8> src)
    {
        var dst = new List <u32>(src.Count / 3);

        using (dst.ViewAsNativeArray(out var dstArray))
            using (src.ViewAsNativeArray(out var srcArray))
                V128ForLoop((u8 *)srcArray.GetUnsafePtr(), (u32 *)dstArray.GetUnsafePtr(), dst.Capacity);

        NoAllocHelpers.ResizeList(dst, src.Count / 3);
        return(dst);
    }
Example #14
0
 public SoAMesh(int vertexCount, int indexCount)
 {
     Vertices = new List <Vector3>(vertexCount);
     Normals  = new List <Vector3>(vertexCount);
     Colors   = new List <Color32>(vertexCount);
     Indices  = new List <int>(indexCount);
     NoAllocHelpers.ResizeList(Vertices, vertexCount);
     NoAllocHelpers.ResizeList(Normals, vertexCount);
     NoAllocHelpers.ResizeList(Colors, vertexCount);
     NoAllocHelpers.ResizeList(Indices, indexCount);
 }
Example #15
0
 // Note: No checking that there is actually this many vertices in here.
 // However, it will increase capacity if needed.
 public void SetVertexCount(int count)
 {
     if (count > Vertices.Capacity)
     {
         Vertices.Capacity = count;
         Normals.Capacity  = count;
         Colors.Capacity   = count;
     }
     NoAllocHelpers.ResizeList(Vertices, count);
     NoAllocHelpers.ResizeList(Normals, count);
     NoAllocHelpers.ResizeList(Colors, count);
 }
Example #16
0
        void TransformVerts(LayerSubMesh mesh)
        {
            var offset  = Rot4.FromAngleFlat(target);
            var offseti = offset.AsInt;

            var uvs       = mesh.uvs;
            var vertsc    = mesh.verts.Count;
            var origVerts = NoAllocHelpers.ExtractArrayFromListT(mesh.verts);

            // Rotate around a center
            if (PrintPlanePatch.plantMats.Contains(mesh.material) ||
                GraphicPrintPatch.graphicSingle.Contains(mesh.material))
            {
                if (uvs.Count * 4 != vertsc)
                {
                    Log.ErrorOnce($"Carousel: Bad material {mesh.material}", mesh.material.GetHashCode());
                    return;
                }

                Util.ResizeIfNeeded(ref tempVerts, vertsc);

                for (int i = 0; i < vertsc; i += 4)
                {
                    // The mesh data lists are only used during mesh building and are otherwise unused
                    // In between mesh rebuilding, Carousel uses the uv list to store object centers for rotation
                    var c = uvs[i / 4];

                    tempVerts[i]     = c + (origVerts[i] - c).RotatedBy(offset);
                    tempVerts[i + 1] = c + (origVerts[i + 1] - c).RotatedBy(offset);
                    tempVerts[i + 2] = c + (origVerts[i + 2] - c).RotatedBy(offset);
                    tempVerts[i + 3] = c + (origVerts[i + 3] - c).RotatedBy(offset);
                }

                mesh.mesh.SetVertices(tempVerts, vertsc);
            }

            // Exchange vertices
            if (GraphicPrintPatch.matData.ContainsKey(mesh.material) ||
                LinkedPrintPatch.linkedMaterials.Contains(mesh.material))
            {
                Util.ResizeIfNeeded(ref tempVerts, vertsc);

                for (int i = 0; i < vertsc; i += 4)
                {
                    tempVerts[i].SetXZY(ref origVerts[i + (offseti & 3)], origVerts[i].y);
                    tempVerts[i + 1].SetXZY(ref origVerts[i + (offseti + 1 & 3)], origVerts[i + 1].y);
                    tempVerts[i + 2].SetXZY(ref origVerts[i + (offseti + 2 & 3)], origVerts[i + 2].y);
                    tempVerts[i + 3].SetXZY(ref origVerts[i + (offseti + 3 & 3)], origVerts[i + 3].y);
                }

                mesh.mesh.SetVertices(tempVerts, vertsc);
            }
        }
Example #17
0
        void TransformAtlas(LayerSubMesh mesh, TextureAtlasGroup group)
        {
            var offset   = Rot4.FromAngleFlat(target);
            var offseti  = offset.AsInt;
            var vertsc   = mesh.verts.Count / 5 * 4;
            var uvsc     = mesh.uvs.Count;
            var vertsArr = NoAllocHelpers.ExtractArrayFromListT(mesh.verts);
            var uvsArr   = NoAllocHelpers.ExtractArrayFromListT(mesh.uvs);

            Util.ResizeIfNeeded(ref tempVerts, vertsc);
            Util.ResizeIfNeeded(ref tempUVs, uvsc);

            for (int i = 0; i < vertsc; i += 4)
            {
                var data = vertsArr[vertsc + i / 4];

                if (data.x == PrintPlanePatch.SPECIAL_X)
                {
                    ExchangeVerts(tempVerts, vertsArr, i, offseti);

                    var rotData  = ((int)data.z & 0b1100) >> 2;
                    var flipData = (int)data.z & 0b0011;

                    var relRot  = GenMath.PositiveMod(rotData - Rot4.FromAngleFlat(target).AsInt, 4);
                    var flipped = relRot == 1 && ((flipData & 1) == 1) || relRot == 3 && ((flipData & 2) == 2) ? 1 : 0;

                    var rotatedMat = GraphicPrintPatch_SetData.intToGraphic[(int)data.y].mats[(rotData + Rot4.FromAngleFlat(-target).AsInt) % 4];
                    Graphic.TryGetTextureAtlasReplacementInfo(rotatedMat, group, false, false, out _, out var uvs, out _);

                    FixUVs(
                        tempUVs,
                        uvs,
                        i,
                        flipped
                        );
                }
                else if (data.x != PrintPlanePatch.EMPTY_X)
                {
                    RotateVerts(tempVerts, vertsArr, i, data, offset);
                    Array.Copy(uvsArr, i, tempUVs, i, 4);
                }
                else
                {
                    Array.Copy(vertsArr, i, tempVerts, i, 4);
                    Array.Copy(uvsArr, i, tempUVs, i, 4);
                }
            }

            mesh.mesh.SetVertices(tempVerts, vertsc);
            mesh.mesh.SetUVs(tempUVs, uvsc);
        }
        /// <summary>Box fills tiles and GameObjects into given bounds within the selected layers.</summary>
        /// <param name="gridLayout">Grid to box fill data to.</param>
        /// <param name="brushTarget">Target of the box fill operation. By default the currently selected GameObject.</param>
        /// <param name="position">The bounds to box fill data into.</param>
        public override void BoxFill(GridLayout gridLayout, GameObject brushTarget, BoundsInt position)
        {
            if (brushTarget == null)
            {
                return;
            }

            Tilemap map = brushTarget.GetComponent <Tilemap>();

            if (map == null)
            {
                return;
            }

            int count    = 0;
            var listSize = position.size.x * position.size.y * position.size.z;

            if (m_TileChangeDataList == null || m_TileChangeDataList.Capacity != listSize)
            {
                m_TileChangeDataList = new List <TileChangeData>(listSize);
            }
            m_TileChangeDataList.Clear();
            foreach (Vector3Int location in position.allPositionsWithin)
            {
                Vector3Int local = location - position.min;
                BrushCell  cell  = m_Cells[GetCellIndexWrapAround(local.x, local.y, local.z)];
                if (cell.tile == null)
                {
                    continue;
                }

                var tcd = new TileChangeData {
                    position = location, tile = cell.tile, transform = cell.matrix, color = cell.color
                };
                m_TileChangeDataList.Add(tcd);
                count++;
            }
            // Duplicate empty slots in the list, as ExtractArrayFromListT returns full list
            if (0 < count && count < listSize)
            {
                var tcd = m_TileChangeDataList[count - 1];
                for (int i = count; i < listSize; ++i)
                {
                    m_TileChangeDataList.Add(tcd);
                }
            }
            var tileChangeData = NoAllocHelpers.ExtractArrayFromListT(m_TileChangeDataList);

            map.SetTiles(tileChangeData, false);
        }
Example #19
0
    /// <summary>
    /// View <paramref name="list"/> as a <see cref="NativeArray{T}"/> without having to copy it or doing all the boilerplate for getting the pointer out of a list.
    /// Useful for allowing a job to work on a list.
    ///
    /// <para>
    /// Put this thing in a disposable scope unless you can guarantee that the list will never change size or reallocate (in that case consider using a <see cref="NativeArray{T}"/> instead),
    /// as Unity will <b>not</b> tell you if you're out of bounds, accessing invalid data, or accessing stale data because you have a stale/invalid view of the list.
    /// The following changes to the list will turn a view invalid/stale:
    /// <list type="number">
    /// <item>The contents of the array will be stale (not reflect any changes to the values in the list) in case of a reallocation (changes to, or adding more items than, <see cref="List{T}.Capacity"/> or using <see cref="List{T}.TrimExcess"/>)</item>
    /// <item>The length of the array will be wrong if you add/remove elements from the list</item>
    /// </list>
    /// </para>
    ///
    /// <para>
    /// The <paramref name="nativeArray"/> itself does not need to be disposed, but you need to dispose the <see cref="NativeArrayViewHandle"/> you get back, Unity's Memory Leak Detection will tell you if you forget.
    /// Do not use the array after calling <see cref="NativeArrayViewHandle.Dispose"/> on the <see cref="NativeArrayViewHandle"/> returned from this function,
    /// as you can risk the garbage collector removing the data from down under you, Unity's Collections Safety Checks will tell you if you do this.
    /// There is <b>no</b> race detection for accessing multiple different views of the same list in different jobs concurrently, or modifying the list while a job is working on a view.
    /// </para>
    ///
    /// Usage:
    /// <code>
    /// List&lt;int&gt; list;
    /// using (list.ViewAsNativeArray(out var nativeArray))
    /// {
    ///     // work on nativeArray
    /// }
    /// </code>
    /// </summary>
    public unsafe static NativeArrayViewHandle ViewAsNativeArray <T>(this List <T> list, out NativeArray <T> nativeArray) where T : struct
    {
        var lArray = NoAllocHelpers.ExtractArrayFromListT(list);
        var ptr    = UnsafeUtility.PinGCArrayAndGetDataAddress(lArray, out var handle);

        nativeArray = NativeArrayUnsafeUtility.ConvertExistingDataToNativeArray <T>(ptr, list.Count, Allocator.None);
#if ENABLE_UNITY_COLLECTIONS_CHECKS
        DisposeSentinel.Create(out var safety, out var sentinel, 0, Allocator.None);
        NativeArrayUnsafeUtility.SetAtomicSafetyHandle(ref nativeArray, safety);
        return(new NativeArrayViewHandle(handle, safety, sentinel));
#else
        return(new NativeArrayViewHandle(handle));
#endif
    }
        private static NativeArray <int> ArrayFromList(List <int> list, Allocator allocator)
        {
            if (list == null || list.Count == 0)
            {
                return(new NativeArray <int>());
            }

            var array = new NativeArray <int>(list.Count, allocator, NativeArrayOptions.UninitializedMemory);

            // Use explicit copy length because the internal list might be longer than Count, which causes an error
            NativeArray <int> .Copy(NoAllocHelpers.ExtractArrayFromListT(list), array, list.Count);

            return(array);
        }
Example #21
0
    public unsafe static int PointerDefaultIndexOf(List <int> list, int target)
    {
        var len = list.Count;

        fixed(int *p = NoAllocHelpers.ExtractArrayFromListT(list))
        for (int i = 0; i < len; i++)
        {
            if (p[i] == target)
            {
                return(i);
            }
        }
        return(-1);
    }
Example #22
0
        public void ExtractArrayFromListTReturnsInternalList()
        {
            var list = new List <int>(5);

            for (var i = 0; i < 5; i++)
            {
                list.Add(0);
            }

            var array = NoAllocHelpers.ExtractArrayFromListT(list);

            array[3] = 4;

            Assert.AreEqual(4, list[3]);
        }
Example #23
0
        public static unsafe void EmitSessionMetaData <T>(Guid id, int tag, List <T> data) where T : struct
        {
            if (data == null)
            {
                throw new ArgumentNullException("data");
            }

            var elementType = typeof(T);

            if (!UnsafeUtility.IsBlittable(typeof(T)))
            {
                throw new ArgumentException(string.Format("{0} type must be blittable", elementType));
            }

            Internal_EmitGlobalMetaData_Array(&id, 16, tag, NoAllocHelpers.ExtractArrayFromList(data), data.Count, UnsafeUtility.SizeOf(elementType), false);
        }
Example #24
0
        public static void EmitFrameMetaData <T>(Guid id, int tag, List <T> data) where T : struct
        {
            if (data == null)
            {
                throw new ArgumentNullException("data");
            }

            var elementType = typeof(T);

            if (!UnsafeUtility.IsBlittable(typeof(T)))
            {
                throw new ArgumentException(string.Format("{0} type used in Profiler.ReportFrameStats must be blittable", elementType));
            }

            Internal_EmitFrameMetaData_Array(id.ToByteArray(), tag, NoAllocHelpers.ExtractArrayFromList(data), data.Count, UnsafeUtility.SizeOf(elementType));
        }
Example #25
0
        void TransformVerts(LayerSubMesh mesh)
        {
            var offset  = Rot4.FromAngleFlat(target);
            var offseti = offset.AsInt;

            // Rotate around a center
            if (PrintPlanePatch.plantMats.Contains(mesh.material) ||
                GraphicPrintPatch_TransformMats.graphicSingle.Contains(mesh.material))
            {
                var vertsc   = mesh.verts.Count / 5 * 4;
                var vertsArr = NoAllocHelpers.ExtractArrayFromListT(mesh.verts);

                Util.ResizeIfNeeded(ref tempVerts, vertsc);

                for (int i = 0; i < vertsc; i += 4)
                {
                    // The mesh data lists are only used during mesh building and are otherwise unused.
                    // In between mesh rebuilding, Carousel reuses the lists to recalculate the meshes
                    // but also appends additional information to the end of the vertex list
                    var center = vertsArr[vertsc + i / 4];

                    RotateVerts(tempVerts, vertsArr, i, center, offset);
                }

                mesh.mesh.SetVertices(tempVerts, vertsc);
            }

            // Exchange vertices
            // This doesn't change the set of their values but changes their order
            if (GraphicPrintPatch_TransformMats.exchangeMats.ContainsKey(mesh.material) ||
                LinkedPrintPatch.linkedMaterials.Contains(mesh.material))
            {
                var vertsc   = mesh.verts.Count;
                var vertsArr = NoAllocHelpers.ExtractArrayFromListT(mesh.verts);

                Util.ResizeIfNeeded(ref tempVerts, vertsc);

                for (int i = 0; i < vertsc; i += 4)
                {
                    ExchangeVerts(tempVerts, vertsArr, i, offseti);
                }

                mesh.mesh.SetVertices(tempVerts, vertsc);
            }
        }
Example #26
0
    public unsafe static int PointerDefaultIndexOfThrows(List <int> list, int target)
    {
        var len = list.Count;

        fixed(int *p = NoAllocHelpers.ExtractArrayFromListT(list))
        for (int i = 0; i < len; i++)
        {
            if (i < 0 || i >= len)
            {
                throw new ArgumentOutOfRangeException();
            }
            if (p[i] == target)
            {
                return(i);
            }
        }

        return(-1);
    }
Example #27
0
    public static unsafe void CopyIntegers(NativeList <int> src, List <int> dst)
    {
        if (dst.Capacity < src.Length)
        {
            dst.Capacity = src.Length;
        }

        var array = NoAllocHelpers.ExtractArrayFromListT(dst);

        fixed(int *arrayPtr = array)
        {
            var dstSlice = NativeSliceUnsafeUtility.ConvertExistingDataToNativeSlice <int>(arrayPtr, sizeof(int), src.Length);

#if ENABLE_UNITY_COLLECTIONS_CHECKS
            NativeSliceUnsafeUtility.SetAtomicSafetyHandle(ref dstSlice, AtomicSafetyHandle.GetTempUnsafePtrSliceHandle());
#endif
            dstSlice.CopyFrom((NativeArray <int>)src);
        }

        NoAllocHelpers.ResizeList(dst, src.Length);
    }
Example #28
0
    // https://forum.unity.com/threads/nativearray-and-mesh.522951/
    // avoid having to call NativeList.ToArray() when assigning a Mesh attribute which results in garbage
    //  There seems some GCAllocs still happen, but CPU spikes seem to be improved alot
    // NOTE: that the buffer resizes up to the size of native, and does not shrink to avoid allocations -> Potential Memory Hog
    // TODO: This HACK will go away with the official support of NativeArrays / NativeLists? in https://forum.unity.com/threads/feedback-wanted-mesh-scripting-api-improvements.684670/
    static unsafe void assignNativeListToBuffer <TNative, T> (NativeList <TNative> native, ref List <T> buffer) where TNative : struct where T : struct
    {
        //Debug.Assert(buffer.Count == 0);
        Debug.Assert(UnsafeUtility.SizeOf <TNative>() == UnsafeUtility.SizeOf <T>());

        if (native.Length > 0)
        {
            if (buffer.Capacity < native.Length)
            {
                buffer.Capacity = native.Length;
            }

            var arr  = NoAllocHelpers.ExtractArrayFromListT(buffer);
            var size = UnsafeUtility.SizeOf <T>();

            var ptr = (byte *)UnsafeUtility.AddressOf(ref arr[0]);

            UnsafeUtility.MemCpy(ptr, native.GetUnsafePtr(), native.Length * (long)size);
        }
        NoAllocHelpers.ResizeList(buffer, native.Length);
    }
    static unsafe void NativeAddRange <T>(this List <T> list, NativeSlice <T> nativeSlice) where T : struct
    {
        var index     = list.Count;
        var newLength = index + nativeSlice.Length;

        // Resize our list if we require
        if (list.Capacity < newLength)
        {
            list.Capacity = newLength;
        }

        var items = NoAllocHelpers.ExtractArrayFromListT(list);
        var size  = UnsafeUtility.SizeOf <T>();

        // Get the pointer to the end of the list
        var bufferStart = (IntPtr)UnsafeUtility.AddressOf(ref items[0]);
        var buffer      = (byte *)(bufferStart + (size * index));

        UnsafeUtility.MemCpy(buffer, nativeSlice.GetUnsafePtr(), nativeSlice.Length * (long)size);

        NoAllocHelpers.ResizeList(list, newLength);
    }
        private static unsafe void NativeInject <T>(this List <T> list, int startIndex, void *src, int srcIndex,
                                                    int length)
            where T : struct
        {
            var newLength = startIndex + length;

            if (list.Capacity < newLength)
            {
                list.Capacity = newLength;
            }

            var size = UnsafeUtility.SizeOf <T>();
            var dst  = list.GetUnsafePtr(out var gcHandle);

            UnsafeUtility.MemCpy(
                (void *)((IntPtr)dst + startIndex * size),
                (void *)((IntPtr)src + srcIndex * size),
                length * size
                );

            UnsafeUtility.ReleaseGCObject(gcHandle);
            NoAllocHelpers.ResizeList(list, newLength);
        }