public void Evaluate(int spreadMax) { // Check if any inputs changed (important for string) if (!StreamUtils.AnyChanged(FDataIn, FSelectIn)) { return; } spreadMax = StreamUtils.GetSpreadMax(FDataIn, FSelectIn); // Early exit if (spreadMax == 0) { FDataOut.Length = 0; FFormerSliceOut.Length = 0; return; } // In case nothing changed also do an early exit - important if T is a string or a reference type if (!FDataIn.IsChanged && !FSelectIn.IsChanged) { return; } // Fetch readers and writers using (var dataReader = FDataIn.GetCyclicReader()) using (var selectReader = FSelectIn.GetCyclicReader()) using (var dataWriter = FDataOut.GetDynamicWriter()) using (var formerSliceWriter = FFormerSliceOut.GetDynamicWriter()) { // Grab buffers from pool var dataInBuffer = MemoryPool <T> .GetArray(); var dataOutBuffer = MemoryPool <T> .GetArray(); var selectBuffer = MemoryPool <int> .GetArray(); var sliceBuffer = MemoryPool <int> .GetArray(); try { var numSlicesToRead = spreadMax; var offset = 0; var formerSlice = 0; while (numSlicesToRead > 0) { var blockSize = Math.Min(StreamUtils.BUFFER_SIZE, numSlicesToRead); dataReader.Read(dataInBuffer, 0, blockSize); selectReader.Read(selectBuffer, 0, blockSize); // This loop iterates through the input data for (int i = 0; i < blockSize; i++) { var data = dataInBuffer[i]; var select = selectBuffer[i]; // This loop replicates the input data on the output select times for (int j = 0; j < select; j++) { // Buffer result data dataOutBuffer[offset] = data; sliceBuffer[offset] = formerSlice; offset++; // Write data out if buffer is full if (offset == StreamUtils.BUFFER_SIZE) { dataWriter.Write(dataOutBuffer, 0, StreamUtils.BUFFER_SIZE); formerSliceWriter.Write(sliceBuffer, 0, StreamUtils.BUFFER_SIZE); offset = 0; } } formerSlice++; } numSlicesToRead -= blockSize; } // Write any buffered output data left if (offset > 0) { dataWriter.Write(dataOutBuffer, 0, offset); formerSliceWriter.Write(sliceBuffer, 0, offset); } } finally { MemoryPool <T> .PutArray(dataInBuffer); MemoryPool <T> .PutArray(dataOutBuffer); MemoryPool <int> .PutArray(selectBuffer); MemoryPool <int> .PutArray(sliceBuffer); } } }