From ecf160e5bbde7d16fa8af8d29dc25ace5529dd9b Mon Sep 17 00:00:00 2001 From: Anton Firszov Date: Mon, 18 Jun 2018 23:28:54 +0200 Subject: [PATCH] refactor QuickSort to a common utility class --- .../Drawing/Processors/FillRegionProcessor.cs | 69 +-------------- .../Processing/Text/DrawTextExtensions.cs | 2 - .../Text/Processors/DrawTextProcessor.cs | 58 +------------ src/ImageSharp.Drawing/Utils/QuickSort.cs | 84 +++++++++++++++++++ .../ImageSharp.Tests/Drawing/BeziersTests.cs | 3 +- .../Drawing/Utils/QuickSortTests.cs | 51 +++++++++++ 6 files changed, 140 insertions(+), 127 deletions(-) create mode 100644 src/ImageSharp.Drawing/Utils/QuickSort.cs create mode 100644 tests/ImageSharp.Tests/Drawing/Utils/QuickSortTests.cs diff --git a/src/ImageSharp.Drawing/Processing/Drawing/Processors/FillRegionProcessor.cs b/src/ImageSharp.Drawing/Processing/Drawing/Processors/FillRegionProcessor.cs index c81f4028b..1e968b97e 100644 --- a/src/ImageSharp.Drawing/Processing/Drawing/Processors/FillRegionProcessor.cs +++ b/src/ImageSharp.Drawing/Processing/Drawing/Processors/FillRegionProcessor.cs @@ -2,11 +2,11 @@ // Licensed under the Apache License, Version 2.0. using System; -using System.Runtime.CompilerServices; using SixLabors.ImageSharp.PixelFormats; using SixLabors.ImageSharp.Primitives; using SixLabors.ImageSharp.Processing.Drawing.Brushes; using SixLabors.ImageSharp.Processing.Processors; +using SixLabors.ImageSharp.Utils; using SixLabors.Memory; using SixLabors.Primitives; @@ -124,7 +124,7 @@ namespace SixLabors.ImageSharp.Processing.Drawing.Processors continue; } - QuickSort(buffer.Slice(0, pointsFound)); + QuickSort.Sort(buffer.Slice(0, pointsFound)); for (int point = 0; point < pointsFound; point += 2) { @@ -186,70 +186,5 @@ namespace SixLabors.ImageSharp.Processing.Drawing.Processors } } } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - private static void Swap(ref float left, ref float right) - { - float tmp = left; - left = right; - right = tmp; - } - - private static void QuickSort(Span data) - { - if (data.Length < 2) - { - return; - } - else if (data.Length == 2) - { - if (data[0] > data[1]) - { - Swap(ref data[0], ref data[1]); - } - - return; - } - - QuickSort(ref data[0], 0, data.Length - 1); - } - - private static void QuickSort(ref float data0, int lo, int hi) - { - if (lo < hi) - { - int p = Partition(ref data0, lo, hi); - QuickSort(ref data0, lo, p); - QuickSort(ref data0, p + 1, hi); - } - } - - private static int Partition(ref float data0, int lo, int hi) - { - float pivot = Unsafe.Add(ref data0, lo); - int i = lo - 1; - int j = hi + 1; - while (true) - { - do - { - i = i + 1; - } - while (Unsafe.Add(ref data0, i) < pivot && i < hi); - - do - { - j = j - 1; - } - while (Unsafe.Add(ref data0, j) > pivot && j > lo); - - if (i >= j) - { - return j; - } - - Swap(ref Unsafe.Add(ref data0, i), ref Unsafe.Add(ref data0, j)); - } - } } } \ No newline at end of file diff --git a/src/ImageSharp.Drawing/Processing/Text/DrawTextExtensions.cs b/src/ImageSharp.Drawing/Processing/Text/DrawTextExtensions.cs index ed7a7bbfa..a20d7f730 100644 --- a/src/ImageSharp.Drawing/Processing/Text/DrawTextExtensions.cs +++ b/src/ImageSharp.Drawing/Processing/Text/DrawTextExtensions.cs @@ -3,12 +3,10 @@ using SixLabors.Fonts; using SixLabors.ImageSharp.PixelFormats; -using SixLabors.ImageSharp.Processing.Drawing; using SixLabors.ImageSharp.Processing.Drawing.Brushes; using SixLabors.ImageSharp.Processing.Drawing.Pens; using SixLabors.ImageSharp.Processing.Text.Processors; using SixLabors.Primitives; -using SixLabors.Shapes; namespace SixLabors.ImageSharp.Processing.Text { diff --git a/src/ImageSharp.Drawing/Processing/Text/Processors/DrawTextProcessor.cs b/src/ImageSharp.Drawing/Processing/Text/Processors/DrawTextProcessor.cs index a38a0c320..f86bd827f 100644 --- a/src/ImageSharp.Drawing/Processing/Text/Processors/DrawTextProcessor.cs +++ b/src/ImageSharp.Drawing/Processing/Text/Processors/DrawTextProcessor.cs @@ -3,16 +3,13 @@ using System; using System.Collections.Generic; -using System.Runtime.CompilerServices; -using System.Threading.Tasks; using SixLabors.Fonts; using SixLabors.ImageSharp.Advanced; using SixLabors.ImageSharp.PixelFormats; -using SixLabors.ImageSharp.Primitives; using SixLabors.ImageSharp.Processing.Drawing.Brushes; using SixLabors.ImageSharp.Processing.Drawing.Pens; -using SixLabors.ImageSharp.Processing.Drawing.Processors; using SixLabors.ImageSharp.Processing.Processors; +using SixLabors.ImageSharp.Utils; using SixLabors.Memory; using SixLabors.Primitives; using SixLabors.Shapes; @@ -377,7 +374,7 @@ namespace SixLabors.ImageSharp.Processing.Text.Processors buffer[i] = intersectionSpan[i].X; } - QuickSort(buffer.Slice(0, pointsFound)); + QuickSort.Sort(buffer.Slice(0, pointsFound)); for (int point = 0; point < pointsFound; point += 2) { @@ -439,57 +436,6 @@ namespace SixLabors.ImageSharp.Processing.Text.Processors return fullBuffer; } - [MethodImpl(MethodImplOptions.AggressiveInlining)] - private static void Swap(Span data, int left, int right) - { - float tmp = data[left]; - data[left] = data[right]; - data[right] = tmp; - } - - private static void QuickSort(Span data) - { - QuickSort(data, 0, data.Length - 1); - } - - private static void QuickSort(Span data, int lo, int hi) - { - if (lo < hi) - { - int p = Partition(data, lo, hi); - QuickSort(data, lo, p); - QuickSort(data, p + 1, hi); - } - } - - private static int Partition(Span data, int lo, int hi) - { - float pivot = data[lo]; - int i = lo - 1; - int j = hi + 1; - while (true) - { - do - { - i = i + 1; - } - while (data[i] < pivot && i < hi); - - do - { - j = j - 1; - } - while (data[j] > pivot && j > lo); - - if (i >= j) - { - return j; - } - - Swap(data, i, j); - } - } - public void EndText() { } diff --git a/src/ImageSharp.Drawing/Utils/QuickSort.cs b/src/ImageSharp.Drawing/Utils/QuickSort.cs new file mode 100644 index 000000000..ca1da5505 --- /dev/null +++ b/src/ImageSharp.Drawing/Utils/QuickSort.cs @@ -0,0 +1,84 @@ +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. + +using System; +using System.Runtime.CompilerServices; + +namespace SixLabors.ImageSharp.Utils +{ + /// + /// Optimized quick sort implementation for Span{float} input + /// + internal class QuickSort + { + /// + /// Sorts the elements of in ascending order + /// + /// The items to sort + public static void Sort(Span data) + { + if (data.Length < 2) + { + return; + } + + if (data.Length == 2) + { + if (data[0] > data[1]) + { + Swap(ref data[0], ref data[1]); + } + + return; + } + + Sort(ref data[0], 0, data.Length - 1); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static void Swap(ref float left, ref float right) + { + float tmp = left; + left = right; + right = tmp; + } + + private static void Sort(ref float data0, int lo, int hi) + { + if (lo < hi) + { + int p = Partition(ref data0, lo, hi); + Sort(ref data0, lo, p); + Sort(ref data0, p + 1, hi); + } + } + + private static int Partition(ref float data0, int lo, int hi) + { + float pivot = Unsafe.Add(ref data0, lo); + int i = lo - 1; + int j = hi + 1; + while (true) + { + do + { + i = i + 1; + } + while (Unsafe.Add(ref data0, i) < pivot && i < hi); + + do + { + j = j - 1; + } + while (Unsafe.Add(ref data0, j) > pivot && j > lo); + + if (i >= j) + { + return j; + } + + Swap(ref Unsafe.Add(ref data0, i), ref Unsafe.Add(ref data0, j)); + } + } + } +} diff --git a/tests/ImageSharp.Tests/Drawing/BeziersTests.cs b/tests/ImageSharp.Tests/Drawing/BeziersTests.cs index 6dc2fae89..a5fda7958 100644 --- a/tests/ImageSharp.Tests/Drawing/BeziersTests.cs +++ b/tests/ImageSharp.Tests/Drawing/BeziersTests.cs @@ -7,12 +7,11 @@ using SixLabors.ImageSharp.PixelFormats; using SixLabors.ImageSharp.Processing; using SixLabors.ImageSharp.Processing.Drawing; using SixLabors.ImageSharp.Processing.Overlays; +using SixLabors.Memory; using Xunit; namespace SixLabors.ImageSharp.Tests.Drawing { - using SixLabors.Memory; - public class Beziers : FileTestBase { [Fact] diff --git a/tests/ImageSharp.Tests/Drawing/Utils/QuickSortTests.cs b/tests/ImageSharp.Tests/Drawing/Utils/QuickSortTests.cs new file mode 100644 index 000000000..6660cd87a --- /dev/null +++ b/tests/ImageSharp.Tests/Drawing/Utils/QuickSortTests.cs @@ -0,0 +1,51 @@ +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. + +namespace SixLabors.ImageSharp.Tests.Drawing.Utils +{ + using System; + using System.Linq; + + using SixLabors.ImageSharp.Utils; + + using Xunit; + + public class QuickSortTests + { + public static readonly TheoryData Data = new TheoryData() + { + new float[]{ 3, 2, 1 }, + new float[0], + new float[] { 42}, + new float[] { 1, 2}, + new float[] { 2, 1}, + new float[] { 5, 1, 2, 3, 0} + }; + + [Theory] + [MemberData(nameof(Data))] + public void Sort(float[] data) + { + float[] expected = data.ToArray(); + + Array.Sort(expected); + + QuickSort.Sort(data); + + Assert.Equal(expected, data); + } + + [Fact] + public void SortSlice() + { + float[] data = { 3, 2, 1, 0, -1 }; + + Span slice = data.AsSpan(1, 3); + QuickSort.Sort(slice); + float[] actual = slice.ToArray(); + float[] expected = { 0, 1, 2 }; + + Assert.Equal(actual, expected); + } + } +} \ No newline at end of file