using System; using System.Collections.Generic; using Unity.Collections; using Unity.Collections.LowLevel.Unsafe; namespace UnityEngine.XR.ARSubsystems { /// /// Utilities for copying native arrays. /// public static class NativeCopyUtility { /// /// Creates a NativeArray from a pointer by first copying /// s into the NativeArray, and then overwriting the /// data in the array with , assuming each element in /// is bytes. /// /// /// This is useful for native inter-operations with structs that might change over time. This allows /// new fields to be added to the C# struct without breaking data obtained from data calls. /// /// The type of struct to copy. /// A default version of , which will be used to first fill the array /// before copying from . /// A pointer to a contiguous block of data of size * . /// The size of one element in . /// The number of elements to copy. /// The allocator to use when creating the NativeArray. /// /// A new NativeArray populating with and . /// The caller owns the memory. /// public static unsafe NativeArray PtrToNativeArrayWithDefault( T defaultT, void* source, int sourceElementSize, int length, Allocator allocator) where T : struct { var array = CreateArrayFilledWithValue(defaultT, length, allocator); // Then overwrite with the source data, which may have a different size UnsafeUtility.MemCpyStride( destination: array.GetUnsafePtr(), destinationStride: UnsafeUtility.SizeOf(), source: source, sourceStride: sourceElementSize, elementSize: sourceElementSize, count: length); return array; } /// /// Fills with repeated copies of . /// /// The type of the NativeArray. Must be a struct. /// The array to fill. /// The value with which to fill the array. public static unsafe void FillArrayWithValue(NativeArray array, T value) where T : struct { // Early out if array is zero, or iOS will crash in MemCpyReplicate. if (array.Length == 0) return; UnsafeUtility.MemCpyReplicate( array.GetUnsafePtr(), UnsafeUtility.AddressOf(ref value), UnsafeUtility.SizeOf(), array.Length); } /// /// Creates a new array allocated with and initialized with /// copies of . /// /// The type of the NativeArray to create. Must be a struct. /// The value with which to fill the array. /// The length of the array to create. /// The allocator with which to create the NativeArray. /// A new NativeArray initialized with copies of . public static NativeArray CreateArrayFilledWithValue(T value, int length, Allocator allocator) where T : struct { var array = new NativeArray(length, allocator, NativeArrayOptions.UninitializedMemory); FillArrayWithValue(array, value); return array; } /// /// Copies the contents of into the NativeArray . /// The lengths of both collections must match. /// /// The type of the NativeArray structs that will be copied /// The IReadOnlyList that provides the data /// The NativeArray that will be written to /// Thrown when there is a mismatch between and sizes. public static void CopyFromReadOnlyList(IReadOnlyList source, NativeArray destination) where T : struct { if (source.Count != destination.Length) throw new ArgumentException( $"{nameof(source)} count {source.Count} doesn't match {nameof(destination)} length {destination.Length}!"); for (var i = 0; i < source.Count; i++) { destination[i] = source[i]; } } /// /// Copies the contents of into the NativeArray . /// The lengths of both collections must match. /// /// The type of the NativeArray structs that will be copied /// The IReadOnlyCollection that provides the data /// The NativeArray that will be written to /// Thrown when there is a mismatch between and sizes. /// Prefer IReadOnlyList over IReadOnlyCollection for copy performance where possible. /// public static void CopyFromReadOnlyCollection(IReadOnlyCollection source, NativeArray destination) where T : struct { if (source.Count != destination.Length) throw new ArgumentException( $"{nameof(source)} count {source.Count} doesn't match {nameof(destination)} length {destination.Length}!"); var index = 0; foreach (var item in source) { destination[index] = item; index++; } } } }