123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545 |
- using System;
- using NUnit.Framework;
- using Unity.Burst;
- using Unity.Collections;
- using Unity.Collections.LowLevel.Unsafe;
- using Unity.Collections.Tests;
- using Unity.Jobs;
- using UnityEngine;
- using Assert = FastAssert;
-
- internal class NativeStreamTests : CollectionsTestFixture
- {
- [BurstCompile(CompileSynchronously = true)]
- struct WriteInts : IJobParallelFor
- {
- public NativeStream.Writer Writer;
-
- public void Execute(int index)
- {
- Writer.BeginForEachIndex(index);
- for (int i = 0; i != index; i++)
- Writer.Write(i);
- Writer.EndForEachIndex();
- }
- }
-
- struct ReadInts : IJobParallelFor
- {
- public NativeStream.Reader Reader;
-
- public void Execute(int index)
- {
- int count = Reader.BeginForEachIndex(index);
- Assert.AreEqual(count, index);
-
- for (int i = 0; i != index; i++)
- {
- Assert.AreEqual(index - i, Reader.RemainingItemCount);
- var peekedValue = Reader.Peek<int>();
- var value = Reader.Read<int>();
- Assert.AreEqual(i, value);
- Assert.AreEqual(i, peekedValue);
- }
-
- Reader.EndForEachIndex();
- }
- }
-
- [Test]
- public void NativeStream_PopulateInts([Values(1, 100, 200)] int count, [Values(1, 3, 10)] int batchSize)
- {
- var stream = new NativeStream(count, CommonRwdAllocator.Handle);
- var fillInts = new WriteInts {Writer = stream.AsWriter()};
- var jobHandle = fillInts.Schedule(count, batchSize);
-
- var compareInts = new ReadInts {Reader = stream.AsReader()};
- var res0 = compareInts.Schedule(count, batchSize, jobHandle);
- var res1 = compareInts.Schedule(count, batchSize, jobHandle);
-
- res0.Complete();
- res1.Complete();
-
- stream.Dispose();
- }
-
- static void ExpectedCount(ref NativeStream container, int expected)
- {
- Assert.AreEqual(expected == 0, container.IsEmpty());
- Assert.AreEqual(expected, container.Count());
- }
-
- [Test]
- public void NativeStream_CreateAndDestroy([Values(1, 100, 200)] int count)
- {
- var stream = new NativeStream(count, Allocator.Temp);
-
- Assert.IsTrue(stream.IsCreated);
- Assert.IsTrue(stream.ForEachCount == count);
- ExpectedCount(ref stream, 0);
-
- stream.Dispose();
- Assert.IsFalse(stream.IsCreated);
- }
-
- [Test]
- public void NativeStream_ItemCount([Values(1, 100, 200)] int count, [Values(1, 3, 10)] int batchSize)
- {
- var stream = new NativeStream(count, CommonRwdAllocator.Handle);
- var fillInts = new WriteInts {Writer = stream.AsWriter()};
- fillInts.Schedule(count, batchSize).Complete();
-
- ExpectedCount(ref stream, count * (count - 1) / 2);
-
- stream.Dispose();
- }
-
- [Test]
- public void NativeStream_ToArray([Values(1, 100, 200)] int count, [Values(1, 3, 10)] int batchSize)
- {
- var stream = new NativeStream(count, CommonRwdAllocator.Handle);
- var fillInts = new WriteInts {Writer = stream.AsWriter()};
- fillInts.Schedule(count, batchSize).Complete();
- ExpectedCount(ref stream, count * (count - 1) / 2);
-
- var array = stream.ToNativeArray<int>(Allocator.Temp);
- int itemIndex = 0;
-
- for (int i = 0; i != count; ++i)
- {
- for (int j = 0; j < i; ++j)
- {
- Assert.AreEqual(j, array[itemIndex]);
- itemIndex++;
- }
- }
-
- array.Dispose();
- stream.Dispose();
- }
-
- [Test]
- public void NativeStream_DisposeJob()
- {
- var stream = new NativeStream(100, CommonRwdAllocator.Handle);
- Assert.IsTrue(stream.IsCreated);
-
- var fillInts = new WriteInts {Writer = stream.AsWriter()};
- var writerJob = fillInts.Schedule(100, 16);
-
- var disposeJob = stream.Dispose(writerJob);
- Assert.IsFalse(stream.IsCreated);
-
- disposeJob.Complete();
- }
-
- #if ENABLE_UNITY_COLLECTIONS_CHECKS
- [Test]
- public void NativeStream_ParallelWriteThrows()
- {
- var stream = new NativeStream(100, CommonRwdAllocator.Handle);
- var fillInts = new WriteInts {Writer = stream.AsWriter()};
-
- var writerJob = fillInts.Schedule(100, 16);
- Assert.Throws<InvalidOperationException>(() => fillInts.Schedule(100, 16));
-
- writerJob.Complete();
- stream.Dispose();
- }
-
- [Test]
- public void NativeStream_ScheduleCreateThrows_NativeList()
- {
- var container = new NativeList<int>(Allocator.Persistent);
- container.Add(2);
-
- NativeStream stream;
- var jobHandle = NativeStream.ScheduleConstruct(out stream, container, default, CommonRwdAllocator.Handle);
-
- Assert.Throws<InvalidOperationException>(() => { int val = stream.ForEachCount; });
-
- jobHandle.Complete();
-
- Assert.AreEqual(1, stream.ForEachCount);
-
- stream.Dispose();
- container.Dispose();
- }
-
- [Test]
- public void NativeStream_ScheduleCreateThrows_NativeArray()
- {
- var container = new NativeArray<int>(1, Allocator.Persistent);
- container[0] = 1;
-
- NativeStream stream;
- var jobHandle = NativeStream.ScheduleConstruct(out stream, container, default, CommonRwdAllocator.Handle);
-
- Assert.Throws<InvalidOperationException>(() => { int val = stream.ForEachCount; });
-
- jobHandle.Complete();
-
- Assert.AreEqual(1, stream.ForEachCount);
-
- stream.Dispose();
- container.Dispose();
- }
-
- [Test]
- public void NativeStream_OutOfBoundsWriteThrows()
- {
- var stream = new NativeStream(1, Allocator.Temp);
- var writer = stream.AsWriter();
- Assert.Throws<ArgumentException>(() => writer.BeginForEachIndex(-1));
- Assert.Throws<ArgumentException>(() => writer.BeginForEachIndex(2));
-
- stream.Dispose();
- }
-
- [Test]
- public void NativeStream_EndForEachIndexWithoutBeginThrows()
- {
- var stream = new NativeStream(1, Allocator.Temp);
- var writer = stream.AsWriter();
- Assert.Throws<ArgumentException>(() => writer.EndForEachIndex());
-
- stream.Dispose();
- }
-
- [Test]
- public void NativeStream_WriteWithoutBeginThrows()
- {
- var stream = new NativeStream(1, Allocator.Temp);
- var writer = stream.AsWriter();
- Assert.Throws<ArgumentException>(() => writer.Write(5));
-
- stream.Dispose();
- }
-
- [Test]
- public void NativeStream_WriteAfterEndThrows()
- {
- var stream = new NativeStream(1, Allocator.Temp);
- var writer = stream.AsWriter();
- writer.BeginForEachIndex(0);
- writer.Write(2);
- Assert.AreEqual(1, writer.ForEachCount);
- writer.EndForEachIndex();
-
- Assert.AreEqual(1, writer.ForEachCount);
- Assert.Throws<ArgumentException>(() => writer.Write(5));
-
- stream.Dispose();
- }
-
- [Test]
- public void NativeStream_UnbalancedBeginThrows()
- {
- var stream = new NativeStream(2, Allocator.Temp);
- var writer = stream.AsWriter();
- writer.BeginForEachIndex(0);
- // Missing EndForEachIndex();
- Assert.Throws<ArgumentException>(() => writer.BeginForEachIndex(1));
-
- stream.Dispose();
- }
-
- static void CreateBlockStream1And2Int(out NativeStream stream)
- {
- stream = new NativeStream(2, Allocator.Temp);
-
- var writer = stream.AsWriter();
- writer.BeginForEachIndex(0);
- writer.Write(0);
- writer.EndForEachIndex();
-
- writer.BeginForEachIndex(1);
- writer.Write(1);
- writer.Write(2);
- writer.EndForEachIndex();
- }
-
- [Test]
- public void NativeStream_IncompleteReadThrows()
- {
- NativeStream stream;
- CreateBlockStream1And2Int(out stream);
-
- var reader = stream.AsReader();
-
- reader.BeginForEachIndex(0);
- reader.Read<byte>();
- Assert.Throws<ArgumentException>(() => reader.EndForEachIndex());
-
- reader.BeginForEachIndex(1);
-
- stream.Dispose();
- }
-
- [Test]
- public void NativeStream_ReadWithoutBeginThrows()
- {
- NativeStream stream;
- CreateBlockStream1And2Int(out stream);
-
- var reader = stream.AsReader();
- Assert.Throws<ArgumentException>(() => reader.Read<int>());
-
- stream.Dispose();
- }
-
- [Test]
- public void NativeStream_TooManyReadsThrows()
- {
- NativeStream stream;
- CreateBlockStream1And2Int(out stream);
-
- var reader = stream.AsReader();
-
- reader.BeginForEachIndex(0);
- reader.Read<byte>();
- Assert.Throws<ArgumentException>(() => reader.Read<byte>());
-
- stream.Dispose();
- }
-
- [Test]
- public void NativeStream_OutOfBoundsReadThrows()
- {
- NativeStream stream;
- CreateBlockStream1And2Int(out stream);
-
- var reader = stream.AsReader();
-
- reader.BeginForEachIndex(0);
- Assert.Throws<ArgumentException>(() => reader.Read<long>());
-
- stream.Dispose();
- }
-
- [Test]
- public void NativeStream_CopyWriterByValueThrows()
- {
- var stream = new NativeStream(1, Allocator.Temp);
- var writer = stream.AsWriter();
-
- writer.BeginForEachIndex(0);
-
- Assert.Throws<ArgumentException>(() =>
- {
- var writerCopy = writer;
- writerCopy.Write(5);
- });
-
- Assert.Throws<ArgumentException>(() =>
- {
- var writerCopy = writer;
- writerCopy.BeginForEachIndex(1);
- writerCopy.Write(5);
- });
-
- stream.Dispose();
- }
-
- [Test]
- public void NativeStream_WriteSameIndexTwiceThrows()
- {
- var stream = new NativeStream(1, Allocator.Temp);
- var writer = stream.AsWriter();
-
- writer.BeginForEachIndex(0);
- writer.Write(1);
- writer.EndForEachIndex();
-
- Assert.Throws<ArgumentException>(() =>
- {
- writer.BeginForEachIndex(0);
- writer.Write(2);
- });
-
- stream.Dispose();
- }
-
- static void WriteNotPassedByRef(NativeStream.Writer notPassedByRef)
- {
- notPassedByRef.Write(10);
- }
-
- static void WritePassedByRef(ref NativeStream.Writer passedByRef)
- {
- passedByRef.Write(10);
- }
-
- [Test]
- public void NativeStream_ThrowsOnIncorrectUsage()
- {
- var stream = new NativeStream(1, Allocator.Temp);
- var writer = stream.AsWriter();
-
- Assert.Throws<ArgumentException>(() => stream.AsWriter().Write(10));
-
- writer.BeginForEachIndex(0);
- Assert.Throws<ArgumentException>(() => WriteNotPassedByRef(writer));
- Assert.DoesNotThrow(() => WritePassedByRef(ref writer));
- writer.EndForEachIndex();
-
- stream.Dispose();
- }
-
- #endif
-
- [Test]
- public void NativeStream_CustomAllocatorTest()
- {
- AllocatorManager.Initialize();
- var allocatorHelper = new AllocatorHelper<CustomAllocatorTests.CountingAllocator>(AllocatorManager.Persistent);
- ref var allocator = ref allocatorHelper.Allocator;
- allocator.Initialize();
-
- using (var container = new NativeStream(1, allocator.Handle))
- {
- }
-
- Assert.IsTrue(allocator.WasUsed);
- allocator.Dispose();
- allocatorHelper.Dispose();
- AllocatorManager.Shutdown();
- }
-
- [BurstCompile]
- struct BurstedCustomAllocatorJob : IJob
- {
- [NativeDisableUnsafePtrRestriction]
- public unsafe CustomAllocatorTests.CountingAllocator* Allocator;
-
- public void Execute()
- {
- unsafe
- {
- using (var container = new NativeStream(1, Allocator->Handle))
- {
- }
- }
- }
- }
-
- [Test]
- public unsafe void NativeStream_BurstedCustomAllocatorTest()
- {
- AllocatorManager.Initialize();
- var allocatorHelper = new AllocatorHelper<CustomAllocatorTests.CountingAllocator>(AllocatorManager.Persistent);
- ref var allocator = ref allocatorHelper.Allocator;
- allocator.Initialize();
-
- var allocatorPtr = (CustomAllocatorTests.CountingAllocator*)UnsafeUtility.AddressOf<CustomAllocatorTests.CountingAllocator>(ref allocator);
- unsafe
- {
- var handle = new BurstedCustomAllocatorJob {Allocator = allocatorPtr}.Schedule();
- handle.Complete();
- }
-
- Assert.IsTrue(allocator.WasUsed);
- allocator.Dispose();
- allocatorHelper.Dispose();
- AllocatorManager.Shutdown();
- }
-
- public struct NestedContainer
- {
- public NativeList<int> data;
- }
-
- [Test]
- public void NativeStream_Nested()
- {
- var inner = new NativeList<int>(CommonRwdAllocator.Handle);
- NestedContainer nestedStruct = new NestedContainer { data = inner };
-
- var containerNestedStruct = new NativeStream(100, CommonRwdAllocator.Handle);
- var containerNested = new NativeStream(100, CommonRwdAllocator.Handle);
-
- var writer = containerNested.AsWriter();
- writer.BeginForEachIndex(0);
- writer.Write(inner);
- writer.EndForEachIndex();
- var writerStruct = containerNestedStruct.AsWriter();
- writerStruct.BeginForEachIndex(0);
- writerStruct.Write(nestedStruct);
- writerStruct.EndForEachIndex();
-
- containerNested.Dispose();
- containerNestedStruct.Dispose();
- inner.Dispose();
- }
-
- [Test]
- public unsafe void NativeStream_Continue_Append()
- {
- AllocatorManager.Initialize();
- var allocatorHelper = new AllocatorHelper<CustomAllocatorTests.CountingAllocator>(AllocatorManager.Persistent);
- ref var allocator = ref allocatorHelper.Allocator;
- allocator.Initialize();
-
- for (var i = 0; i < 1024; i++)
- {
- var stream = new NativeStream(2, allocator.Handle);
-
- var writer = stream.AsWriter();
- writer.BeginForEachIndex(0);
- writer.Allocate(4000);
- writer.EndForEachIndex();
-
- var writer2 = stream.AsWriter();
- writer2.BeginForEachIndex(1);
- writer2.Allocate(4000);
- writer2.Allocate(4000);
- writer2.EndForEachIndex();
-
- stream.Dispose();
-
- Assert.AreEqual(0, allocatorHelper.Allocator.Used);
- }
-
- allocator.Dispose();
- allocatorHelper.Dispose();
- AllocatorManager.Shutdown();
- }
-
- struct NestedContainerJob : IJob
- {
- public NativeStream nestedContainer;
-
- public void Execute()
- {
- var writer = nestedContainer.AsWriter();
- writer.BeginForEachIndex(0);
- writer.Write(1);
- writer.EndForEachIndex();
- }
- }
-
- [Test]
- [TestRequiresCollectionChecks]
- public void NativeStream_NestedJob_Error()
- {
- var inner = new NativeList<int>(CommonRwdAllocator.Handle);
- var container = new NativeStream(100, CommonRwdAllocator.Handle);
-
- // This should mark the NativeStream as having nested containers and therefore should not be able to be scheduled
- var writer = container.AsWriter();
- writer.BeginForEachIndex(0);
- writer.Write(inner);
- writer.EndForEachIndex();
-
- var nestedJob = new NestedContainerJob
- {
- nestedContainer = container
- };
-
- JobHandle job = default;
- Assert.Throws<System.InvalidOperationException>(() => { job = nestedJob.Schedule(); });
- job.Complete();
-
- container.Dispose();
- }
- }
|