public unsafe bool Allocate(ulong id, int vertexCount, out int start, out Buffer <Vector3> vertices) { if (TryGetExistingMesh(id, out start, out vertices)) { return(false); } if (allocator.Allocate(id, vertexCount, out var longStart)) { start = (int)longStart; vertices = this.vertices.Slice(start, vertexCount); pendingUploads.Add(new UploadRequest { Start = start, Count = vertexCount }, Pool); return(true); } //Didn't fit. We need to resize. var copyCount = TriangleBuffer.Capacity + vertexCount; var newSize = 1 << SpanHelper.GetContainingPowerOf2(copyCount); Pool.ResizeToAtLeast(ref this.vertices, newSize, copyCount); allocator.Capacity = newSize; allocator.Allocate(id, vertexCount, out longStart); start = (int)longStart; vertices = this.vertices.Slice(start, vertexCount); //A resize forces an upload of everything, so any previous pending uploads are unnecessary. pendingUploads.Count = 0; pendingUploads.Add(new UploadRequest { Start = 0, Count = copyCount }, Pool); return(true); }
public unsafe bool Allocate(ulong id, int vertexCount, out int start, out Buffer <Vector3> vertices) { if (allocator.TryGetAllocationRegion(id, out var allocation)) { Debug.Assert(allocation.End - allocation.Start == vertexCount, "If you're trying to allocate room for a bunch of triangles and we found it already, it better match the expected size."); start = (int)allocation.Start; vertices = this.vertices.Slice(start, vertexCount); return(false); } if (allocator.Allocate(id, vertexCount, out var longStart)) { start = (int)longStart; vertices = this.vertices.Slice(start, vertexCount); pendingUploads.Add(new UploadRequest { Start = start, Count = vertexCount }, Pool.SpecializeFor <UploadRequest>()); return(true); } //Didn't fit. We need to resize. var copyCount = TriangleBuffer.Capacity + vertexCount; var newSize = SpanHelper.GetContainingPowerOf2(copyCount); Pool.Resize(ref this.vertices, newSize, copyCount); allocator.Capacity = newSize; allocator.Allocate(id, vertexCount, out longStart); start = (int)longStart; vertices = this.vertices.Slice(start, vertexCount); //A resize forces an upload of everything, so any previous pending uploads are unnecessary. pendingUploads.Count = 0; pendingUploads.Add(new UploadRequest { Start = 0, Count = copyCount }, Pool.SpecializeFor <UploadRequest>()); return(true); }
/// <summary> /// There are two files: sourceFile and targetFile. Blocks are merged, mergeFactor at the time, from source to target. When all blocks from source have /// been merged into a larger block one merge iteration is done and source and target are flipped. As long as source contain more than a single block more /// merge iterations are needed and we start over again. /// When source only contain a single block we are finished and the extra file is deleted and <seealso cref="blockFile"/> contains the result with a single sorted /// block. /// /// See <seealso cref="performSingleMerge(int, BlockReader, StoreChannel, Cancellation, ByteBuffer[], ByteBuffer)"/> for further details. /// </summary> /// <param name="mergeFactor"> See <seealso cref="performSingleMerge(int, BlockReader, StoreChannel, Cancellation, ByteBuffer[], ByteBuffer)"/>. </param> /// <param name="cancellation"> Injected so that this merge can be cancelled, if an external request to do that comes in. /// A cancelled merge will leave the same end state file/channel-wise, just not quite completed, which is fine because the merge /// was cancelled meaning that the result will not be used for anything other than deletion. </param> /// <exception cref="IOException"> If something goes wrong when reading from file. </exception> //JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in C#: //ORIGINAL LINE: public void merge(int mergeFactor, Cancellation cancellation) throws java.io.IOException public virtual void Merge(int mergeFactor, Cancellation cancellation) { _monitor.mergeStarted(_entryCount, CalculateNumberOfEntriesWrittenDuringMerges(_entryCount, _numberOfBlocksInCurrentFile, mergeFactor)); File sourceFile = _blockFile; File tempFile = new File(_blockFile.Parent, _blockFile.Name + ".b"); try { using (Allocator mergeBufferAllocator = _bufferFactory.newLocalAllocator()) { File targetFile = tempFile; // Allocate all buffers that will be used and reused for all merge iterations ByteBuffer writeBuffer = mergeBufferAllocator.Allocate(_bufferFactory.bufferSize()); ByteBuffer[] readBuffers = new ByteBuffer[mergeFactor]; for (int i = 0; i < readBuffers.Length; i++) { readBuffers[i] = mergeBufferAllocator.Allocate(_bufferFactory.bufferSize()); } while (_numberOfBlocksInCurrentFile > 1) { // Perform one complete merge iteration, merging all blocks from source into target. // After this step, target will contain fewer blocks than source, but may need another merge iteration. using (BlockReader <KEY, VALUE> reader = reader(sourceFile), StoreChannel targetChannel = _fs.open(targetFile, OpenMode.READ_WRITE)) { long blocksMergedSoFar = 0; long blocksInMergedFile = 0; while (!cancellation.Cancelled() && blocksMergedSoFar < _numberOfBlocksInCurrentFile) { blocksMergedSoFar += PerformSingleMerge(mergeFactor, reader, targetChannel, cancellation, readBuffers, writeBuffer); blocksInMergedFile++; } _numberOfBlocksInCurrentFile = blocksInMergedFile; _monitor.mergeIterationFinished(blocksMergedSoFar, blocksInMergedFile); } // Flip and restore the channels File tmpSourceFile = sourceFile; sourceFile = targetFile; targetFile = tmpSourceFile; } } } finally { if (sourceFile == _blockFile) { _fs.deleteFile(tempFile); } else { _fs.deleteFile(_blockFile); _fs.renameFile(tempFile, _blockFile); } } }
public void Third_VarianceDistributionIsEvenTest() { Person firstPerson = new Person(1, 13); Person secondPerson = new Person(2, 14); Person thirdPerson = new Person(3, 15); Person fourthPerson = new Person(4, 14); Person fifthPerson = new Person(5, 34); Person sixthPerson = new Person(6, 4); List <Person> collectors = new List <Person>() { firstPerson, secondPerson, thirdPerson, fourthPerson, fifthPerson, sixthPerson }; Allocator allocator = new Allocator(); allocator.Allocate(100, collectors); Assert.IsTrue(firstPerson.NewSticksHolded == 19); Assert.IsTrue(secondPerson.NewSticksHolded == 18); Assert.IsTrue(thirdPerson.NewSticksHolded == 17); Assert.IsTrue(fourthPerson.NewSticksHolded == 18); Assert.IsTrue(fifthPerson.NewSticksHolded == 34); Assert.IsTrue(sixthPerson.NewSticksHolded == 28); }
public void TestSplitFirst() { var engine = new Engine(); engine.LoadYaml("../../../fixtures/sink11.yaml", true); Assert.NotNull(engine.World); engine.World.Time.Restart(); var stock1 = engine.World.Map.Cells[1, 0]; var sink1 = engine.World.Map.Cells[0, 0]; var sink2 = engine.World.Map.Cells[2, 0]; Assert.AreEqual(300.0f, stock1.GetStock("coal")); Assert.AreEqual("sink", sink1.Jm2.Id); Assert.AreEqual("sink", sink2.Jm2.Id); foreach (var cell in engine.World.Map.Cells) { ((Cell)cell).StepPrepare((Time)engine.World.Time); } var allocator = Allocator.Allocate((Time)engine.World.Time, engine.World.Resources, (Map)engine.World.Map); var allocation = allocator.Allocations["coal"]; // D1 demand: Assert.AreEqual(100.0f, allocation.AllocationTable[0, 0]); Assert.AreEqual(200.0f, allocation.AllocationTable[1, 0]); engine.World.Time.Step(); Assert.AreEqual(0.0f, stock1.GetStock("coal")); Assert.AreEqual(33, Math.Round((double)sink1.Jm2.Efficiency * 100.0)); Assert.AreEqual(33, Math.Round((double)sink2.Jm2.Efficiency * 100.0)); }
//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in C#: //ORIGINAL LINE: private void writeScanUpdatesToTree(RecordingConflictDetector<KEY,VALUE> recordingConflictDetector, org.neo4j.kernel.impl.index.schema.ByteBufferFactory.Allocator allocator, int bufferSize) throws java.io.IOException, org.neo4j.kernel.api.exceptions.index.IndexEntryConflictException private void WriteScanUpdatesToTree(RecordingConflictDetector <KEY, VALUE> recordingConflictDetector, Allocator allocator, int bufferSize) { using (MergingBlockEntryReader <KEY, VALUE> allEntries = new MergingBlockEntryReader <KEY, VALUE>(layout)) { ByteBuffer singleBlockAssertionBuffer = allocator.Allocate(( int )kibiBytes(8)); foreach (ThreadLocalBlockStorage part in _allScanUpdates) { using (BlockReader <KEY, VALUE> reader = part.BlockStorage.reader()) { BlockEntryReader <KEY, VALUE> singleMergedBlock = reader.NextBlock(allocator.Allocate(bufferSize)); if (singleMergedBlock != null) { allEntries.AddSource(singleMergedBlock); // Pass in some sort of ByteBuffer here. The point is that there should be no more data to read, // if there is then it's due to a bug in the code and must be fixed. if (reader.NextBlock(singleBlockAssertionBuffer) != null) { throw new System.InvalidOperationException("Final BlockStorage had multiple blocks"); } } } } int asMuchAsPossibleToTheLeft = 1; using (Writer <KEY, VALUE> writer = tree.writer(asMuchAsPossibleToTheLeft)) { while (allEntries.Next() && !_cancellation.cancelled()) { WriteToTree(writer, recordingConflictDetector, allEntries.Key(), allEntries.Value()); _numberOfAppliedScanUpdates++; } } } }
public NativeString(char *pointer, int length, Allocator allocator) { if (pointer == null && length == 0) { this = default; return; } if (pointer == null) { throw new ArgumentException("pointer is null"); } if (length <= 0) { throw new ArgumentException("length cannot be negative or zero"); } if (Allocator.IsCached(allocator) is false) { throw new ArgumentException("Allocator is not in cache"); } char *buffer = allocator.Allocate <char>(length); Unsafe.CopyBlockUnaligned(buffer, pointer, (uint)(sizeof(char) * length)); _buffer = buffer; _length = length; _allocatorID = allocator.ID; }
public void TestSinksNearest() { var engine = new Engine(); engine.LoadYaml("../../../fixtures/sink15.yaml", true); Assert.NotNull(engine.World); engine.World.Time.Restart(); var stock1 = engine.World.Map.Cells[1, 0]; var sink1 = engine.World.Map.Cells[0, 0]; var sink2 = engine.World.Map.Cells[3, 0]; Assert.AreEqual(100.0f, stock1.GetStock("coal")); Assert.AreEqual("sink", sink1.Jm2.Id); Assert.AreEqual("sink", sink2.Jm2.Id); foreach (var cell in engine.World.Map.Cells) { ((Cell)cell).StepPrepare((Time)engine.World.Time); } var allocator = Allocator.Allocate((Time)engine.World.Time, engine.World.Resources, (Map)engine.World.Map); var allocation = allocator.Allocations["coal"]; // D1 demand: Assert.AreEqual(50.0f, allocation.AllocationTable[0, 0]); // D2 demand: Assert.AreEqual(50.0f, allocation.AllocationTable[1, 0]); }
/// <summary> /// Checks whether the buffer size for a file about to be loaded is sufficient and /// conditonally returns an address to a new buffer with adequate size. /// </summary> /// <returns>The address of a new buffer for the game to decompress a file to</returns> private static void *CheckBufferSize(int fileIndex, void *addressToDecompressTo, ONEFILE *thisPointer) { if (fileIndex >= 2) { // Get pointer and length. IntPtr onePointer = (IntPtr)thisPointer[0].InternalDataPointer - 0xC; // The start of file pointer is sometimes unused, so we use the InternalDataPointer instead and offset. int fileLength = thisPointer[0].FileLength; // Now the ONE File MemoryONEArchive memoryOneFile = MemoryONEArchive.ParseONEFromMemory(onePointer, fileLength); // Now we estimate the size of it. int actualFileIndex = fileIndex - 2; MemoryONEFile oneFile = memoryOneFile.Files[actualFileIndex]; byte[] oneFileCopy = GameProcess.ReadMemory((IntPtr)oneFile.CompressedDataPointer, oneFile.DataLength); int oneFileLength = Prs.Estimate(ref oneFileCopy); // Check if the size of allocation is sufficient. MemoryAddressDetails addressDetails = Allocator.GetAddressDetails((int)addressToDecompressTo); if (addressDetails.MemorySize < oneFileLength) { // Allocate some new data for me please addressToDecompressTo = (void *)Allocator.Allocate((int)addressToDecompressTo, oneFileLength); } } return(addressToDecompressTo); }
/// <summary> /// Initializes a new instance of the <see cref="NativeDeque{T}"/> struct. /// </summary> /// <param name="elements">The elements.</param> /// <param name="allocator">The allocator.</param> /// <exception cref="ArgumentException">If the allocator is no in cache. public NativeDeque(Span <T> elements, Allocator allocator) { if (Allocator.IsCached(allocator) is false) { throw new ArgumentException("Allocator is not in cache.", nameof(allocator)); } if (elements.IsEmpty) { this = default; } else { int length = elements.Length; _buffer = allocator.Allocate <T>(length); void *source = Unsafe.AsPointer(ref elements.GetPinnableReference()); Unsafe.CopyBlock(_buffer, source, (uint)(sizeof(T) * length)); _capacity = length; _count = length; _allocatorID = allocator.ID; _head = 0; _tail = _capacity - 1; } }
public NativeQuery <T> Take(int count) { if (_length == 0) { return(new NativeQuery <T>(GetAllocator())); } if (count == 0) { var emptyQuery = new NativeQuery <T>(GetAllocator()); Dispose(); return(emptyQuery); } if (count < 0) { Dispose(); throw new ArgumentException(count.ToString(), nameof(count)); } int length = count >= _length ? _length : count; Allocator allocator = GetAllocator() !; void * src = _buffer; void * dst = allocator.Allocate <T>(length); Unsafe.CopyBlockUnaligned(dst, src, (uint)(sizeof(T) * length)); Dispose(); return(new NativeQuery <T>(dst, length, allocator)); }
private NativeStack(ref NativeStack <T> stack) { Debug.Assert(stack.IsValid); Allocator allocator = stack.GetAllocator() !; T * buffer = allocator.Allocate <T>(stack._capacity); Unsafe.CopyBlockUnaligned(buffer, stack._buffer, (uint)(sizeof(T) * stack._capacity)); _buffer = buffer; _capacity = stack._capacity; _count = stack._count; _allocatorID = stack._allocatorID; }
/// <summary> /// Gets a <see cref="NativeQuery{T}"/> with the default value if this query is empty, otherwise get the same query. /// </summary> /// <typeparam name="T"></typeparam> /// <typeparam name="TResult">The type of the result.</typeparam> /// <param name="query">The query.</param> /// <param name="defaultValue">The default value.</param> /// <returns>A query with the default value if empty, otherwise the same query will be returned.</returns> public static NativeQuery <T> DefaultIfEmpty <T>(this NativeQuery <T> query, T defaultValue) where T : unmanaged { if (query.IsEmpty) { unsafe { Allocator allocator = query.GetAllocator() ?? Allocator.Default; T * value = allocator.Allocate <T>(1); * value = defaultValue; return(new NativeQuery <T>(value, 1, allocator)); } } return(query); }
/// <summary> /// Initializes a new instance of the <see cref="NativeArray{T}" /> struct. /// </summary> /// <param name="capacity">The capacity of the array.</param> /// <param name="allocator">The allocator used for this array.</param> public NativeArray(int capacity, Allocator allocator) { if (capacity <= 0) { throw new ArgumentException($"capacity must be greater than 0: {capacity}"); } if (allocator.ID <= 0) { throw new ArgumentException("Allocator is not in cache.", "allocator"); } _buffer = allocator.Allocate <T>(capacity); _capacity = capacity; _allocatorID = allocator.ID; }
private NativeDeque(ref NativeDeque <T> deque) { Debug.Assert(deque.IsValid); Allocator allocator = deque.GetAllocator() !; T * buffer = allocator.Allocate <T>(deque._capacity); Unsafe.CopyBlockUnaligned(buffer, deque._buffer, (uint)(sizeof(T) * deque._capacity)); _buffer = buffer; _count = deque._count; _capacity = deque._capacity; _allocatorID = deque._allocatorID; _head = deque._head; _tail = deque._tail; }
private NativeString(ref NativeString str) { if (!str.IsValid) { throw new ArgumentException("string is invalid"); } Allocator allocator = str.GetAllocator() !; char * buffer = allocator.Allocate <char>(str._length); Unsafe.CopyBlockUnaligned(buffer, str._buffer, (uint)(sizeof(char) * str._length)); _buffer = buffer; _length = str._length; _allocatorID = str._allocatorID; }
/// <summary> /// Initializes a new instance of the <see cref="NativeQueue{T}"/> struct. /// </summary> /// <param name="initialCapacity">The initial capacity.</param> /// <param name="allocator">The allocator.</param> /// <exception cref="ArgumentException">capacity must be greater than 0: {initialCapacity}</exception> public NativeQueue(int initialCapacity, Allocator allocator) { if (initialCapacity <= 0) { throw new ArgumentException($"capacity must be greater than 0: {initialCapacity}"); } if (Allocator.IsCached(allocator) is false) { throw new ArgumentException("Allocator is not in cache.", nameof(allocator)); } _buffer = (T *)allocator.Allocate(initialCapacity, sizeof(T)); _capacity = initialCapacity; _count = _head = _tail = 0; _allocatorID = allocator.ID; }
/// <summary> /// Initializes a new instance of the <see cref="NativeBuffer"/> struct. /// </summary> /// <param name="bytesCount">The number of bytes to allocate.</param> /// <param name="allocator">The allocator.</param> /// <exception cref="ArgumentException">If bytes count is negative or zero, or the allocator is not in cache.</exception> public NativeBuffer(int bytesCount, Allocator allocator) { if (bytesCount <= 0) { throw new ArgumentException("bytesCount cannot be negative or zero"); } if (Allocator.IsCached(allocator) is false) { throw new ArgumentException("The allocator is not in cache"); } _buffer = (byte *)allocator.Allocate(bytesCount); _length = bytesCount; _offset = 0; _allocatorID = allocator.ID; }
/// <summary> /// Initializes a new instance of the <see cref="NativeList{T}"/> struct. /// </summary> /// <param name="initialCapacity">The initial capacity of the list.</param> /// <param name="allocator">The allocator used for this list.</param> /// <exception cref="ArgumentException">If the capacity is negative or zero.</exception> public NativeList(int initialCapacity, Allocator allocator) { if (initialCapacity <= 0) { throw new ArgumentException($"initialCapacity should be greater than 0: {initialCapacity}"); } if (Allocator.IsCached(allocator) is false) { throw new ArgumentException("Allocator is not in cache.", nameof(allocator)); } _buffer = allocator.Allocate <T>(initialCapacity); _capacity = initialCapacity; _count = 0; _allocatorID = allocator.ID; }
private static void *AllocateCopy <T>(void *pointer, int elementCount, Allocator allocator) where T : unmanaged { if (pointer == null) { throw new ArgumentException("pointer is null"); } if (elementCount <= 0) { throw new ArgumentException($"elementCount cannot be negative or 0: {elementCount}"); } void *destination = allocator.Allocate <T>(elementCount); Unsafe.CopyBlockUnaligned(destination, pointer, (uint)(sizeof(T) * elementCount)); return(destination); }
/// <summary> /// Initializes a new instance of the <see cref="NativeSortedSet{T}"/> struct. /// </summary> /// <param name="initialCapacity">The initial capacity.</param> /// <param name="allocator">The allocator.</param> /// <exception cref="System.ArgumentException">If the initialCapacity is negative or zero, or the allocator is not in cache.</exception> public NativeSortedSet(int initialCapacity, Allocator allocator) { if (initialCapacity <= 0) { throw new ArgumentException("initialCapacity cannot be negative or zero", nameof(initialCapacity)); } if (Allocator.IsCached(allocator) is false) { throw new ArgumentException("allocator is not in cache", nameof(allocator)); } _buffer = allocator.Allocate <T>(initialCapacity); _capacity = initialCapacity; _allocatorID = allocator.ID; _count = 0; }
private NativeMultiValueMap(ref NativeMultiValueMap <TKey, TValue> multiValueMap) { Debug.Assert(multiValueMap.IsValid); Allocator allocator = multiValueMap.GetAllocator() !; int slots = multiValueMap.Slots; int sizeOfEntry = sizeof(NativeMap <TKey, NativeList <TValue> > .Entry); var buffer = allocator.Allocate <NativeMap <TKey, NativeList <TValue> > .Entry>(slots); var source = multiValueMap._map._buffer; Unsafe.CopyBlockUnaligned(buffer, source, (uint)(sizeOfEntry * slots)); for (int i = 0; i < slots; ++i) { ref var entry = ref buffer[i]; if (entry.hashCode >= 0) { entry.value = entry.value.Clone(); } }
private static void AllocateServer(List <Server> servers) { Allocator allocator = new Allocator(servers); try { var allocatedServer = allocator.Allocate(); if (allocatedServer != null) { Console.WriteLine($"New connection from Server{allocatedServer?.Id + 1}."); } else { Console.WriteLine("Server not found."); } } catch (Exception) { Console.WriteLine("Server not found."); } }
/// <summary> /// Initializes a new instance of the <see cref="NativeSet{T}"/> struct. /// </summary> /// <param name="initialCapacity">The initial capacity.</param> /// <param name="allocator">The allocator.</param> /// <exception cref="ArgumentException">If the capacity is negative or 0, or if the allocator is not in cache.</exception> public NativeSet(int initialCapacity, Allocator allocator) { if (initialCapacity <= 0) { throw new ArgumentException("initialCapacity should be greater than 0.", nameof(initialCapacity)); } if (Allocator.IsCached(allocator) is false) { throw new ArgumentException("Allocator is not in cache.", nameof(allocator)); } _buffer = (Slot *)allocator.Allocate(initialCapacity, sizeof(Slot)); _capacity = initialCapacity; _count = 0; _freeList = -1; _freeCount = 0; _allocatorID = allocator.ID; Initializate(); }
public NativeQuery <TResult> Select <TResult>(Func <T, TResult> selector) where TResult : unmanaged { if (_length == 0) { return(new NativeQuery <TResult>(GetAllocator())); } int length = _length; Allocator allocator = GetAllocator() !; TResult * buffer = allocator.Allocate <TResult>(length); Enumerator enumerator = GetEnumerator(disposing: false); int i = 0; foreach (ref var e in this) { buffer[i++] = selector(e); } return(new NativeQuery <TResult>(buffer, length, allocator)); }
/// <summary> /// Initializes a new instance of the <see cref="NativeStack{T}"/> struct. /// </summary> /// <param name="elements">The initial elements.</param> /// <param name="allocator">The allocator.</param> public NativeStack(Span <int> elements, Allocator allocator) { if (Allocator.IsCached(allocator) is false) { throw new ArgumentException("Allocator is not in cache.", nameof(allocator)); } if (elements.IsEmpty) { this = default; } else { _buffer = allocator.Allocate <T>(elements.Length); _capacity = elements.Length; _count = _capacity; _allocatorID = allocator.ID; void *source = Unsafe.AsPointer(ref MemoryMarshal.GetReference(elements)); Unsafe.CopyBlock(_buffer, source, (uint)(sizeof(T) * _capacity)); } }
public void VarianceDistributionIsMinimum() { Person firstPerson = new Person(1, 5); Person secondPerson = new Person(1, 6); Person thirdPerson = new Person(1, 8); List <Person> collectors = new List <Person>() { firstPerson, secondPerson, thirdPerson }; Allocator allocator = new Allocator(); allocator.Allocate(50, collectors); Assert.IsTrue(firstPerson.NewSticksHolded == 18); Assert.IsTrue(secondPerson.NewSticksHolded == 17); Assert.IsTrue(thirdPerson.NewSticksHolded == 15); }
public void Second_VarianceDistributionIsBigTest() { Person firstPerson = new Person(1, 50); Person secondPerson = new Person(1, 0); Person thirdPerson = new Person(1, 0); List <Person> collectors = new List <Person>() { firstPerson, secondPerson, thirdPerson }; Allocator allocator = new Allocator(); allocator.Allocate(60, collectors); Assert.IsTrue(firstPerson.NewSticksHolded == 50); Assert.IsTrue(secondPerson.NewSticksHolded == 30); Assert.IsTrue(thirdPerson.NewSticksHolded == 30); }
/// <summary> /// Gets a <see cref="NativeQuery{T}"/> with the default values if this query is empty, otherwise get the same query. /// </summary> /// <typeparam name="T"></typeparam> /// <typeparam name="TResult">The type of the result.</typeparam> /// <param name="query">The query.</param> /// <param name="defaultValues">The default values.</param> /// <returns>A query with the default value if empty, otherwise the same query will be returned.</returns> public static NativeQuery <T> DefaultIfEmpty <T>(this NativeQuery <T> query, Span <T> defaultValues) where T : unmanaged { if (query.IsEmpty) { if (defaultValues.IsEmpty) { return(new NativeQuery <T>(query.GetAllocator())); } unsafe { int length = defaultValues.Length; Allocator allocator = query.GetAllocator() ?? Allocator.Default; T * buffer = allocator.Allocate <T>(length); void * src = Unsafe.AsPointer(ref defaultValues[0]); Unsafe.CopyBlockUnaligned(buffer, src, (uint)(sizeof(T) * length)); return(new NativeQuery <T>(buffer, length, allocator)); } } return(query); }
public static void TestChurnStability() { var allocator = new Allocator(2048); var random = new Random(5); ulong idCounter = 0; var pool = new PassthroughArrayPool <ulong>(); QuickList <ulong, Array <ulong> > .Create(pool, 8, out var allocatedIds); QuickList <ulong, Array <ulong> > .Create(pool, 8, out var unallocatedIds); for (int i = 0; i < 512; ++i) { long start; var id = idCounter++; //allocator.ValidatePointers(); if (allocator.Allocate(id, 1 + random.Next(5), out start)) { allocatedIds.Add(id, pool); } else { unallocatedIds.Add(id, pool); } //allocator.ValidatePointers(); } for (int timestepIndex = 0; timestepIndex < 100000; ++timestepIndex) { //First add and remove a bunch randomly. for (int i = random.Next(Math.Min(allocatedIds.Count, 15)); i >= 0; --i) { var indexToRemove = random.Next(allocatedIds.Count); //allocator.ValidatePointers(); var deallocated = allocator.Deallocate(allocatedIds[indexToRemove]); Debug.Assert(deallocated); //allocator.ValidatePointers(); unallocatedIds.Add(allocatedIds[indexToRemove], pool); allocatedIds.FastRemoveAt(indexToRemove); } for (int i = random.Next(Math.Min(unallocatedIds.Count, 15)); i >= 0; --i) { var indexToAllocate = random.Next(unallocatedIds.Count); //allocator.ValidatePointers(); if (allocator.Allocate(unallocatedIds[indexToAllocate], random.Next(3), out long start)) { //allocator.ValidatePointers(); allocatedIds.Add(unallocatedIds[indexToAllocate], pool); unallocatedIds.FastRemoveAt(indexToAllocate); } //allocator.ValidatePointers(); } //Check to ensure that everything's still coherent. for (int i = 0; i < allocatedIds.Count; ++i) { Debug.Assert(allocator.Contains(allocatedIds[i])); } for (int i = 0; i < unallocatedIds.Count; ++i) { Debug.Assert(!allocator.Contains(unallocatedIds[i])); } } //Wind it down. for (int i = 0; i < allocatedIds.Count; ++i) { var deallocated = allocator.Deallocate(allocatedIds[i]); Debug.Assert(deallocated); } //Confirm cleanup. for (int i = 0; i < allocatedIds.Count; ++i) { Debug.Assert(!allocator.Contains(allocatedIds[i])); } for (int i = 0; i < unallocatedIds.Count; ++i) { Debug.Assert(!allocator.Contains(unallocatedIds[i])); } }