public void IterateRows_OverMinimumPixelsLimit_ShouldVisitAllRows(
            int maxDegreeOfParallelism,
            int minY,
            int maxY,
            int expectedStepLength,
            int expectedLastStepLength,
            int expectedNumberOfSteps)
        {
            var parallelSettings = new ParallelExecutionSettings(
                maxDegreeOfParallelism,
                1,
                Configuration.Default.MemoryAllocator);

            var rectangle = new Rectangle(0, minY, 10, maxY - minY);

            int[] expectedData = Enumerable.Repeat(0, minY).Concat(Enumerable.Range(minY, maxY - minY)).ToArray();
            var   actualData   = new int[maxY];

            void RowAction(RowInterval rows)
            {
                for (int y = rows.Min; y < rows.Max; y++)
                {
                    actualData[y] = y;
                }
            }

            var operation = new TestRowIntervalOperation(RowAction);

            ParallelRowIterator.IterateRowIntervals(
                rectangle,
                in parallelSettings,
                in operation);

            Assert.Equal(expectedData, actualData);
        }
        public void IterateRectangularBuffer(
            int maxDegreeOfParallelism,
            int bufferWidth,
            int bufferHeight,
            int rectX,
            int rectY,
            int rectWidth,
            int rectHeight)
        {
            MemoryAllocator memoryAllocator = Configuration.Default.MemoryAllocator;

            using (Buffer2D <Point> expected = memoryAllocator.Allocate2D <Point>(bufferWidth, bufferHeight, AllocationOptions.Clean))
                using (Buffer2D <Point> actual = memoryAllocator.Allocate2D <Point>(bufferWidth, bufferHeight, AllocationOptions.Clean))
                {
                    var rect = new Rectangle(rectX, rectY, rectWidth, rectHeight);

                    void FillRow(int y, Buffer2D <Point> buffer)
                    {
                        for (int x = rect.Left; x < rect.Right; x++)
                        {
                            buffer[x, y] = new Point(x, y);
                        }
                    }

                    // Fill Expected data:
                    for (int y = rectY; y < rect.Bottom; y++)
                    {
                        FillRow(y, expected);
                    }

                    // Fill actual data using IterateRows:
                    var settings = new ParallelExecutionSettings(maxDegreeOfParallelism, memoryAllocator);

                    void RowAction(RowInterval rows)
                    {
                        this.output.WriteLine(rows.ToString());
                        for (int y = rows.Min; y < rows.Max; y++)
                        {
                            FillRow(y, actual);
                        }
                    }

                    var operation = new TestRowIntervalOperation(RowAction);

                    ParallelRowIterator.IterateRowIntervals(
                        rect,
                        settings,
                        in operation);

                    // Assert:
                    TestImageExtensions.CompareBuffers(expected.GetSingleSpan(), actual.GetSingleSpan());
                }
        }
        public void IterateRowsWithTempBufferRequiresValidRectangle(int width, int height)
        {
            var parallelSettings = default(ParallelExecutionSettings);

            var rect = new Rectangle(0, 0, width, height);

            void RowAction(RowInterval rows, Span <Rgba32> memory)
            {
            }

            var operation = new TestRowIntervalOperation <Rgba32>(RowAction);

            ArgumentOutOfRangeException ex = Assert.Throws <ArgumentOutOfRangeException>(
                () => ParallelRowIterator.IterateRowIntervals <TestRowIntervalOperation <Rgba32>, Rgba32>(rect, in parallelSettings, in operation));

            Assert.Contains(width <= 0 ? "Width" : "Height", ex.Message);
        }
        public void IterateRowsWithTempBuffer_WithEffectiveMinimumPixelsLimit(
            int maxDegreeOfParallelism,
            int minimumPixelsProcessedPerTask,
            int width,
            int height,
            int expectedNumberOfSteps,
            int expectedStepLength,
            int expectedLastStepLength)
        {
            var parallelSettings = new ParallelExecutionSettings(
                maxDegreeOfParallelism,
                minimumPixelsProcessedPerTask,
                Configuration.Default.MemoryAllocator);

            var rectangle = new Rectangle(0, 0, width, height);

            int actualNumberOfSteps = 0;

            void RowAction(RowInterval rows, Span <Vector4> buffer)
            {
                Assert.True(rows.Min >= 0);
                Assert.True(rows.Max <= height);

                int step     = rows.Max - rows.Min;
                int expected = rows.Max < height ? expectedStepLength : expectedLastStepLength;

                Interlocked.Increment(ref actualNumberOfSteps);
                Assert.Equal(expected, step);
            }

            var operation = new TestRowIntervalOperation <Vector4>(RowAction);

            ParallelRowIterator.IterateRowIntervals <TestRowIntervalOperation <Vector4>, Vector4>(
                rectangle,
                in parallelSettings,
                in operation);

            Assert.Equal(expectedNumberOfSteps, actualNumberOfSteps);
        }
        public void IterateRows_OverMinimumPixelsLimit_IntervalsAreCorrect(
            int maxDegreeOfParallelism,
            int minY,
            int maxY,
            int expectedStepLength,
            int expectedLastStepLength,
            int expectedNumberOfSteps)
        {
            var parallelSettings = new ParallelExecutionSettings(
                maxDegreeOfParallelism,
                1,
                Configuration.Default.MemoryAllocator);

            var rectangle = new Rectangle(0, minY, 10, maxY - minY);

            int actualNumberOfSteps = 0;

            void RowAction(RowInterval rows)
            {
                Assert.True(rows.Min >= minY);
                Assert.True(rows.Max <= maxY);

                int step     = rows.Max - rows.Min;
                int expected = rows.Max < maxY ? expectedStepLength : expectedLastStepLength;

                Interlocked.Increment(ref actualNumberOfSteps);
                Assert.Equal(expected, step);
            }

            var operation = new TestRowIntervalOperation(RowAction);

            ParallelRowIterator.IterateRowIntervals(
                rectangle,
                in parallelSettings,
                in operation);

            Assert.Equal(expectedNumberOfSteps, actualNumberOfSteps);
        }