├── LICENSE.md ├── LICENSE.md.meta ├── README.md ├── README.md.meta ├── Runtime.meta ├── Runtime ├── SharedArray.cs ├── SharedArray.cs.meta ├── com.stella3d.sharedarray.asmdef └── com.stella3d.sharedarray.asmdef.meta ├── Tests.meta ├── Tests ├── Editor.meta └── Editor │ ├── AssertSafety.cs │ ├── AssertSafety.cs.meta │ ├── SharedArrayTests.cs │ ├── SharedArrayTests.cs.meta │ ├── com.stella3d.sharedarray.EditorTests.asmdef │ └── com.stella3d.sharedarray.EditorTests.asmdef.meta ├── package.json └── package.json.meta /LICENSE.md: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020 Stella Cannefax 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /LICENSE.md.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 16142f06d144e4246b1fcabccd50761a 3 | TextScriptImporter: 4 | externalObjects: {} 5 | userData: 6 | assetBundleName: 7 | assetBundleVariant: 8 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # SharedArray 2 | A `SharedArray` is a segment of memory that is represented both as a normal C# array `T[]`, and a Unity [`NativeArray`](https://docs.unity3d.com/ScriptReference/Unity.Collections.NativeArray_1.html). 3 | 4 | It's designed to reduce the overhead of communicating between C# job data in `NativeArray` and APIs that use a normal array of structs, such as [Graphics.DrawMeshInstanced()](https://docs.unity3d.com/ScriptReference/Graphics.DrawMeshInstanced.html), by eliminating the need to copy data. 5 | 6 | ## Installation 7 | 8 | Minimum Unity version is 2018.4. 9 | 10 | To install, grab the latest .unitypackage [from the Releases Tab](https://github.com/stella3d/SharedArray/releases) and import it to your project. 11 | 12 | ## Usage 13 | 14 | 15 | ```csharp 16 | // SharedArray implicitly converts to both managed and native array 17 | SharedArray shared = new SharedArray(8); 18 | NativeArray asNative = shared; 19 | Vector4[] asManaged = shared; 20 | ``` 21 | 22 | Please see the [demo project](https://github.com/stella3d/SharedArray-Demo) for a more detailed usage example. 23 | 24 | 25 | ## Safety System 26 | 27 | Unity's job system has a [safety system for reading & writing data](https://docs.unity3d.com/Manual/JobSystemSafetySystem.html) (in the Editor only). This catches cases where a data race would occur and warns you about it. 28 | 29 | SharedArray _works with this safety system_, so when you access the data on the main thread, the system knows whether it is safe to read or write, just like using a `NativeArray` allocated the normal way. 30 | 31 | Here's all of the operations that include a check of the safety system. 32 | 33 | ```csharp 34 | SharedArray sharedArray; // created elsewhere 35 | 36 | // These 4 operations will check that no jobs are using the data, in any way 37 | T[] asNormalArray = sharedArray; 38 | sharedArray.Clear(); 39 | sharedArray.Resize(32); 40 | sharedArray.Dispose(); 41 | 42 | // Enumerating in either of these ways will check if any jobs are writing to the data, but allow other readers 43 | foreach(var element in sharedArray) { } 44 | 45 | var enumerator = sharedArray.GetEnumerator(); 46 | ``` 47 | 48 | The safest way to use SharedArray is: 49 | 1) Manipulate data in a C# job, using the `NativeArray` representation 50 | 2) Convert to a managed array `T[]` only right before you use it on the main thread. 51 | 52 | This is important if you want the safety system to work - if you pass around a reference to the managed representation, you won't get the safety system checks. 53 | 54 | You can see this pattern demonstrated in the [demo project](https://github.com/stella3d/SharedArray-Demo). 55 | 56 | ## Aliasing 57 | 58 | It's possible to have the `NativeArray` representation of the data be of a different type than the source managed array. 59 | 60 | To do so, create the `SharedArray` with 2 types instead of 1 : 61 | 62 | ```csharp 63 | Vector4[] source = new Vector4[64]; 64 | SharedArray shared = new SharedArray(source); 65 | NativeArray native = shared; 66 | Vector4[] asManaged = shared; 67 | ``` 68 | 69 | The only safety check that aliasing makes is that the types are both `unmanaged` and the same size. 70 | 71 | #### Why Alias Types ? 72 | 73 | Aliasing was made to eliminate the overhead of converting between analogous types in `Unity.Mathematics` and `UnityEngine` (such as `float4` <-> `Vector4` or `float4x4` <-> `Matrix4x4`). 74 | 75 | These `Unity.Mathematics` types have optimizations specific to the [Burst compiler](https://docs.unity3d.com/Packages/com.unity.burst@0.2/manual/index.html), and replace the existing Unity math structs and methods. 76 | We want to get the compiler-specific performance advantage of using those new types, without the overhead of converting back from `Unity.Mathematics` types. 77 | 78 | For types that are laid out the same in memory, we can just treat one like the other. Since we do this for the whole array, there is never any conversion between types happening, and thus no overhead - it's just a different "view" on the same memory. 79 | 80 | -------------------------------------------------------------------------------- /README.md.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 97a41ba235bec9846b40af70f0dd28e8 3 | TextScriptImporter: 4 | externalObjects: {} 5 | userData: 6 | assetBundleName: 7 | assetBundleVariant: 8 | -------------------------------------------------------------------------------- /Runtime.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 6df5894e34cd65648b129c813d66cb65 3 | folderAsset: yes 4 | DefaultImporter: 5 | externalObjects: {} 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /Runtime/SharedArray.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections; 3 | using System.Collections.Generic; 4 | using System.Runtime.CompilerServices; 5 | using System.Runtime.InteropServices; 6 | using Unity.Collections; 7 | using Unity.Collections.LowLevel.Unsafe; 8 | 9 | namespace Stella3D 10 | { 11 | /// 12 | /// An array usable as both a NativeArray and managed array 13 | /// 14 | /// The type of the array element 15 | public class SharedArray : SharedArray where T : unmanaged 16 | { 17 | public SharedArray(T[] managed) { Initialize(managed); } 18 | public SharedArray(int size) { Initialize(new T[size]); } 19 | } 20 | 21 | /// 22 | /// An array usable as both a NativeArray and managed array 23 | /// 24 | /// The element type in the managed representation 25 | /// 26 | /// The element type in the NativeArray representation. Must be the same size as T 27 | /// 28 | public class SharedArray : IDisposable, IEnumerable 29 | where T : unmanaged 30 | where TNative : unmanaged 31 | { 32 | protected GCHandle m_GcHandle; 33 | #if UNITY_EDITOR 34 | protected AtomicSafetyHandle m_SafetyHandle; 35 | #endif 36 | protected T[] m_Managed; 37 | protected NativeArray m_Native; 38 | 39 | public int Length => m_Managed.Length; 40 | 41 | public SharedArray(T[] managed) 42 | { 43 | ThrowIfTypesNotEqualSize(); 44 | Initialize(managed); 45 | } 46 | 47 | public SharedArray(int size) 48 | { 49 | ThrowIfTypesNotEqualSize(); 50 | Initialize(new T[size]); 51 | } 52 | 53 | protected SharedArray() { } 54 | 55 | // implicit conversion means you can pass a SharedArray where either NativeArray or [] is expected 56 | public static implicit operator NativeArray(SharedArray self) => self.m_Native; 57 | 58 | public static implicit operator T[](SharedArray self) 59 | { 60 | #if UNITY_EDITOR && !DISABLE_SHAREDARRAY_SAFETY 61 | AtomicSafetyHandle.CheckWriteAndThrow(self.m_SafetyHandle); 62 | #endif 63 | return self.m_Managed; 64 | } 65 | 66 | protected void Initialize(T[] managed) 67 | { 68 | m_Managed = managed; 69 | Initialize(); 70 | } 71 | 72 | void Initialize() 73 | { 74 | // Unity's default garbage collector doesn't move objects around, so pinning the array in memory 75 | // should not even be necessary. Better to be safe, though 76 | m_GcHandle = GCHandle.Alloc(m_Managed, GCHandleType.Pinned); 77 | CreateNativeAlias(); 78 | } 79 | 80 | protected unsafe void CreateNativeAlias() 81 | { 82 | // this is the trick to making a NativeArray view of a managed array (or any pointer) 83 | fixed (void* ptr = m_Managed) 84 | { 85 | m_Native = NativeArrayUnsafeUtility.ConvertExistingDataToNativeArray 86 | (ptr, m_Managed.Length, Allocator.None); 87 | } 88 | 89 | #if UNITY_EDITOR 90 | m_SafetyHandle = AtomicSafetyHandle.Create(); 91 | NativeArrayUnsafeUtility.SetAtomicSafetyHandle(ref m_Native, m_SafetyHandle); 92 | #endif 93 | } 94 | 95 | // allows taking pointer of SharedArray in 'fixed' statements 96 | public ref T GetPinnableReference() => ref m_Managed[0]; 97 | 98 | public void Resize(int newSize) 99 | { 100 | if (newSize == m_Managed.Length) 101 | return; 102 | 103 | #if UNITY_EDITOR 104 | AtomicSafetyHandle.CheckDeallocateAndThrow(m_SafetyHandle); 105 | AtomicSafetyHandle.Release(m_SafetyHandle); 106 | #endif 107 | if (m_GcHandle.IsAllocated) m_GcHandle.Free(); 108 | 109 | Array.Resize(ref m_Managed, newSize); 110 | Initialize(); 111 | } 112 | 113 | public void Clear() 114 | { 115 | #if UNITY_EDITOR 116 | AtomicSafetyHandle.CheckWriteAndThrow(m_SafetyHandle); 117 | #endif 118 | Array.Clear(m_Managed, 0, m_Managed.Length); 119 | } 120 | 121 | public IEnumerator GetEnumerator() 122 | { 123 | #if UNITY_EDITOR 124 | // Unlike the other safety checks, only check if it's safe to read. 125 | // Enumerating an array of structs gives the user copies of each element, since structs pass by value. 126 | // This means that the source memory can't be modified while enumerating. 127 | AtomicSafetyHandle.CheckReadAndThrow(m_SafetyHandle); 128 | #endif 129 | return ((IEnumerable) m_Managed).GetEnumerator(); 130 | } 131 | 132 | IEnumerator IEnumerable.GetEnumerator() => GetEnumerator(); 133 | 134 | public void Dispose() 135 | { 136 | if (m_Managed == null) 137 | return; 138 | #if UNITY_EDITOR 139 | AtomicSafetyHandle.CheckDeallocateAndThrow(m_SafetyHandle); 140 | AtomicSafetyHandle.Release(m_SafetyHandle); 141 | #endif 142 | m_Managed = null; 143 | if (m_GcHandle.IsAllocated) m_GcHandle.Free(); 144 | } 145 | 146 | ~SharedArray() { Dispose(); } 147 | 148 | static unsafe void ThrowIfTypesNotEqualSize() 149 | { 150 | if (sizeof(T) != sizeof(TNative)) 151 | { 152 | throw new InvalidOperationException( 153 | $"size of native alias type '{typeof(TNative).FullName}' ({sizeof(TNative)} bytes) " + 154 | $"must be equal to size of source type '{typeof(T).FullName}' ({sizeof(T)} bytes)"); 155 | } 156 | } 157 | } 158 | } 159 | -------------------------------------------------------------------------------- /Runtime/SharedArray.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 1ff788b75cbf443682900debc3332019 3 | timeCreated: 1583726178 -------------------------------------------------------------------------------- /Runtime/com.stella3d.sharedarray.asmdef: -------------------------------------------------------------------------------- 1 | { 2 | "name": "com.stella3d.sharedarray", 3 | "references": [], 4 | "includePlatforms": [ 5 | "Android", 6 | "Editor", 7 | "iOS", 8 | "LinuxStandalone64", 9 | "Lumin", 10 | "macOSStandalone", 11 | "PS4", 12 | "Switch", 13 | "tvOS", 14 | "WindowsStandalone32", 15 | "WindowsStandalone64", 16 | "XboxOne" 17 | ], 18 | "excludePlatforms": [], 19 | "allowUnsafeCode": true, 20 | "overrideReferences": false, 21 | "precompiledReferences": [], 22 | "autoReferenced": true, 23 | "defineConstraints": [], 24 | "versionDefines": [], 25 | "noEngineReferences": false 26 | } 27 | -------------------------------------------------------------------------------- /Runtime/com.stella3d.sharedarray.asmdef.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 4c1a3d26ba481b74fb4a69c0e5c9f2c5 3 | AssemblyDefinitionImporter: 4 | externalObjects: {} 5 | userData: 6 | assetBundleName: 7 | assetBundleVariant: 8 | -------------------------------------------------------------------------------- /Tests.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: c04345acfbf52954e96207b959573847 3 | folderAsset: yes 4 | DefaultImporter: 5 | externalObjects: {} 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /Tests/Editor.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: b0cc066170e548a42928927af8a2be00 3 | folderAsset: yes 4 | DefaultImporter: 5 | externalObjects: {} 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /Tests/Editor/AssertSafety.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using NUnit.Framework; 3 | using Unity.Collections; 4 | using Unity.Jobs; 5 | 6 | namespace Stella3D.Tests 7 | { 8 | public static class AssertSafety 9 | { 10 | public static void ThrowsIfAnyScheduledWriters(SharedArray shared, TestDelegate safetyCheckedAction) where T : unmanaged 11 | { 12 | AssertCheck(new WriteTestJob(shared), safetyCheckedAction); 13 | } 14 | 15 | public static void ThrowsIfAnyJobsAreUsingData(SharedArray shared, TestDelegate safetyCheckedAction) where T : unmanaged 16 | { 17 | AssertCheck(new ReadOnlyTestJob(shared), safetyCheckedAction); 18 | AssertCheck(new WriteTestJob(shared), safetyCheckedAction); 19 | } 20 | 21 | // for methods like .Dispose() where calling them more than once has undesirable side effects 22 | public static void ThrowsIfAnyDataUsers_SingleCall(SharedArray shared, TestDelegate safetyCheckedAction) 23 | where T : unmanaged 24 | { 25 | SingleAssertCheck(new WriteTestJob(shared), safetyCheckedAction); 26 | } 27 | 28 | public static void DoesNotThrowIfAnyScheduledReaders(SharedArray shared, TestDelegate safetyCheckedAction) where T : unmanaged 29 | { 30 | AssertCheck(new ReadOnlyTestJob(shared), safetyCheckedAction, false); 31 | } 32 | 33 | static void SingleAssertCheck(TJob job, TestDelegate safetyCheckedAction, bool shouldThrow = true) 34 | where TJob : struct, IJob 35 | { 36 | var jobHandle = job.Schedule(); 37 | 38 | if(shouldThrow) 39 | Assert.Throws(safetyCheckedAction); 40 | else 41 | Assert.DoesNotThrow(safetyCheckedAction); 42 | 43 | jobHandle.Complete(); 44 | } 45 | 46 | static void AssertCheck(TJob job, TestDelegate safetyCheckedAction, bool shouldThrow = true) 47 | where TJob : struct, IJob 48 | { 49 | Assert.DoesNotThrow(safetyCheckedAction); 50 | var jobHandle = job.Schedule(); 51 | 52 | if(shouldThrow) 53 | Assert.Throws(safetyCheckedAction); 54 | else 55 | Assert.DoesNotThrow(safetyCheckedAction); 56 | 57 | jobHandle.Complete(); 58 | Assert.DoesNotThrow(safetyCheckedAction); 59 | } 60 | 61 | public struct WriteTestJob : IJob where T: unmanaged 62 | { 63 | public NativeArray Values; 64 | public WriteTestJob(NativeArray values) { Values = values; } 65 | public void Execute() { } 66 | } 67 | 68 | public struct ReadOnlyTestJob : IJob where T: unmanaged 69 | { 70 | [ReadOnly] public NativeArray Values; 71 | public ReadOnlyTestJob(NativeArray values) { Values = values; } 72 | public void Execute() { } 73 | } 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /Tests/Editor/AssertSafety.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: e155252f107a47fbb0ba5e5374528e40 3 | timeCreated: 1584849796 -------------------------------------------------------------------------------- /Tests/Editor/SharedArrayTests.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Linq; 3 | using NUnit.Framework; 4 | using Unity.Collections; 5 | using Unity.Collections.LowLevel.Unsafe; 6 | using UnityEngine; 7 | 8 | namespace Stella3D.Tests 9 | { 10 | public class SharedArrayTests 11 | { 12 | [Test] 13 | public void BothRepresentations_ReferToSameData() 14 | { 15 | var shared = new SharedArray(8); 16 | 17 | float[] asManaged = shared; 18 | for (int i = 0; i < asManaged.Length; i++) 19 | asManaged[i] = i; 20 | 21 | NativeArray asNative = shared; 22 | 23 | // does the native representation reflect changes made in the managed one ? 24 | for (int i = 0; i < asNative.Length; i++) 25 | Assert.IsTrue(asManaged[i].Equals(asNative[i])); 26 | 27 | for (int i = 0; i < asNative.Length; i++) 28 | asNative[i] = i * 2f; 29 | 30 | // does the managed representation reflect changes made in the native one ? 31 | for (int i = 0; i < asManaged.Length; i++) 32 | { 33 | var nativeElement = asNative[i]; 34 | Assert.IsTrue((i * 2f).Equals(nativeElement)); 35 | Assert.IsTrue(asManaged[i].Equals(nativeElement)); 36 | } 37 | } 38 | 39 | [Test] 40 | public unsafe void ManagedAndNativeHaveSamePointers() 41 | { 42 | var shared = new SharedArray(4); 43 | fixed (void* managedPtr = (Vector4[]) shared) 44 | { 45 | var nativePtr = ((NativeArray) shared).GetUnsafeReadOnlyPtr(); 46 | Assert.IsTrue(managedPtr == nativePtr); 47 | } 48 | } 49 | 50 | [Test] 51 | public unsafe void GetPinnableReference_ReturnsCorrectPointer() 52 | { 53 | var shared = new SharedArray(4); 54 | fixed (Vector4* arrayPtr = (Vector4[]) shared) 55 | fixed (Vector4* pinRefPtr = shared) 56 | Assert.IsTrue(arrayPtr == pinRefPtr); 57 | } 58 | 59 | [Test] 60 | public void Constructor_ThrowsIf_TypesAreNotEqualSize() 61 | { 62 | try 63 | { 64 | var shared = new SharedArray(8); 65 | throw new Exception("Shouldn't get here, the above constructor should throw!"); 66 | } 67 | catch (InvalidOperationException e) 68 | { 69 | Assert.NotNull(e.Message); 70 | Assert.IsTrue(e.Message.Contains("size")); // is the exception message the intended one ? 71 | } 72 | } 73 | 74 | [Test] 75 | public void Resize() 76 | { 77 | const int initialLength = 8; 78 | var shared = new SharedArray(initialLength); 79 | 80 | Vector3[] asManaged = shared; 81 | for (int i = 0; i < asManaged.Length; i++) 82 | asManaged[i] = Vector3.one * i; 83 | 84 | Assert.AreEqual(initialLength, shared.Length); 85 | Assert.AreEqual(initialLength, ((NativeArray)shared).Length); 86 | 87 | const int resizedLength = 16; 88 | shared.Resize(resizedLength); 89 | 90 | Vector3[] managedAfterResize = shared; 91 | // did data from before resize get preserved ? 92 | for (int i = 0; i < initialLength; i++) 93 | Assert.AreEqual(Vector3.one * i, managedAfterResize[i]); 94 | 95 | Assert.AreEqual(resizedLength, managedAfterResize.Length); 96 | Assert.AreEqual(resizedLength, ((NativeArray)shared).Length); 97 | } 98 | 99 | [Test] 100 | public void Resize_ThrowsIf_AnyJobsAreUsingData() 101 | { 102 | var shared = new SharedArray(4); 103 | AssertSafety.ThrowsIfAnyDataUsers_SingleCall(shared, () => shared.Resize(8)); 104 | } 105 | 106 | [Test] 107 | public void Clear_BasicSuccess() 108 | { 109 | var managed = new[] { 10, 8, 30, 20 }; 110 | var shared = new SharedArray(managed); 111 | shared.Clear(); 112 | 113 | for (int i = 0; i < managed.Length; i++) 114 | Assert.Zero(managed[i]); 115 | } 116 | 117 | [Test] 118 | public void Clear_ThrowsIf_AnyJobsAreUsingData() 119 | { 120 | var shared = new SharedArray(new[] { 6, 9, 4, 2 }); 121 | AssertSafety.ThrowsIfAnyJobsAreUsingData(shared, shared.Clear); 122 | } 123 | 124 | [Test] 125 | public void GetEnumerator_BasicSuccess() 126 | { 127 | var shared = new SharedArray(4); 128 | var asManaged = (float[]) shared; 129 | for (int i = 0; i < asManaged.Length; i++) 130 | asManaged[i] = i; 131 | 132 | // try enumerating, which is just a wrapper around normal array enumeration 133 | foreach (var floatEntry in shared) 134 | Assert.IsTrue(asManaged.Contains(floatEntry)); 135 | } 136 | 137 | [Test] 138 | public void GetEnumerator_ThrowsIf_AnyJobsAreWriting() 139 | { 140 | var shared = new SharedArray(4); 141 | TestDelegate enumerateAction = () => { foreach (var e in shared) { } }; 142 | 143 | AssertSafety.ThrowsIfAnyScheduledWriters(shared, enumerateAction); 144 | // it's fine if other things are reading while we enumerate, because enumerating returns copies of structs, 145 | // so the source data won't be changed by the enumerator 146 | AssertSafety.DoesNotThrowIfAnyScheduledReaders(shared, enumerateAction); 147 | } 148 | 149 | [Test] 150 | public void ImplicitCastToManagedArray_ThrowsIf_AnyJobsAreUsingData() 151 | { 152 | var shared = new SharedArray(4); 153 | AssertSafety.ThrowsIfAnyJobsAreUsingData(shared, () => { double[] asManaged = shared; }); 154 | } 155 | 156 | [Test] 157 | public void Dispose_ThrowsIf_AnyJobsAreUsingData() 158 | { 159 | var shared = new SharedArray(new[] { 3, 0, 3, 0 }); 160 | AssertSafety.ThrowsIfAnyDataUsers_SingleCall(shared, shared.Dispose); 161 | } 162 | } 163 | } 164 | -------------------------------------------------------------------------------- /Tests/Editor/SharedArrayTests.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 0cc3b2fdef18ad1448cc6408434237a3 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Tests/Editor/com.stella3d.sharedarray.EditorTests.asmdef: -------------------------------------------------------------------------------- 1 | { 2 | "name": "com.stella3d.sharedarray.EditorTests", 3 | "references": [ 4 | "com.stella3d.sharedarray" 5 | ], 6 | "optionalUnityReferences": [ 7 | "TestAssemblies" 8 | ], 9 | "includePlatforms": [ 10 | "Editor" 11 | ], 12 | "excludePlatforms": [], 13 | "allowUnsafeCode": true, 14 | "overrideReferences": true, 15 | "precompiledReferences": [], 16 | "autoReferenced": false, 17 | "defineConstraints": [] 18 | } -------------------------------------------------------------------------------- /Tests/Editor/com.stella3d.sharedarray.EditorTests.asmdef.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 282a48b7c94a11f48a5262c4855760ef 3 | AssemblyDefinitionImporter: 4 | externalObjects: {} 5 | userData: 6 | assetBundleName: 7 | assetBundleVariant: 8 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "com.stella3d.sharedarray", 3 | "version": "0.1.0", 4 | "displayName": "Shared Array", 5 | "description": "Zero-copy sharing between managed and native arrays", 6 | "unity": "2018.4", 7 | "unityRelease": "17f1", 8 | "dependencies": {}, 9 | "keywords": [ 10 | "Shared", 11 | "NativeArray", 12 | "Jobs" 13 | ], 14 | "author": { 15 | "name": "Stella Cannefax", 16 | "email": "stella@unity3d.com", 17 | "url": "https://github.com/stella3d/SharedArray" 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /package.json.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 298441a54207b3a4a909c004c071b1a2 3 | TextScriptImporter: 4 | externalObjects: {} 5 | userData: 6 | assetBundleName: 7 | assetBundleVariant: 8 | --------------------------------------------------------------------------------