From 097022dcaca1a239662987d227595001e2777926 Mon Sep 17 00:00:00 2001 From: Jack Dermody Date: Wed, 31 Jul 2024 09:38:41 +1000 Subject: [PATCH] added fixed size sorted arrays and refactored fixed size graph nodes --- BrightData.UnitTests/FixedSizeArrayTests.cs | 44 + BrightData.UnitTests/VectorSetTests.cs | 2 +- BrightData/BrightData.csproj | 14 + BrightData/BrightData.xml | 5257 +++++++++++- BrightData/ExtensionMethods.Span.cs | 33 + BrightData/ExtensionMethods.TensorSegment.cs | 25 +- BrightData/Interfaces.cs | 76 + .../Helper/IndexedFixedSizeGraphNode.cs | 119 +- .../VectorIndexing/Helper/VectorGraph.cs | 13 +- .../FixedSizeSortedArray.cs | 7481 +++++++++++++++++ .../FixedSizeSortedArray.tt | 259 + .../FixedSizeSortedArrayHelper.cs | 154 + 12 files changed, 13331 insertions(+), 146 deletions(-) create mode 100644 BrightData.UnitTests/FixedSizeArrayTests.cs create mode 100644 BrightData/Types/FixedSizeSortedArray/FixedSizeSortedArray.cs create mode 100644 BrightData/Types/FixedSizeSortedArray/FixedSizeSortedArray.tt create mode 100644 BrightData/Types/FixedSizeSortedArray/FixedSizeSortedArrayHelper.cs diff --git a/BrightData.UnitTests/FixedSizeArrayTests.cs b/BrightData.UnitTests/FixedSizeArrayTests.cs new file mode 100644 index 00000000..5417b825 --- /dev/null +++ b/BrightData.UnitTests/FixedSizeArrayTests.cs @@ -0,0 +1,44 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using BrightData.Types; +using FluentAssertions; +using Xunit; + +namespace BrightData.UnitTests +{ + public class FixedSizeArrayTests + { + [Fact] + public void TestAscending() + { + var array = new FixedSizeSortedAscending2Array(); + array.TryAdd(1, 0.5f).Should().BeTrue(); + array.TryAdd(1, 0.5f).Should().BeFalse(); + array.TryAdd(2, 0.3f).Should().BeTrue(); + array.TryAdd(3, 0.8f).Should().BeFalse(); + array.MinValue.Should().Be(2); + array.MaxValue.Should().Be(1); + array.RemoveAt(0); + array.Size.Should().Be(1); + array.MinValue.Should().Be(1); + } + + [Fact] + public void TestDescending() + { + var array = new FixedSizeSortedDescending2Array(); + array.TryAdd(1, 0.5f).Should().BeTrue(); + array.TryAdd(1, 0.5f).Should().BeFalse(); + array.TryAdd(2, 0.8f).Should().BeTrue(); + array.TryAdd(3, 0.3f).Should().BeFalse(); + array.MinValue.Should().Be(1); + array.MaxValue.Should().Be(2); + array.RemoveAt(0); + array.Size.Should().Be(1); + array.MaxValue.Should().Be(1); + } + } +} diff --git a/BrightData.UnitTests/VectorSetTests.cs b/BrightData.UnitTests/VectorSetTests.cs index 80dc3ca8..35a5dcb2 100644 --- a/BrightData.UnitTests/VectorSetTests.cs +++ b/BrightData.UnitTests/VectorSetTests.cs @@ -67,7 +67,7 @@ public void Closest() [Fact] public void TestVectorGraphNode() { - var node = new IndexedFixedSizeGraphNode(1); + var node = new IndexedFixedSizeGraphNode>(1); node.Index.Should().Be(1); node.NeighbourIndices.Length.Should().Be(0); diff --git a/BrightData/BrightData.csproj b/BrightData/BrightData.csproj index 3d477dc9..507b41de 100644 --- a/BrightData/BrightData.csproj +++ b/BrightData/BrightData.csproj @@ -63,6 +63,11 @@ True GenericTypeMapping.tt + + True + True + FixedSizeSortedArray.tt + @@ -82,6 +87,10 @@ True \ + + TextTemplatingFileGenerator + FixedSizeSortedArray.cs + @@ -104,5 +113,10 @@ True GenericTypeMapping.tt + + True + True + FixedSizeSortedArray.tt + diff --git a/BrightData/BrightData.xml b/BrightData/BrightData.xml index 87ebccac..a977f713 100644 --- a/BrightData/BrightData.xml +++ b/BrightData/BrightData.xml @@ -6812,6 +6812,80 @@ + + + Fixed size sorted array of values and weights + + Type of value to store + Type of weight that will be used to sort + + + + Maximum number of elements that can fit in the array + + + + + Current number of elements + + + + + Sorted list of values + + + + + Sorted list of weights + + + + + The smallest weight + + + + + The largest weight + + + + + The value with the smallest weight + + + + + The value with the largest weight + + + + + Returns a value and weight + + Index to return + + + + Enumerates the values and weights + + + + + Tries to add a new element - will succeed if there aren't already max elements with a smaller weight + + Value to add + Weight to add + True if values should be unique - will return false if the value already exists + True if the element was added + + + + Removes an element from the array + + Index of element to remove + + Indicates that the type has a single index @@ -12057,78 +12131,81 @@ - + Fixed size indexed graph node that maintains weighted list of neighbours as a max heap - + Weight type + Array type - + Fixed size indexed graph node that maintains weighted list of neighbours as a max heap - + Weight type + Array type - + - + Max number of neighbours - + Current number of neighbours - + The smallest neighbour weight - + The largest neighbour weight - + The index of the neighbour with the smallest weight - + The index of the neighbour with the largest weight - + Tries to add a new neighbour - will succeed if there aren't already max neighbours with a smaller weight + - + Sorted list of neighbour indices - + Sorted list of neighbour weights - + Returns a neighbour weight - + Enumerates the weighted neighbours @@ -12139,7 +12216,7 @@ - + Creates a vector graph from an array of nodes @@ -12370,6 +12447,5152 @@ + + + Fixed size sorted array of values and weights (max 2 elements) + that is sorted in ascending order based on each weight + + Type of value to store + Type of weight that will be used to sort + + + + Fixed size sorted array of values and weights (max 2 elements) + that is sorted in ascending order based on each weight + + Type of value to store + Type of weight that will be used to sort + + + + Max size of the array + + + + + Current number of elements + + + + + Sorted list of values + + + + + Sorted list of weights + + + + + The smallest weight + + + + + The largest weight + + + + + The value with the smallest weight + + + + + The value with the largest weight + + + + + Returns a value and weight + + Index to return + + + + Enumerates the values and weights + + + + + Tries to add a new element - will succeed if there aren't already max elements with a smaller weight + + Value to add + Weight to add + True if values should be unique - will return false if the value already exists + True if the element was added + + + + Removes an element from the array + + Index of element to remove + + + + + Fixed size sorted array of values and weights (max 2 elements) + that is sorted in descending order based on each weight + + Type of value to store + Type of weight that will be used to sort + + + + Fixed size sorted array of values and weights (max 2 elements) + that is sorted in descending order based on each weight + + Type of value to store + Type of weight that will be used to sort + + + + Max size of the array + + + + + Current number of elements + + + + + Sorted list of values + + + + + Sorted list of weights + + + + + The smallest weight + + + + + The largest weight + + + + + The value with the smallest weight + + + + + The value with the largest weight + + + + + Returns a value and weight + + Index to return + + + + Enumerates the values and weights + + + + + Tries to add a new element - will succeed if there aren't already max elements with a smaller weight + + Value to add + Weight to add + True if values should be unique - will return false if the value already exists + True if the element was added + + + + Removes an element from the array + + Index of element to remove + + + + + Fixed size sorted array of values and weights (max 3 elements) + that is sorted in ascending order based on each weight + + Type of value to store + Type of weight that will be used to sort + + + + Fixed size sorted array of values and weights (max 3 elements) + that is sorted in ascending order based on each weight + + Type of value to store + Type of weight that will be used to sort + + + + Max size of the array + + + + + Current number of elements + + + + + Sorted list of values + + + + + Sorted list of weights + + + + + The smallest weight + + + + + The largest weight + + + + + The value with the smallest weight + + + + + The value with the largest weight + + + + + Returns a value and weight + + Index to return + + + + Enumerates the values and weights + + + + + Tries to add a new element - will succeed if there aren't already max elements with a smaller weight + + Value to add + Weight to add + True if values should be unique - will return false if the value already exists + True if the element was added + + + + Removes an element from the array + + Index of element to remove + + + + + Fixed size sorted array of values and weights (max 3 elements) + that is sorted in descending order based on each weight + + Type of value to store + Type of weight that will be used to sort + + + + Fixed size sorted array of values and weights (max 3 elements) + that is sorted in descending order based on each weight + + Type of value to store + Type of weight that will be used to sort + + + + Max size of the array + + + + + Current number of elements + + + + + Sorted list of values + + + + + Sorted list of weights + + + + + The smallest weight + + + + + The largest weight + + + + + The value with the smallest weight + + + + + The value with the largest weight + + + + + Returns a value and weight + + Index to return + + + + Enumerates the values and weights + + + + + Tries to add a new element - will succeed if there aren't already max elements with a smaller weight + + Value to add + Weight to add + True if values should be unique - will return false if the value already exists + True if the element was added + + + + Removes an element from the array + + Index of element to remove + + + + + Fixed size sorted array of values and weights (max 4 elements) + that is sorted in ascending order based on each weight + + Type of value to store + Type of weight that will be used to sort + + + + Fixed size sorted array of values and weights (max 4 elements) + that is sorted in ascending order based on each weight + + Type of value to store + Type of weight that will be used to sort + + + + Max size of the array + + + + + Current number of elements + + + + + Sorted list of values + + + + + Sorted list of weights + + + + + The smallest weight + + + + + The largest weight + + + + + The value with the smallest weight + + + + + The value with the largest weight + + + + + Returns a value and weight + + Index to return + + + + Enumerates the values and weights + + + + + Tries to add a new element - will succeed if there aren't already max elements with a smaller weight + + Value to add + Weight to add + True if values should be unique - will return false if the value already exists + True if the element was added + + + + Removes an element from the array + + Index of element to remove + + + + + Fixed size sorted array of values and weights (max 4 elements) + that is sorted in descending order based on each weight + + Type of value to store + Type of weight that will be used to sort + + + + Fixed size sorted array of values and weights (max 4 elements) + that is sorted in descending order based on each weight + + Type of value to store + Type of weight that will be used to sort + + + + Max size of the array + + + + + Current number of elements + + + + + Sorted list of values + + + + + Sorted list of weights + + + + + The smallest weight + + + + + The largest weight + + + + + The value with the smallest weight + + + + + The value with the largest weight + + + + + Returns a value and weight + + Index to return + + + + Enumerates the values and weights + + + + + Tries to add a new element - will succeed if there aren't already max elements with a smaller weight + + Value to add + Weight to add + True if values should be unique - will return false if the value already exists + True if the element was added + + + + Removes an element from the array + + Index of element to remove + + + + + Fixed size sorted array of values and weights (max 5 elements) + that is sorted in ascending order based on each weight + + Type of value to store + Type of weight that will be used to sort + + + + Fixed size sorted array of values and weights (max 5 elements) + that is sorted in ascending order based on each weight + + Type of value to store + Type of weight that will be used to sort + + + + Max size of the array + + + + + Current number of elements + + + + + Sorted list of values + + + + + Sorted list of weights + + + + + The smallest weight + + + + + The largest weight + + + + + The value with the smallest weight + + + + + The value with the largest weight + + + + + Returns a value and weight + + Index to return + + + + Enumerates the values and weights + + + + + Tries to add a new element - will succeed if there aren't already max elements with a smaller weight + + Value to add + Weight to add + True if values should be unique - will return false if the value already exists + True if the element was added + + + + Removes an element from the array + + Index of element to remove + + + + + Fixed size sorted array of values and weights (max 5 elements) + that is sorted in descending order based on each weight + + Type of value to store + Type of weight that will be used to sort + + + + Fixed size sorted array of values and weights (max 5 elements) + that is sorted in descending order based on each weight + + Type of value to store + Type of weight that will be used to sort + + + + Max size of the array + + + + + Current number of elements + + + + + Sorted list of values + + + + + Sorted list of weights + + + + + The smallest weight + + + + + The largest weight + + + + + The value with the smallest weight + + + + + The value with the largest weight + + + + + Returns a value and weight + + Index to return + + + + Enumerates the values and weights + + + + + Tries to add a new element - will succeed if there aren't already max elements with a smaller weight + + Value to add + Weight to add + True if values should be unique - will return false if the value already exists + True if the element was added + + + + Removes an element from the array + + Index of element to remove + + + + + Fixed size sorted array of values and weights (max 6 elements) + that is sorted in ascending order based on each weight + + Type of value to store + Type of weight that will be used to sort + + + + Fixed size sorted array of values and weights (max 6 elements) + that is sorted in ascending order based on each weight + + Type of value to store + Type of weight that will be used to sort + + + + Max size of the array + + + + + Current number of elements + + + + + Sorted list of values + + + + + Sorted list of weights + + + + + The smallest weight + + + + + The largest weight + + + + + The value with the smallest weight + + + + + The value with the largest weight + + + + + Returns a value and weight + + Index to return + + + + Enumerates the values and weights + + + + + Tries to add a new element - will succeed if there aren't already max elements with a smaller weight + + Value to add + Weight to add + True if values should be unique - will return false if the value already exists + True if the element was added + + + + Removes an element from the array + + Index of element to remove + + + + + Fixed size sorted array of values and weights (max 6 elements) + that is sorted in descending order based on each weight + + Type of value to store + Type of weight that will be used to sort + + + + Fixed size sorted array of values and weights (max 6 elements) + that is sorted in descending order based on each weight + + Type of value to store + Type of weight that will be used to sort + + + + Max size of the array + + + + + Current number of elements + + + + + Sorted list of values + + + + + Sorted list of weights + + + + + The smallest weight + + + + + The largest weight + + + + + The value with the smallest weight + + + + + The value with the largest weight + + + + + Returns a value and weight + + Index to return + + + + Enumerates the values and weights + + + + + Tries to add a new element - will succeed if there aren't already max elements with a smaller weight + + Value to add + Weight to add + True if values should be unique - will return false if the value already exists + True if the element was added + + + + Removes an element from the array + + Index of element to remove + + + + + Fixed size sorted array of values and weights (max 7 elements) + that is sorted in ascending order based on each weight + + Type of value to store + Type of weight that will be used to sort + + + + Fixed size sorted array of values and weights (max 7 elements) + that is sorted in ascending order based on each weight + + Type of value to store + Type of weight that will be used to sort + + + + Max size of the array + + + + + Current number of elements + + + + + Sorted list of values + + + + + Sorted list of weights + + + + + The smallest weight + + + + + The largest weight + + + + + The value with the smallest weight + + + + + The value with the largest weight + + + + + Returns a value and weight + + Index to return + + + + Enumerates the values and weights + + + + + Tries to add a new element - will succeed if there aren't already max elements with a smaller weight + + Value to add + Weight to add + True if values should be unique - will return false if the value already exists + True if the element was added + + + + Removes an element from the array + + Index of element to remove + + + + + Fixed size sorted array of values and weights (max 7 elements) + that is sorted in descending order based on each weight + + Type of value to store + Type of weight that will be used to sort + + + + Fixed size sorted array of values and weights (max 7 elements) + that is sorted in descending order based on each weight + + Type of value to store + Type of weight that will be used to sort + + + + Max size of the array + + + + + Current number of elements + + + + + Sorted list of values + + + + + Sorted list of weights + + + + + The smallest weight + + + + + The largest weight + + + + + The value with the smallest weight + + + + + The value with the largest weight + + + + + Returns a value and weight + + Index to return + + + + Enumerates the values and weights + + + + + Tries to add a new element - will succeed if there aren't already max elements with a smaller weight + + Value to add + Weight to add + True if values should be unique - will return false if the value already exists + True if the element was added + + + + Removes an element from the array + + Index of element to remove + + + + + Fixed size sorted array of values and weights (max 8 elements) + that is sorted in ascending order based on each weight + + Type of value to store + Type of weight that will be used to sort + + + + Fixed size sorted array of values and weights (max 8 elements) + that is sorted in ascending order based on each weight + + Type of value to store + Type of weight that will be used to sort + + + + Max size of the array + + + + + Current number of elements + + + + + Sorted list of values + + + + + Sorted list of weights + + + + + The smallest weight + + + + + The largest weight + + + + + The value with the smallest weight + + + + + The value with the largest weight + + + + + Returns a value and weight + + Index to return + + + + Enumerates the values and weights + + + + + Tries to add a new element - will succeed if there aren't already max elements with a smaller weight + + Value to add + Weight to add + True if values should be unique - will return false if the value already exists + True if the element was added + + + + Removes an element from the array + + Index of element to remove + + + + + Fixed size sorted array of values and weights (max 8 elements) + that is sorted in descending order based on each weight + + Type of value to store + Type of weight that will be used to sort + + + + Fixed size sorted array of values and weights (max 8 elements) + that is sorted in descending order based on each weight + + Type of value to store + Type of weight that will be used to sort + + + + Max size of the array + + + + + Current number of elements + + + + + Sorted list of values + + + + + Sorted list of weights + + + + + The smallest weight + + + + + The largest weight + + + + + The value with the smallest weight + + + + + The value with the largest weight + + + + + Returns a value and weight + + Index to return + + + + Enumerates the values and weights + + + + + Tries to add a new element - will succeed if there aren't already max elements with a smaller weight + + Value to add + Weight to add + True if values should be unique - will return false if the value already exists + True if the element was added + + + + Removes an element from the array + + Index of element to remove + + + + + Fixed size sorted array of values and weights (max 9 elements) + that is sorted in ascending order based on each weight + + Type of value to store + Type of weight that will be used to sort + + + + Fixed size sorted array of values and weights (max 9 elements) + that is sorted in ascending order based on each weight + + Type of value to store + Type of weight that will be used to sort + + + + Max size of the array + + + + + Current number of elements + + + + + Sorted list of values + + + + + Sorted list of weights + + + + + The smallest weight + + + + + The largest weight + + + + + The value with the smallest weight + + + + + The value with the largest weight + + + + + Returns a value and weight + + Index to return + + + + Enumerates the values and weights + + + + + Tries to add a new element - will succeed if there aren't already max elements with a smaller weight + + Value to add + Weight to add + True if values should be unique - will return false if the value already exists + True if the element was added + + + + Removes an element from the array + + Index of element to remove + + + + + Fixed size sorted array of values and weights (max 9 elements) + that is sorted in descending order based on each weight + + Type of value to store + Type of weight that will be used to sort + + + + Fixed size sorted array of values and weights (max 9 elements) + that is sorted in descending order based on each weight + + Type of value to store + Type of weight that will be used to sort + + + + Max size of the array + + + + + Current number of elements + + + + + Sorted list of values + + + + + Sorted list of weights + + + + + The smallest weight + + + + + The largest weight + + + + + The value with the smallest weight + + + + + The value with the largest weight + + + + + Returns a value and weight + + Index to return + + + + Enumerates the values and weights + + + + + Tries to add a new element - will succeed if there aren't already max elements with a smaller weight + + Value to add + Weight to add + True if values should be unique - will return false if the value already exists + True if the element was added + + + + Removes an element from the array + + Index of element to remove + + + + + Fixed size sorted array of values and weights (max 10 elements) + that is sorted in ascending order based on each weight + + Type of value to store + Type of weight that will be used to sort + + + + Fixed size sorted array of values and weights (max 10 elements) + that is sorted in ascending order based on each weight + + Type of value to store + Type of weight that will be used to sort + + + + Max size of the array + + + + + Current number of elements + + + + + Sorted list of values + + + + + Sorted list of weights + + + + + The smallest weight + + + + + The largest weight + + + + + The value with the smallest weight + + + + + The value with the largest weight + + + + + Returns a value and weight + + Index to return + + + + Enumerates the values and weights + + + + + Tries to add a new element - will succeed if there aren't already max elements with a smaller weight + + Value to add + Weight to add + True if values should be unique - will return false if the value already exists + True if the element was added + + + + Removes an element from the array + + Index of element to remove + + + + + Fixed size sorted array of values and weights (max 10 elements) + that is sorted in descending order based on each weight + + Type of value to store + Type of weight that will be used to sort + + + + Fixed size sorted array of values and weights (max 10 elements) + that is sorted in descending order based on each weight + + Type of value to store + Type of weight that will be used to sort + + + + Max size of the array + + + + + Current number of elements + + + + + Sorted list of values + + + + + Sorted list of weights + + + + + The smallest weight + + + + + The largest weight + + + + + The value with the smallest weight + + + + + The value with the largest weight + + + + + Returns a value and weight + + Index to return + + + + Enumerates the values and weights + + + + + Tries to add a new element - will succeed if there aren't already max elements with a smaller weight + + Value to add + Weight to add + True if values should be unique - will return false if the value already exists + True if the element was added + + + + Removes an element from the array + + Index of element to remove + + + + + Fixed size sorted array of values and weights (max 11 elements) + that is sorted in ascending order based on each weight + + Type of value to store + Type of weight that will be used to sort + + + + Fixed size sorted array of values and weights (max 11 elements) + that is sorted in ascending order based on each weight + + Type of value to store + Type of weight that will be used to sort + + + + Max size of the array + + + + + Current number of elements + + + + + Sorted list of values + + + + + Sorted list of weights + + + + + The smallest weight + + + + + The largest weight + + + + + The value with the smallest weight + + + + + The value with the largest weight + + + + + Returns a value and weight + + Index to return + + + + Enumerates the values and weights + + + + + Tries to add a new element - will succeed if there aren't already max elements with a smaller weight + + Value to add + Weight to add + True if values should be unique - will return false if the value already exists + True if the element was added + + + + Removes an element from the array + + Index of element to remove + + + + + Fixed size sorted array of values and weights (max 11 elements) + that is sorted in descending order based on each weight + + Type of value to store + Type of weight that will be used to sort + + + + Fixed size sorted array of values and weights (max 11 elements) + that is sorted in descending order based on each weight + + Type of value to store + Type of weight that will be used to sort + + + + Max size of the array + + + + + Current number of elements + + + + + Sorted list of values + + + + + Sorted list of weights + + + + + The smallest weight + + + + + The largest weight + + + + + The value with the smallest weight + + + + + The value with the largest weight + + + + + Returns a value and weight + + Index to return + + + + Enumerates the values and weights + + + + + Tries to add a new element - will succeed if there aren't already max elements with a smaller weight + + Value to add + Weight to add + True if values should be unique - will return false if the value already exists + True if the element was added + + + + Removes an element from the array + + Index of element to remove + + + + + Fixed size sorted array of values and weights (max 12 elements) + that is sorted in ascending order based on each weight + + Type of value to store + Type of weight that will be used to sort + + + + Fixed size sorted array of values and weights (max 12 elements) + that is sorted in ascending order based on each weight + + Type of value to store + Type of weight that will be used to sort + + + + Max size of the array + + + + + Current number of elements + + + + + Sorted list of values + + + + + Sorted list of weights + + + + + The smallest weight + + + + + The largest weight + + + + + The value with the smallest weight + + + + + The value with the largest weight + + + + + Returns a value and weight + + Index to return + + + + Enumerates the values and weights + + + + + Tries to add a new element - will succeed if there aren't already max elements with a smaller weight + + Value to add + Weight to add + True if values should be unique - will return false if the value already exists + True if the element was added + + + + Removes an element from the array + + Index of element to remove + + + + + Fixed size sorted array of values and weights (max 12 elements) + that is sorted in descending order based on each weight + + Type of value to store + Type of weight that will be used to sort + + + + Fixed size sorted array of values and weights (max 12 elements) + that is sorted in descending order based on each weight + + Type of value to store + Type of weight that will be used to sort + + + + Max size of the array + + + + + Current number of elements + + + + + Sorted list of values + + + + + Sorted list of weights + + + + + The smallest weight + + + + + The largest weight + + + + + The value with the smallest weight + + + + + The value with the largest weight + + + + + Returns a value and weight + + Index to return + + + + Enumerates the values and weights + + + + + Tries to add a new element - will succeed if there aren't already max elements with a smaller weight + + Value to add + Weight to add + True if values should be unique - will return false if the value already exists + True if the element was added + + + + Removes an element from the array + + Index of element to remove + + + + + Fixed size sorted array of values and weights (max 13 elements) + that is sorted in ascending order based on each weight + + Type of value to store + Type of weight that will be used to sort + + + + Fixed size sorted array of values and weights (max 13 elements) + that is sorted in ascending order based on each weight + + Type of value to store + Type of weight that will be used to sort + + + + Max size of the array + + + + + Current number of elements + + + + + Sorted list of values + + + + + Sorted list of weights + + + + + The smallest weight + + + + + The largest weight + + + + + The value with the smallest weight + + + + + The value with the largest weight + + + + + Returns a value and weight + + Index to return + + + + Enumerates the values and weights + + + + + Tries to add a new element - will succeed if there aren't already max elements with a smaller weight + + Value to add + Weight to add + True if values should be unique - will return false if the value already exists + True if the element was added + + + + Removes an element from the array + + Index of element to remove + + + + + Fixed size sorted array of values and weights (max 13 elements) + that is sorted in descending order based on each weight + + Type of value to store + Type of weight that will be used to sort + + + + Fixed size sorted array of values and weights (max 13 elements) + that is sorted in descending order based on each weight + + Type of value to store + Type of weight that will be used to sort + + + + Max size of the array + + + + + Current number of elements + + + + + Sorted list of values + + + + + Sorted list of weights + + + + + The smallest weight + + + + + The largest weight + + + + + The value with the smallest weight + + + + + The value with the largest weight + + + + + Returns a value and weight + + Index to return + + + + Enumerates the values and weights + + + + + Tries to add a new element - will succeed if there aren't already max elements with a smaller weight + + Value to add + Weight to add + True if values should be unique - will return false if the value already exists + True if the element was added + + + + Removes an element from the array + + Index of element to remove + + + + + Fixed size sorted array of values and weights (max 14 elements) + that is sorted in ascending order based on each weight + + Type of value to store + Type of weight that will be used to sort + + + + Fixed size sorted array of values and weights (max 14 elements) + that is sorted in ascending order based on each weight + + Type of value to store + Type of weight that will be used to sort + + + + Max size of the array + + + + + Current number of elements + + + + + Sorted list of values + + + + + Sorted list of weights + + + + + The smallest weight + + + + + The largest weight + + + + + The value with the smallest weight + + + + + The value with the largest weight + + + + + Returns a value and weight + + Index to return + + + + Enumerates the values and weights + + + + + Tries to add a new element - will succeed if there aren't already max elements with a smaller weight + + Value to add + Weight to add + True if values should be unique - will return false if the value already exists + True if the element was added + + + + Removes an element from the array + + Index of element to remove + + + + + Fixed size sorted array of values and weights (max 14 elements) + that is sorted in descending order based on each weight + + Type of value to store + Type of weight that will be used to sort + + + + Fixed size sorted array of values and weights (max 14 elements) + that is sorted in descending order based on each weight + + Type of value to store + Type of weight that will be used to sort + + + + Max size of the array + + + + + Current number of elements + + + + + Sorted list of values + + + + + Sorted list of weights + + + + + The smallest weight + + + + + The largest weight + + + + + The value with the smallest weight + + + + + The value with the largest weight + + + + + Returns a value and weight + + Index to return + + + + Enumerates the values and weights + + + + + Tries to add a new element - will succeed if there aren't already max elements with a smaller weight + + Value to add + Weight to add + True if values should be unique - will return false if the value already exists + True if the element was added + + + + Removes an element from the array + + Index of element to remove + + + + + Fixed size sorted array of values and weights (max 15 elements) + that is sorted in ascending order based on each weight + + Type of value to store + Type of weight that will be used to sort + + + + Fixed size sorted array of values and weights (max 15 elements) + that is sorted in ascending order based on each weight + + Type of value to store + Type of weight that will be used to sort + + + + Max size of the array + + + + + Current number of elements + + + + + Sorted list of values + + + + + Sorted list of weights + + + + + The smallest weight + + + + + The largest weight + + + + + The value with the smallest weight + + + + + The value with the largest weight + + + + + Returns a value and weight + + Index to return + + + + Enumerates the values and weights + + + + + Tries to add a new element - will succeed if there aren't already max elements with a smaller weight + + Value to add + Weight to add + True if values should be unique - will return false if the value already exists + True if the element was added + + + + Removes an element from the array + + Index of element to remove + + + + + Fixed size sorted array of values and weights (max 15 elements) + that is sorted in descending order based on each weight + + Type of value to store + Type of weight that will be used to sort + + + + Fixed size sorted array of values and weights (max 15 elements) + that is sorted in descending order based on each weight + + Type of value to store + Type of weight that will be used to sort + + + + Max size of the array + + + + + Current number of elements + + + + + Sorted list of values + + + + + Sorted list of weights + + + + + The smallest weight + + + + + The largest weight + + + + + The value with the smallest weight + + + + + The value with the largest weight + + + + + Returns a value and weight + + Index to return + + + + Enumerates the values and weights + + + + + Tries to add a new element - will succeed if there aren't already max elements with a smaller weight + + Value to add + Weight to add + True if values should be unique - will return false if the value already exists + True if the element was added + + + + Removes an element from the array + + Index of element to remove + + + + + Fixed size sorted array of values and weights (max 16 elements) + that is sorted in ascending order based on each weight + + Type of value to store + Type of weight that will be used to sort + + + + Fixed size sorted array of values and weights (max 16 elements) + that is sorted in ascending order based on each weight + + Type of value to store + Type of weight that will be used to sort + + + + Max size of the array + + + + + Current number of elements + + + + + Sorted list of values + + + + + Sorted list of weights + + + + + The smallest weight + + + + + The largest weight + + + + + The value with the smallest weight + + + + + The value with the largest weight + + + + + Returns a value and weight + + Index to return + + + + Enumerates the values and weights + + + + + Tries to add a new element - will succeed if there aren't already max elements with a smaller weight + + Value to add + Weight to add + True if values should be unique - will return false if the value already exists + True if the element was added + + + + Removes an element from the array + + Index of element to remove + + + + + Fixed size sorted array of values and weights (max 16 elements) + that is sorted in descending order based on each weight + + Type of value to store + Type of weight that will be used to sort + + + + Fixed size sorted array of values and weights (max 16 elements) + that is sorted in descending order based on each weight + + Type of value to store + Type of weight that will be used to sort + + + + Max size of the array + + + + + Current number of elements + + + + + Sorted list of values + + + + + Sorted list of weights + + + + + The smallest weight + + + + + The largest weight + + + + + The value with the smallest weight + + + + + The value with the largest weight + + + + + Returns a value and weight + + Index to return + + + + Enumerates the values and weights + + + + + Tries to add a new element - will succeed if there aren't already max elements with a smaller weight + + Value to add + Weight to add + True if values should be unique - will return false if the value already exists + True if the element was added + + + + Removes an element from the array + + Index of element to remove + + + + + Fixed size sorted array of values and weights (max 17 elements) + that is sorted in ascending order based on each weight + + Type of value to store + Type of weight that will be used to sort + + + + Fixed size sorted array of values and weights (max 17 elements) + that is sorted in ascending order based on each weight + + Type of value to store + Type of weight that will be used to sort + + + + Max size of the array + + + + + Current number of elements + + + + + Sorted list of values + + + + + Sorted list of weights + + + + + The smallest weight + + + + + The largest weight + + + + + The value with the smallest weight + + + + + The value with the largest weight + + + + + Returns a value and weight + + Index to return + + + + Enumerates the values and weights + + + + + Tries to add a new element - will succeed if there aren't already max elements with a smaller weight + + Value to add + Weight to add + True if values should be unique - will return false if the value already exists + True if the element was added + + + + Removes an element from the array + + Index of element to remove + + + + + Fixed size sorted array of values and weights (max 17 elements) + that is sorted in descending order based on each weight + + Type of value to store + Type of weight that will be used to sort + + + + Fixed size sorted array of values and weights (max 17 elements) + that is sorted in descending order based on each weight + + Type of value to store + Type of weight that will be used to sort + + + + Max size of the array + + + + + Current number of elements + + + + + Sorted list of values + + + + + Sorted list of weights + + + + + The smallest weight + + + + + The largest weight + + + + + The value with the smallest weight + + + + + The value with the largest weight + + + + + Returns a value and weight + + Index to return + + + + Enumerates the values and weights + + + + + Tries to add a new element - will succeed if there aren't already max elements with a smaller weight + + Value to add + Weight to add + True if values should be unique - will return false if the value already exists + True if the element was added + + + + Removes an element from the array + + Index of element to remove + + + + + Fixed size sorted array of values and weights (max 18 elements) + that is sorted in ascending order based on each weight + + Type of value to store + Type of weight that will be used to sort + + + + Fixed size sorted array of values and weights (max 18 elements) + that is sorted in ascending order based on each weight + + Type of value to store + Type of weight that will be used to sort + + + + Max size of the array + + + + + Current number of elements + + + + + Sorted list of values + + + + + Sorted list of weights + + + + + The smallest weight + + + + + The largest weight + + + + + The value with the smallest weight + + + + + The value with the largest weight + + + + + Returns a value and weight + + Index to return + + + + Enumerates the values and weights + + + + + Tries to add a new element - will succeed if there aren't already max elements with a smaller weight + + Value to add + Weight to add + True if values should be unique - will return false if the value already exists + True if the element was added + + + + Removes an element from the array + + Index of element to remove + + + + + Fixed size sorted array of values and weights (max 18 elements) + that is sorted in descending order based on each weight + + Type of value to store + Type of weight that will be used to sort + + + + Fixed size sorted array of values and weights (max 18 elements) + that is sorted in descending order based on each weight + + Type of value to store + Type of weight that will be used to sort + + + + Max size of the array + + + + + Current number of elements + + + + + Sorted list of values + + + + + Sorted list of weights + + + + + The smallest weight + + + + + The largest weight + + + + + The value with the smallest weight + + + + + The value with the largest weight + + + + + Returns a value and weight + + Index to return + + + + Enumerates the values and weights + + + + + Tries to add a new element - will succeed if there aren't already max elements with a smaller weight + + Value to add + Weight to add + True if values should be unique - will return false if the value already exists + True if the element was added + + + + Removes an element from the array + + Index of element to remove + + + + + Fixed size sorted array of values and weights (max 19 elements) + that is sorted in ascending order based on each weight + + Type of value to store + Type of weight that will be used to sort + + + + Fixed size sorted array of values and weights (max 19 elements) + that is sorted in ascending order based on each weight + + Type of value to store + Type of weight that will be used to sort + + + + Max size of the array + + + + + Current number of elements + + + + + Sorted list of values + + + + + Sorted list of weights + + + + + The smallest weight + + + + + The largest weight + + + + + The value with the smallest weight + + + + + The value with the largest weight + + + + + Returns a value and weight + + Index to return + + + + Enumerates the values and weights + + + + + Tries to add a new element - will succeed if there aren't already max elements with a smaller weight + + Value to add + Weight to add + True if values should be unique - will return false if the value already exists + True if the element was added + + + + Removes an element from the array + + Index of element to remove + + + + + Fixed size sorted array of values and weights (max 19 elements) + that is sorted in descending order based on each weight + + Type of value to store + Type of weight that will be used to sort + + + + Fixed size sorted array of values and weights (max 19 elements) + that is sorted in descending order based on each weight + + Type of value to store + Type of weight that will be used to sort + + + + Max size of the array + + + + + Current number of elements + + + + + Sorted list of values + + + + + Sorted list of weights + + + + + The smallest weight + + + + + The largest weight + + + + + The value with the smallest weight + + + + + The value with the largest weight + + + + + Returns a value and weight + + Index to return + + + + Enumerates the values and weights + + + + + Tries to add a new element - will succeed if there aren't already max elements with a smaller weight + + Value to add + Weight to add + True if values should be unique - will return false if the value already exists + True if the element was added + + + + Removes an element from the array + + Index of element to remove + + + + + Fixed size sorted array of values and weights (max 20 elements) + that is sorted in ascending order based on each weight + + Type of value to store + Type of weight that will be used to sort + + + + Fixed size sorted array of values and weights (max 20 elements) + that is sorted in ascending order based on each weight + + Type of value to store + Type of weight that will be used to sort + + + + Max size of the array + + + + + Current number of elements + + + + + Sorted list of values + + + + + Sorted list of weights + + + + + The smallest weight + + + + + The largest weight + + + + + The value with the smallest weight + + + + + The value with the largest weight + + + + + Returns a value and weight + + Index to return + + + + Enumerates the values and weights + + + + + Tries to add a new element - will succeed if there aren't already max elements with a smaller weight + + Value to add + Weight to add + True if values should be unique - will return false if the value already exists + True if the element was added + + + + Removes an element from the array + + Index of element to remove + + + + + Fixed size sorted array of values and weights (max 20 elements) + that is sorted in descending order based on each weight + + Type of value to store + Type of weight that will be used to sort + + + + Fixed size sorted array of values and weights (max 20 elements) + that is sorted in descending order based on each weight + + Type of value to store + Type of weight that will be used to sort + + + + Max size of the array + + + + + Current number of elements + + + + + Sorted list of values + + + + + Sorted list of weights + + + + + The smallest weight + + + + + The largest weight + + + + + The value with the smallest weight + + + + + The value with the largest weight + + + + + Returns a value and weight + + Index to return + + + + Enumerates the values and weights + + + + + Tries to add a new element - will succeed if there aren't already max elements with a smaller weight + + Value to add + Weight to add + True if values should be unique - will return false if the value already exists + True if the element was added + + + + Removes an element from the array + + Index of element to remove + + + + + Fixed size sorted array of values and weights (max 21 elements) + that is sorted in ascending order based on each weight + + Type of value to store + Type of weight that will be used to sort + + + + Fixed size sorted array of values and weights (max 21 elements) + that is sorted in ascending order based on each weight + + Type of value to store + Type of weight that will be used to sort + + + + Max size of the array + + + + + Current number of elements + + + + + Sorted list of values + + + + + Sorted list of weights + + + + + The smallest weight + + + + + The largest weight + + + + + The value with the smallest weight + + + + + The value with the largest weight + + + + + Returns a value and weight + + Index to return + + + + Enumerates the values and weights + + + + + Tries to add a new element - will succeed if there aren't already max elements with a smaller weight + + Value to add + Weight to add + True if values should be unique - will return false if the value already exists + True if the element was added + + + + Removes an element from the array + + Index of element to remove + + + + + Fixed size sorted array of values and weights (max 21 elements) + that is sorted in descending order based on each weight + + Type of value to store + Type of weight that will be used to sort + + + + Fixed size sorted array of values and weights (max 21 elements) + that is sorted in descending order based on each weight + + Type of value to store + Type of weight that will be used to sort + + + + Max size of the array + + + + + Current number of elements + + + + + Sorted list of values + + + + + Sorted list of weights + + + + + The smallest weight + + + + + The largest weight + + + + + The value with the smallest weight + + + + + The value with the largest weight + + + + + Returns a value and weight + + Index to return + + + + Enumerates the values and weights + + + + + Tries to add a new element - will succeed if there aren't already max elements with a smaller weight + + Value to add + Weight to add + True if values should be unique - will return false if the value already exists + True if the element was added + + + + Removes an element from the array + + Index of element to remove + + + + + Fixed size sorted array of values and weights (max 22 elements) + that is sorted in ascending order based on each weight + + Type of value to store + Type of weight that will be used to sort + + + + Fixed size sorted array of values and weights (max 22 elements) + that is sorted in ascending order based on each weight + + Type of value to store + Type of weight that will be used to sort + + + + Max size of the array + + + + + Current number of elements + + + + + Sorted list of values + + + + + Sorted list of weights + + + + + The smallest weight + + + + + The largest weight + + + + + The value with the smallest weight + + + + + The value with the largest weight + + + + + Returns a value and weight + + Index to return + + + + Enumerates the values and weights + + + + + Tries to add a new element - will succeed if there aren't already max elements with a smaller weight + + Value to add + Weight to add + True if values should be unique - will return false if the value already exists + True if the element was added + + + + Removes an element from the array + + Index of element to remove + + + + + Fixed size sorted array of values and weights (max 22 elements) + that is sorted in descending order based on each weight + + Type of value to store + Type of weight that will be used to sort + + + + Fixed size sorted array of values and weights (max 22 elements) + that is sorted in descending order based on each weight + + Type of value to store + Type of weight that will be used to sort + + + + Max size of the array + + + + + Current number of elements + + + + + Sorted list of values + + + + + Sorted list of weights + + + + + The smallest weight + + + + + The largest weight + + + + + The value with the smallest weight + + + + + The value with the largest weight + + + + + Returns a value and weight + + Index to return + + + + Enumerates the values and weights + + + + + Tries to add a new element - will succeed if there aren't already max elements with a smaller weight + + Value to add + Weight to add + True if values should be unique - will return false if the value already exists + True if the element was added + + + + Removes an element from the array + + Index of element to remove + + + + + Fixed size sorted array of values and weights (max 23 elements) + that is sorted in ascending order based on each weight + + Type of value to store + Type of weight that will be used to sort + + + + Fixed size sorted array of values and weights (max 23 elements) + that is sorted in ascending order based on each weight + + Type of value to store + Type of weight that will be used to sort + + + + Max size of the array + + + + + Current number of elements + + + + + Sorted list of values + + + + + Sorted list of weights + + + + + The smallest weight + + + + + The largest weight + + + + + The value with the smallest weight + + + + + The value with the largest weight + + + + + Returns a value and weight + + Index to return + + + + Enumerates the values and weights + + + + + Tries to add a new element - will succeed if there aren't already max elements with a smaller weight + + Value to add + Weight to add + True if values should be unique - will return false if the value already exists + True if the element was added + + + + Removes an element from the array + + Index of element to remove + + + + + Fixed size sorted array of values and weights (max 23 elements) + that is sorted in descending order based on each weight + + Type of value to store + Type of weight that will be used to sort + + + + Fixed size sorted array of values and weights (max 23 elements) + that is sorted in descending order based on each weight + + Type of value to store + Type of weight that will be used to sort + + + + Max size of the array + + + + + Current number of elements + + + + + Sorted list of values + + + + + Sorted list of weights + + + + + The smallest weight + + + + + The largest weight + + + + + The value with the smallest weight + + + + + The value with the largest weight + + + + + Returns a value and weight + + Index to return + + + + Enumerates the values and weights + + + + + Tries to add a new element - will succeed if there aren't already max elements with a smaller weight + + Value to add + Weight to add + True if values should be unique - will return false if the value already exists + True if the element was added + + + + Removes an element from the array + + Index of element to remove + + + + + Fixed size sorted array of values and weights (max 24 elements) + that is sorted in ascending order based on each weight + + Type of value to store + Type of weight that will be used to sort + + + + Fixed size sorted array of values and weights (max 24 elements) + that is sorted in ascending order based on each weight + + Type of value to store + Type of weight that will be used to sort + + + + Max size of the array + + + + + Current number of elements + + + + + Sorted list of values + + + + + Sorted list of weights + + + + + The smallest weight + + + + + The largest weight + + + + + The value with the smallest weight + + + + + The value with the largest weight + + + + + Returns a value and weight + + Index to return + + + + Enumerates the values and weights + + + + + Tries to add a new element - will succeed if there aren't already max elements with a smaller weight + + Value to add + Weight to add + True if values should be unique - will return false if the value already exists + True if the element was added + + + + Removes an element from the array + + Index of element to remove + + + + + Fixed size sorted array of values and weights (max 24 elements) + that is sorted in descending order based on each weight + + Type of value to store + Type of weight that will be used to sort + + + + Fixed size sorted array of values and weights (max 24 elements) + that is sorted in descending order based on each weight + + Type of value to store + Type of weight that will be used to sort + + + + Max size of the array + + + + + Current number of elements + + + + + Sorted list of values + + + + + Sorted list of weights + + + + + The smallest weight + + + + + The largest weight + + + + + The value with the smallest weight + + + + + The value with the largest weight + + + + + Returns a value and weight + + Index to return + + + + Enumerates the values and weights + + + + + Tries to add a new element - will succeed if there aren't already max elements with a smaller weight + + Value to add + Weight to add + True if values should be unique - will return false if the value already exists + True if the element was added + + + + Removes an element from the array + + Index of element to remove + + + + + Fixed size sorted array of values and weights (max 25 elements) + that is sorted in ascending order based on each weight + + Type of value to store + Type of weight that will be used to sort + + + + Fixed size sorted array of values and weights (max 25 elements) + that is sorted in ascending order based on each weight + + Type of value to store + Type of weight that will be used to sort + + + + Max size of the array + + + + + Current number of elements + + + + + Sorted list of values + + + + + Sorted list of weights + + + + + The smallest weight + + + + + The largest weight + + + + + The value with the smallest weight + + + + + The value with the largest weight + + + + + Returns a value and weight + + Index to return + + + + Enumerates the values and weights + + + + + Tries to add a new element - will succeed if there aren't already max elements with a smaller weight + + Value to add + Weight to add + True if values should be unique - will return false if the value already exists + True if the element was added + + + + Removes an element from the array + + Index of element to remove + + + + + Fixed size sorted array of values and weights (max 25 elements) + that is sorted in descending order based on each weight + + Type of value to store + Type of weight that will be used to sort + + + + Fixed size sorted array of values and weights (max 25 elements) + that is sorted in descending order based on each weight + + Type of value to store + Type of weight that will be used to sort + + + + Max size of the array + + + + + Current number of elements + + + + + Sorted list of values + + + + + Sorted list of weights + + + + + The smallest weight + + + + + The largest weight + + + + + The value with the smallest weight + + + + + The value with the largest weight + + + + + Returns a value and weight + + Index to return + + + + Enumerates the values and weights + + + + + Tries to add a new element - will succeed if there aren't already max elements with a smaller weight + + Value to add + Weight to add + True if values should be unique - will return false if the value already exists + True if the element was added + + + + Removes an element from the array + + Index of element to remove + + + + + Fixed size sorted array of values and weights (max 26 elements) + that is sorted in ascending order based on each weight + + Type of value to store + Type of weight that will be used to sort + + + + Fixed size sorted array of values and weights (max 26 elements) + that is sorted in ascending order based on each weight + + Type of value to store + Type of weight that will be used to sort + + + + Max size of the array + + + + + Current number of elements + + + + + Sorted list of values + + + + + Sorted list of weights + + + + + The smallest weight + + + + + The largest weight + + + + + The value with the smallest weight + + + + + The value with the largest weight + + + + + Returns a value and weight + + Index to return + + + + Enumerates the values and weights + + + + + Tries to add a new element - will succeed if there aren't already max elements with a smaller weight + + Value to add + Weight to add + True if values should be unique - will return false if the value already exists + True if the element was added + + + + Removes an element from the array + + Index of element to remove + + + + + Fixed size sorted array of values and weights (max 26 elements) + that is sorted in descending order based on each weight + + Type of value to store + Type of weight that will be used to sort + + + + Fixed size sorted array of values and weights (max 26 elements) + that is sorted in descending order based on each weight + + Type of value to store + Type of weight that will be used to sort + + + + Max size of the array + + + + + Current number of elements + + + + + Sorted list of values + + + + + Sorted list of weights + + + + + The smallest weight + + + + + The largest weight + + + + + The value with the smallest weight + + + + + The value with the largest weight + + + + + Returns a value and weight + + Index to return + + + + Enumerates the values and weights + + + + + Tries to add a new element - will succeed if there aren't already max elements with a smaller weight + + Value to add + Weight to add + True if values should be unique - will return false if the value already exists + True if the element was added + + + + Removes an element from the array + + Index of element to remove + + + + + Fixed size sorted array of values and weights (max 27 elements) + that is sorted in ascending order based on each weight + + Type of value to store + Type of weight that will be used to sort + + + + Fixed size sorted array of values and weights (max 27 elements) + that is sorted in ascending order based on each weight + + Type of value to store + Type of weight that will be used to sort + + + + Max size of the array + + + + + Current number of elements + + + + + Sorted list of values + + + + + Sorted list of weights + + + + + The smallest weight + + + + + The largest weight + + + + + The value with the smallest weight + + + + + The value with the largest weight + + + + + Returns a value and weight + + Index to return + + + + Enumerates the values and weights + + + + + Tries to add a new element - will succeed if there aren't already max elements with a smaller weight + + Value to add + Weight to add + True if values should be unique - will return false if the value already exists + True if the element was added + + + + Removes an element from the array + + Index of element to remove + + + + + Fixed size sorted array of values and weights (max 27 elements) + that is sorted in descending order based on each weight + + Type of value to store + Type of weight that will be used to sort + + + + Fixed size sorted array of values and weights (max 27 elements) + that is sorted in descending order based on each weight + + Type of value to store + Type of weight that will be used to sort + + + + Max size of the array + + + + + Current number of elements + + + + + Sorted list of values + + + + + Sorted list of weights + + + + + The smallest weight + + + + + The largest weight + + + + + The value with the smallest weight + + + + + The value with the largest weight + + + + + Returns a value and weight + + Index to return + + + + Enumerates the values and weights + + + + + Tries to add a new element - will succeed if there aren't already max elements with a smaller weight + + Value to add + Weight to add + True if values should be unique - will return false if the value already exists + True if the element was added + + + + Removes an element from the array + + Index of element to remove + + + + + Fixed size sorted array of values and weights (max 28 elements) + that is sorted in ascending order based on each weight + + Type of value to store + Type of weight that will be used to sort + + + + Fixed size sorted array of values and weights (max 28 elements) + that is sorted in ascending order based on each weight + + Type of value to store + Type of weight that will be used to sort + + + + Max size of the array + + + + + Current number of elements + + + + + Sorted list of values + + + + + Sorted list of weights + + + + + The smallest weight + + + + + The largest weight + + + + + The value with the smallest weight + + + + + The value with the largest weight + + + + + Returns a value and weight + + Index to return + + + + Enumerates the values and weights + + + + + Tries to add a new element - will succeed if there aren't already max elements with a smaller weight + + Value to add + Weight to add + True if values should be unique - will return false if the value already exists + True if the element was added + + + + Removes an element from the array + + Index of element to remove + + + + + Fixed size sorted array of values and weights (max 28 elements) + that is sorted in descending order based on each weight + + Type of value to store + Type of weight that will be used to sort + + + + Fixed size sorted array of values and weights (max 28 elements) + that is sorted in descending order based on each weight + + Type of value to store + Type of weight that will be used to sort + + + + Max size of the array + + + + + Current number of elements + + + + + Sorted list of values + + + + + Sorted list of weights + + + + + The smallest weight + + + + + The largest weight + + + + + The value with the smallest weight + + + + + The value with the largest weight + + + + + Returns a value and weight + + Index to return + + + + Enumerates the values and weights + + + + + Tries to add a new element - will succeed if there aren't already max elements with a smaller weight + + Value to add + Weight to add + True if values should be unique - will return false if the value already exists + True if the element was added + + + + Removes an element from the array + + Index of element to remove + + + + + Fixed size sorted array of values and weights (max 29 elements) + that is sorted in ascending order based on each weight + + Type of value to store + Type of weight that will be used to sort + + + + Fixed size sorted array of values and weights (max 29 elements) + that is sorted in ascending order based on each weight + + Type of value to store + Type of weight that will be used to sort + + + + Max size of the array + + + + + Current number of elements + + + + + Sorted list of values + + + + + Sorted list of weights + + + + + The smallest weight + + + + + The largest weight + + + + + The value with the smallest weight + + + + + The value with the largest weight + + + + + Returns a value and weight + + Index to return + + + + Enumerates the values and weights + + + + + Tries to add a new element - will succeed if there aren't already max elements with a smaller weight + + Value to add + Weight to add + True if values should be unique - will return false if the value already exists + True if the element was added + + + + Removes an element from the array + + Index of element to remove + + + + + Fixed size sorted array of values and weights (max 29 elements) + that is sorted in descending order based on each weight + + Type of value to store + Type of weight that will be used to sort + + + + Fixed size sorted array of values and weights (max 29 elements) + that is sorted in descending order based on each weight + + Type of value to store + Type of weight that will be used to sort + + + + Max size of the array + + + + + Current number of elements + + + + + Sorted list of values + + + + + Sorted list of weights + + + + + The smallest weight + + + + + The largest weight + + + + + The value with the smallest weight + + + + + The value with the largest weight + + + + + Returns a value and weight + + Index to return + + + + Enumerates the values and weights + + + + + Tries to add a new element - will succeed if there aren't already max elements with a smaller weight + + Value to add + Weight to add + True if values should be unique - will return false if the value already exists + True if the element was added + + + + Removes an element from the array + + Index of element to remove + + + + + Fixed size sorted array of values and weights (max 30 elements) + that is sorted in ascending order based on each weight + + Type of value to store + Type of weight that will be used to sort + + + + Fixed size sorted array of values and weights (max 30 elements) + that is sorted in ascending order based on each weight + + Type of value to store + Type of weight that will be used to sort + + + + Max size of the array + + + + + Current number of elements + + + + + Sorted list of values + + + + + Sorted list of weights + + + + + The smallest weight + + + + + The largest weight + + + + + The value with the smallest weight + + + + + The value with the largest weight + + + + + Returns a value and weight + + Index to return + + + + Enumerates the values and weights + + + + + Tries to add a new element - will succeed if there aren't already max elements with a smaller weight + + Value to add + Weight to add + True if values should be unique - will return false if the value already exists + True if the element was added + + + + Removes an element from the array + + Index of element to remove + + + + + Fixed size sorted array of values and weights (max 30 elements) + that is sorted in descending order based on each weight + + Type of value to store + Type of weight that will be used to sort + + + + Fixed size sorted array of values and weights (max 30 elements) + that is sorted in descending order based on each weight + + Type of value to store + Type of weight that will be used to sort + + + + Max size of the array + + + + + Current number of elements + + + + + Sorted list of values + + + + + Sorted list of weights + + + + + The smallest weight + + + + + The largest weight + + + + + The value with the smallest weight + + + + + The value with the largest weight + + + + + Returns a value and weight + + Index to return + + + + Enumerates the values and weights + + + + + Tries to add a new element - will succeed if there aren't already max elements with a smaller weight + + Value to add + Weight to add + True if values should be unique - will return false if the value already exists + True if the element was added + + + + Removes an element from the array + + Index of element to remove + + + + + Fixed size sorted array of values and weights (max 31 elements) + that is sorted in ascending order based on each weight + + Type of value to store + Type of weight that will be used to sort + + + + Fixed size sorted array of values and weights (max 31 elements) + that is sorted in ascending order based on each weight + + Type of value to store + Type of weight that will be used to sort + + + + Max size of the array + + + + + Current number of elements + + + + + Sorted list of values + + + + + Sorted list of weights + + + + + The smallest weight + + + + + The largest weight + + + + + The value with the smallest weight + + + + + The value with the largest weight + + + + + Returns a value and weight + + Index to return + + + + Enumerates the values and weights + + + + + Tries to add a new element - will succeed if there aren't already max elements with a smaller weight + + Value to add + Weight to add + True if values should be unique - will return false if the value already exists + True if the element was added + + + + Removes an element from the array + + Index of element to remove + + + + + Fixed size sorted array of values and weights (max 31 elements) + that is sorted in descending order based on each weight + + Type of value to store + Type of weight that will be used to sort + + + + Fixed size sorted array of values and weights (max 31 elements) + that is sorted in descending order based on each weight + + Type of value to store + Type of weight that will be used to sort + + + + Max size of the array + + + + + Current number of elements + + + + + Sorted list of values + + + + + Sorted list of weights + + + + + The smallest weight + + + + + The largest weight + + + + + The value with the smallest weight + + + + + The value with the largest weight + + + + + Returns a value and weight + + Index to return + + + + Enumerates the values and weights + + + + + Tries to add a new element - will succeed if there aren't already max elements with a smaller weight + + Value to add + Weight to add + True if values should be unique - will return false if the value already exists + True if the element was added + + + + Removes an element from the array + + Index of element to remove + + + + + Fixed size sorted array of values and weights (max 32 elements) + that is sorted in ascending order based on each weight + + Type of value to store + Type of weight that will be used to sort + + + + Fixed size sorted array of values and weights (max 32 elements) + that is sorted in ascending order based on each weight + + Type of value to store + Type of weight that will be used to sort + + + + Max size of the array + + + + + Current number of elements + + + + + Sorted list of values + + + + + Sorted list of weights + + + + + The smallest weight + + + + + The largest weight + + + + + The value with the smallest weight + + + + + The value with the largest weight + + + + + Returns a value and weight + + Index to return + + + + Enumerates the values and weights + + + + + Tries to add a new element - will succeed if there aren't already max elements with a smaller weight + + Value to add + Weight to add + True if values should be unique - will return false if the value already exists + True if the element was added + + + + Removes an element from the array + + Index of element to remove + + + + + Fixed size sorted array of values and weights (max 32 elements) + that is sorted in descending order based on each weight + + Type of value to store + Type of weight that will be used to sort + + + + Fixed size sorted array of values and weights (max 32 elements) + that is sorted in descending order based on each weight + + Type of value to store + Type of weight that will be used to sort + + + + Max size of the array + + + + + Current number of elements + + + + + Sorted list of values + + + + + Sorted list of weights + + + + + The smallest weight + + + + + The largest weight + + + + + The value with the smallest weight + + + + + The value with the largest weight + + + + + Returns a value and weight + + Index to return + + + + Enumerates the values and weights + + + + + Tries to add a new element - will succeed if there aren't already max elements with a smaller weight + + Value to add + Weight to add + True if values should be unique - will return false if the value already exists + True if the element was added + + + + Removes an element from the array + + Index of element to remove + + Contains a list of indices diff --git a/BrightData/ExtensionMethods.Span.cs b/BrightData/ExtensionMethods.Span.cs index b2f6e530..911ec14f 100644 --- a/BrightData/ExtensionMethods.Span.cs +++ b/BrightData/ExtensionMethods.Span.cs @@ -1654,6 +1654,39 @@ public static uint[] GetRankedIndices(this ReadOnlySpan span) where T : un /// public static uint[] GetRankedIndices(this Span span) where T : unmanaged, INumber => GetRankedIndices((ReadOnlySpan)span); + public static AT NIndices(this ReadOnlySpan span) + where AT: IFixedSizeSortedArray, new() + { + var ret = new AT(); + for (int i = 0, len = span.Length; i < len; i++) + ret.TryAdd((uint)i, span[i]); + return ret; + } + + public static MemoryOwner EuclideanNormalize(this ReadOnlySpan span) + where T : unmanaged, IBinaryFloatingPointIeee754 + { + var magnitude = span.L2Norm(); + if (magnitude == T.Zero) { + var ret = Allocate((uint)span.Length, false); + span.CopyTo(ret.Span); + return ret; + } + return span.Multiply(T.One / magnitude); + } + + public static MemoryOwner ManhattanNormalize(this ReadOnlySpan span) + where T : unmanaged, IBinaryFloatingPointIeee754 + { + var magnitude = span.L1Norm(); + if (magnitude == T.Zero) { + var ret = Allocate((uint)span.Length, false); + span.CopyTo(ret.Span); + return ret; + } + return span.Multiply(T.One / magnitude); + } + /// /// Creates a read only vector from the span /// diff --git a/BrightData/ExtensionMethods.TensorSegment.cs b/BrightData/ExtensionMethods.TensorSegment.cs index 0fa60106..b227dd6d 100644 --- a/BrightData/ExtensionMethods.TensorSegment.cs +++ b/BrightData/ExtensionMethods.TensorSegment.cs @@ -618,30 +618,11 @@ public static ReadOnlyMemory GetMemory(this IReadOnlyNumericSegment seg ; } - class MaxComparer : IComparer - where T : unmanaged, INumber, IComparable - { - public int Compare(T x, T y) => y.CompareTo(x); - } - class MinComparer : IComparer - where T : unmanaged, INumber, IComparable - { - public int Compare(T x, T y) => x.CompareTo(y); - } - - public static PriorityQueue RankedIndices(this IReadOnlyNumericSegment segment, uint count, bool ascending = true) + public static AT NIndices(this IReadOnlyNumericSegment segment) where T : unmanaged, INumber + where AT: IFixedSizeSortedArray, new() { - var ret = new PriorityQueue(ascending ? new MaxComparer() : new MinComparer()); - segment.ApplyReadOnlySpan(x => { - for (int i = 0, len = x.Length; i < len; i++) { - if (ret.Count < count) - ret.Enqueue((uint)i, x[i]); - else - ret.EnqueueDequeue((uint)i, x[i]); - } - }); - return ret; + return segment.ApplyReadOnlySpan(x => x.NIndices()); } } } diff --git a/BrightData/Interfaces.cs b/BrightData/Interfaces.cs index c5bf4f6c..8b9cde82 100644 --- a/BrightData/Interfaces.cs +++ b/BrightData/Interfaces.cs @@ -562,4 +562,80 @@ internal interface ISimpleNumericAnalysis : IOperation public double MinValue { get; } public double MaxValue { get; } } + + /// + /// Fixed size sorted array of values and weights + /// + /// Type of value to store + /// Type of weight that will be used to sort + public interface IFixedSizeSortedArray : IHaveSize + { + /// + /// Maximum number of elements that can fit in the array + /// + byte MaxSize { get; } + + /// + /// Current number of elements + /// + new byte Size { get; } + uint IHaveSize.Size => Size; + + /// + /// Sorted list of values + /// + ReadOnlySpan Values { get; } + + /// + /// Sorted list of weights + /// + ReadOnlySpan Weights { get; } + + /// + /// The smallest weight + /// + W MinWeight { get; } + + /// + /// The largest weight + /// + W MaxWeight { get; } + + /// + /// The value with the smallest weight + /// + V? MinValue { get; } + + /// + /// The value with the largest weight + /// + V? MaxValue { get; } + + /// + /// Returns a value and weight + /// + /// Index to return + (V Value, W Weight) this[byte index] { get; } + + /// + /// Enumerates the values and weights + /// + IEnumerable<(V Value, W Weight)> Elements { get; } + + /// + /// Tries to add a new element - will succeed if there aren't already max elements with a smaller weight + /// + /// Value to add + /// Weight to add + /// True if values should be unique - will return false if the value already exists + /// True if the element was added + bool TryAdd(V value, W weight, bool enforceUnique = true); + + /// + /// Removes an element from the array + /// + /// Index of element to remove + /// + void RemoveAt(byte index); + } } diff --git a/BrightData/LinearAlgebra/VectorIndexing/Helper/IndexedFixedSizeGraphNode.cs b/BrightData/LinearAlgebra/VectorIndexing/Helper/IndexedFixedSizeGraphNode.cs index b9f9365a..a1e8075f 100644 --- a/BrightData/LinearAlgebra/VectorIndexing/Helper/IndexedFixedSizeGraphNode.cs +++ b/BrightData/LinearAlgebra/VectorIndexing/Helper/IndexedFixedSizeGraphNode.cs @@ -3,161 +3,80 @@ using System.Numerics; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; +using BrightData.Types; namespace BrightData.LinearAlgebra.VectorIndexing.Helper { /// /// Fixed size indexed graph node that maintains weighted list of neighbours as a max heap /// - /// + /// Weight type + /// Array type /// - public record struct IndexedFixedSizeGraphNode(uint Index) + public record struct IndexedFixedSizeGraphNode(uint Index) where T : unmanaged, INumber, IMinMaxValue + where AT: struct, IFixedSizeSortedArray { + AT _neighbours = new(); + /// /// Max number of neighbours /// - public const int MaxNeighbours = 8; - [InlineArray(MaxNeighbours)] - internal struct IndexFixedSize - { - public uint _element0; - } - [InlineArray(MaxNeighbours)] - internal struct WeightFixedSize - { - public T _element0; - } - readonly IndexFixedSize _neighbourIndices = new(); - readonly WeightFixedSize _neighbourWeights = new(); + public int MaxNeighbours => _neighbours.MaxSize; /// /// Current number of neighbours /// - public byte NeighbourCount { get; private set; } = 0; + public byte NeighbourCount => _neighbours.Size; /// /// The smallest neighbour weight /// - public readonly T MinWeight => NeighbourCount > 0 ? NeighbourWeights[0] : T.MaxValue; + public T MinWeight => _neighbours.MinWeight; /// /// The largest neighbour weight /// - public readonly T MaxWeight => NeighbourCount > 0 ? NeighbourWeights[NeighbourCount - 1] : T.MinValue; + public T MaxWeight => _neighbours.MaxWeight; /// /// The index of the neighbour with the smallest weight /// - public readonly uint MinNeighbourIndex => NeighbourCount > 0 ? NeighbourIndices[0] : uint.MaxValue; + public uint MinNeighbourIndex => _neighbours.MinValue; /// /// The index of the neighbour with the largest weight /// - public readonly uint MaxNeighbourIndex => NeighbourCount > 0 ? NeighbourIndices[NeighbourCount - 1] : uint.MaxValue; + public uint MaxNeighbourIndex => _neighbours.MaxValue; /// /// Tries to add a new neighbour - will succeed if there aren't already max neighbours with a smaller weight /// /// /// + /// /// - public bool TryAddNeighbour(uint neighbourIndex, T neighbourWeight) - { - var isFull = NeighbourCount == MaxNeighbours; - var indices = MemoryMarshal.CreateSpan(ref Unsafe.As(ref Unsafe.AsRef(in _neighbourIndices)), MaxNeighbours); - var weights = MemoryMarshal.CreateSpan(ref Unsafe.As(ref Unsafe.AsRef(in _neighbourWeights)), MaxNeighbours); - - // check to see if it should be inserted - if (isFull && weights[NeighbourCount - 1] <= neighbourWeight) - return false; - - // Use binary search to find the insertion position - int left = 0, - right = NeighbourCount - 1, - insertPosition = NeighbourCount - ; - while (left <= right) { - var mid = left + (right - left) / 2; - if (weights[mid] > neighbourWeight) { - insertPosition = mid; - right = mid - 1; - } - else if (weights[mid] < neighbourWeight) { - left = mid + 1; - } - else { - // Check if the neighbour already exists - if (indices[mid] == neighbourIndex) - return false; - - left = mid + 1; - } - } - - // Check if the neighbour already exists in the left partition - for (var i = insertPosition-1; i >= 0; i--) { - if (weights[i] < neighbourWeight) - break; - if (indices[i] == neighbourIndex) - return false; - } - - if (insertPosition == NeighbourCount) { - // there is no room left - if (isFull) - return false; - } - else { - // shuffle to make room - for (var i = NeighbourCount - (isFull ? 2 : 1); i >= insertPosition; i--) { - indices[i + 1] = indices[i]; - weights[i + 1] = weights[i]; - } - } - - // insert the item - indices[insertPosition] = neighbourIndex; - weights[insertPosition] = neighbourWeight; - if (!isFull) - ++NeighbourCount; - return true; - } + public bool TryAddNeighbour(uint neighbourIndex, T neighbourWeight, bool enforceUnique = true) => _neighbours.TryAdd(neighbourIndex, neighbourWeight, enforceUnique); /// /// Sorted list of neighbour indices /// - public readonly ReadOnlySpan NeighbourIndices => MemoryMarshal.CreateReadOnlySpan(ref Unsafe.As(ref Unsafe.AsRef(in _neighbourIndices)), NeighbourCount); + public ReadOnlySpan NeighbourIndices => _neighbours.Values; /// /// Sorted list of neighbour weights /// - public readonly ReadOnlySpan NeighbourWeights => MemoryMarshal.CreateReadOnlySpan(ref Unsafe.As(ref Unsafe.AsRef(in _neighbourWeights)), NeighbourCount); + public ReadOnlySpan NeighbourWeights => _neighbours.Weights; /// /// Returns a neighbour weight /// /// - public readonly (uint NeighbourIndex, T NeighbourWeight) this[byte index] - { - get - { - if (index < NeighbourCount) - return (NeighbourIndices[index], NeighbourWeights[index]); - return (uint.MaxValue, T.MinValue); - } - } + public (uint NeighbourIndex, T NeighbourWeight) this[byte index] => _neighbours[index]; /// /// Enumerates the weighted neighbours /// - public readonly IEnumerable<(uint NeighbourIndex, T NeighbourWeight)> WeightedNeighbours - { - get - { - for (byte i = 0; i < NeighbourCount; i++) - yield return this[i]; - } - } + public IEnumerable<(uint NeighbourIndex, T NeighbourWeight)> WeightedNeighbours => _neighbours.Elements; } } diff --git a/BrightData/LinearAlgebra/VectorIndexing/Helper/VectorGraph.cs b/BrightData/LinearAlgebra/VectorIndexing/Helper/VectorGraph.cs index 3fcb5d3f..48defe3b 100644 --- a/BrightData/LinearAlgebra/VectorIndexing/Helper/VectorGraph.cs +++ b/BrightData/LinearAlgebra/VectorIndexing/Helper/VectorGraph.cs @@ -4,6 +4,7 @@ using System.Numerics; using System.Runtime.CompilerServices; using System.Threading.Tasks; +using BrightData.Types; using CommunityToolkit.HighPerformance; namespace BrightData.LinearAlgebra.VectorIndexing.Helper @@ -15,13 +16,13 @@ namespace BrightData.LinearAlgebra.VectorIndexing.Helper public class VectorGraph : IHaveSize where T : unmanaged, IBinaryFloatingPointIeee754, IMinMaxValue { - readonly IndexedFixedSizeGraphNode[] _nodes; + readonly IndexedFixedSizeGraphNode>[] _nodes; /// /// Creates a vector graph from an array of nodes /// /// - public VectorGraph(IndexedFixedSizeGraphNode[] nodes) + public VectorGraph(IndexedFixedSizeGraphNode>[] nodes) { _nodes = nodes; } @@ -72,13 +73,13 @@ public static unsafe VectorGraph Build( ? stackalloc T[(int)size] : new T[size]; - var ret = GC.AllocateUninitializedArray>((int)size); + var ret = GC.AllocateUninitializedArray>>((int)size); for (var i = 0U; i < size; i++) ret[i] = new(i); for (var i = 0U; i < size; i++) { - if (shortCircuitIfNodeNeighboursAreFull && ret[i].NeighbourCount == IndexedFixedSizeGraphNode.MaxNeighbours) + if (shortCircuitIfNodeNeighboursAreFull && ret[i].NeighbourCount == FixedSizeSortedAscending8Array.MaxSize) continue; // find the distance between this node and each of its neighbours @@ -94,7 +95,7 @@ public static unsafe VectorGraph Build( } // find top N closest neighbours - var maxHeap = new IndexedFixedSizeGraphNode(); + var maxHeap = new IndexedFixedSizeGraphNode>(); for (var j = 0; j < size; j++) { if (i == j) continue; @@ -132,7 +133,7 @@ public async Task WriteToDisk(string filePath) public static async Task> LoadFromDisk(string filePath) { using var fileHandle = File.OpenHandle(filePath); - var ret = GC.AllocateUninitializedArray>((int)(RandomAccess.GetLength(fileHandle) / Unsafe.SizeOf>())); + var ret = GC.AllocateUninitializedArray>>((int)(RandomAccess.GetLength(fileHandle) / Unsafe.SizeOf>>())); await RandomAccess.ReadAsync(fileHandle, ret.AsMemory().AsBytes(), 0); return new(ret); } diff --git a/BrightData/Types/FixedSizeSortedArray/FixedSizeSortedArray.cs b/BrightData/Types/FixedSizeSortedArray/FixedSizeSortedArray.cs new file mode 100644 index 00000000..4fa415d1 --- /dev/null +++ b/BrightData/Types/FixedSizeSortedArray/FixedSizeSortedArray.cs @@ -0,0 +1,7481 @@ +using System; +using System.Numerics; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Collections.Generic; +using BrightData.Types.FixedSizeSortedArray; + +namespace BrightData.Types +{ + /// + /// Fixed size sorted array of values and weights (max 2 elements) + /// that is sorted in ascending order based on each weight + /// + /// Type of value to store + /// Type of weight that will be used to sort + public record struct FixedSizeSortedAscending2Array() : IFixedSizeSortedArray + where V : IComparable + where W : unmanaged, INumber, IMinMaxValue + { + /// + /// Max size of the array + /// + public const int MaxSize = 2; + byte IFixedSizeSortedArray.MaxSize => MaxSize; + + [InlineArray(MaxSize)] + internal struct ValueArray + { + public V _element0; + } + [InlineArray(MaxSize)] + internal struct WeightArray + { + public W _element0; + } + readonly ValueArray _values = new(); + readonly WeightArray _weights = new(); + byte _size = 0; + + /// + /// Current number of elements + /// + public readonly byte Size => _size; + + /// + /// Sorted list of values + /// + public readonly ReadOnlySpan Values => MemoryMarshal.CreateReadOnlySpan(ref Unsafe.As(ref Unsafe.AsRef(in _values)), _size); + + /// + /// Sorted list of weights + /// + public readonly ReadOnlySpan Weights => MemoryMarshal.CreateReadOnlySpan(ref Unsafe.As(ref Unsafe.AsRef(in _weights)), _size); + + /// + /// The smallest weight + /// + public readonly W MinWeight => _size > 0 ? Weights[0] : W.MaxValue; + + /// + /// The largest weight + /// + public readonly W MaxWeight => _size > 0 ? Weights[_size - 1] : W.MinValue; + + /// + /// The value with the smallest weight + /// + public readonly V? MinValue => _size > 0 ? Values[0] : default; + + /// + /// The value with the largest weight + /// + public readonly V? MaxValue => _size > 0 ? Values[_size - 1] : default; + + /// + /// Returns a value and weight + /// + /// Index to return + public readonly (V Value, W Weight) this[byte index] + { + get + { + if (index < Size) + return (Values[index], Weights[index]); + throw new ArgumentOutOfRangeException(); + } + } + + /// + /// Enumerates the values and weights + /// + public readonly IEnumerable<(V Value, W Weight)> Elements + { + get + { + for (byte i = 0; i < Size; i++) + yield return this[i]; + } + } + + /// + /// Tries to add a new element - will succeed if there aren't already max elements with a smaller weight + /// + /// Value to add + /// Weight to add + /// True if values should be unique - will return false if the value already exists + /// True if the element was added + public bool TryAdd(V value, W weight, bool enforceUnique = true) + { + var values = MemoryMarshal.CreateSpan(ref Unsafe.As(ref Unsafe.AsRef(in _values)), MaxSize); + var weights = MemoryMarshal.CreateSpan(ref Unsafe.As(ref Unsafe.AsRef(in _weights)), MaxSize); + return FixedSizeSortedArrayHelper.InsertIntoAscending(enforceUnique, ref _size, MaxSize, value, weight, values, weights); + } + + /// + /// Removes an element from the array + /// + /// Index of element to remove + /// + public void RemoveAt(byte index) + { + if(index >= _size) + throw new ArgumentOutOfRangeException(); + var values = MemoryMarshal.CreateSpan(ref Unsafe.As(ref Unsafe.AsRef(in _values)), _size); + var weights = MemoryMarshal.CreateSpan(ref Unsafe.As(ref Unsafe.AsRef(in _weights)), _size); + FixedSizeSortedArrayHelper.RemoveAt(index, values, weights); + --_size; + } + } + + /// + /// Fixed size sorted array of values and weights (max 2 elements) + /// that is sorted in descending order based on each weight + /// + /// Type of value to store + /// Type of weight that will be used to sort + public record struct FixedSizeSortedDescending2Array() + where V : IComparable + where W : unmanaged, INumber, IMinMaxValue + { + /// + /// Max size of the array + /// + public const int MaxSize = 2; + + [InlineArray(MaxSize)] + internal struct ValueArray + { + public V _element0; + } + [InlineArray(MaxSize)] + internal struct WeightArray + { + public W _element0; + } + readonly ValueArray _values = new(); + readonly WeightArray _weights = new(); + byte _size = 0; + + /// + /// Current number of elements + /// + public readonly byte Size => _size; + + /// + /// Sorted list of values + /// + public readonly ReadOnlySpan Values => MemoryMarshal.CreateReadOnlySpan(ref Unsafe.As(ref Unsafe.AsRef(in _values)), _size); + + /// + /// Sorted list of weights + /// + public readonly ReadOnlySpan Weights => MemoryMarshal.CreateReadOnlySpan(ref Unsafe.As(ref Unsafe.AsRef(in _weights)), _size); + + /// + /// The smallest weight + /// + public readonly W MinWeight => _size > 0 ? Weights[_size - 1] : W.MaxValue; + + /// + /// The largest weight + /// + public readonly W MaxWeight => _size > 0 ? Weights[0] : W.MinValue; + + /// + /// The value with the smallest weight + /// + public readonly V? MinValue => _size > 0 ? Values[_size - 1] : default; + + /// + /// The value with the largest weight + /// + public readonly V? MaxValue => _size > 0 ? Values[0] : default; + + /// + /// Returns a value and weight + /// + /// Index to return + public readonly (V Value, W Weight) this[byte index] + { + get + { + if (index < Size) + return (Values[index], Weights[index]); + throw new ArgumentOutOfRangeException(); + } + } + + /// + /// Enumerates the values and weights + /// + public readonly IEnumerable<(V Value, W Weight)> Elements + { + get + { + for (byte i = 0; i < Size; i++) + yield return this[i]; + } + } + + /// + /// Tries to add a new element - will succeed if there aren't already max elements with a smaller weight + /// + /// Value to add + /// Weight to add + /// True if values should be unique - will return false if the value already exists + /// True if the element was added + public bool TryAdd(V value, W weight, bool enforceUnique = true) + { + var values = MemoryMarshal.CreateSpan(ref Unsafe.As(ref Unsafe.AsRef(in _values)), MaxSize); + var weights = MemoryMarshal.CreateSpan(ref Unsafe.As(ref Unsafe.AsRef(in _weights)), MaxSize); + return FixedSizeSortedArrayHelper.InsertIntoDescending(enforceUnique, ref _size, MaxSize, value, weight, values, weights); + } + + /// + /// Removes an element from the array + /// + /// Index of element to remove + /// + public void RemoveAt(byte index) + { + if(index >= _size) + throw new ArgumentOutOfRangeException(); + var values = MemoryMarshal.CreateSpan(ref Unsafe.As(ref Unsafe.AsRef(in _values)), _size); + var weights = MemoryMarshal.CreateSpan(ref Unsafe.As(ref Unsafe.AsRef(in _weights)), _size); + FixedSizeSortedArrayHelper.RemoveAt(index, values, weights); + --_size; + } + } + + /// + /// Fixed size sorted array of values and weights (max 3 elements) + /// that is sorted in ascending order based on each weight + /// + /// Type of value to store + /// Type of weight that will be used to sort + public record struct FixedSizeSortedAscending3Array() : IFixedSizeSortedArray + where V : IComparable + where W : unmanaged, INumber, IMinMaxValue + { + /// + /// Max size of the array + /// + public const int MaxSize = 3; + byte IFixedSizeSortedArray.MaxSize => MaxSize; + + [InlineArray(MaxSize)] + internal struct ValueArray + { + public V _element0; + } + [InlineArray(MaxSize)] + internal struct WeightArray + { + public W _element0; + } + readonly ValueArray _values = new(); + readonly WeightArray _weights = new(); + byte _size = 0; + + /// + /// Current number of elements + /// + public readonly byte Size => _size; + + /// + /// Sorted list of values + /// + public readonly ReadOnlySpan Values => MemoryMarshal.CreateReadOnlySpan(ref Unsafe.As(ref Unsafe.AsRef(in _values)), _size); + + /// + /// Sorted list of weights + /// + public readonly ReadOnlySpan Weights => MemoryMarshal.CreateReadOnlySpan(ref Unsafe.As(ref Unsafe.AsRef(in _weights)), _size); + + /// + /// The smallest weight + /// + public readonly W MinWeight => _size > 0 ? Weights[0] : W.MaxValue; + + /// + /// The largest weight + /// + public readonly W MaxWeight => _size > 0 ? Weights[_size - 1] : W.MinValue; + + /// + /// The value with the smallest weight + /// + public readonly V? MinValue => _size > 0 ? Values[0] : default; + + /// + /// The value with the largest weight + /// + public readonly V? MaxValue => _size > 0 ? Values[_size - 1] : default; + + /// + /// Returns a value and weight + /// + /// Index to return + public readonly (V Value, W Weight) this[byte index] + { + get + { + if (index < Size) + return (Values[index], Weights[index]); + throw new ArgumentOutOfRangeException(); + } + } + + /// + /// Enumerates the values and weights + /// + public readonly IEnumerable<(V Value, W Weight)> Elements + { + get + { + for (byte i = 0; i < Size; i++) + yield return this[i]; + } + } + + /// + /// Tries to add a new element - will succeed if there aren't already max elements with a smaller weight + /// + /// Value to add + /// Weight to add + /// True if values should be unique - will return false if the value already exists + /// True if the element was added + public bool TryAdd(V value, W weight, bool enforceUnique = true) + { + var values = MemoryMarshal.CreateSpan(ref Unsafe.As(ref Unsafe.AsRef(in _values)), MaxSize); + var weights = MemoryMarshal.CreateSpan(ref Unsafe.As(ref Unsafe.AsRef(in _weights)), MaxSize); + return FixedSizeSortedArrayHelper.InsertIntoAscending(enforceUnique, ref _size, MaxSize, value, weight, values, weights); + } + + /// + /// Removes an element from the array + /// + /// Index of element to remove + /// + public void RemoveAt(byte index) + { + if(index >= _size) + throw new ArgumentOutOfRangeException(); + var values = MemoryMarshal.CreateSpan(ref Unsafe.As(ref Unsafe.AsRef(in _values)), _size); + var weights = MemoryMarshal.CreateSpan(ref Unsafe.As(ref Unsafe.AsRef(in _weights)), _size); + FixedSizeSortedArrayHelper.RemoveAt(index, values, weights); + --_size; + } + } + + /// + /// Fixed size sorted array of values and weights (max 3 elements) + /// that is sorted in descending order based on each weight + /// + /// Type of value to store + /// Type of weight that will be used to sort + public record struct FixedSizeSortedDescending3Array() + where V : IComparable + where W : unmanaged, INumber, IMinMaxValue + { + /// + /// Max size of the array + /// + public const int MaxSize = 3; + + [InlineArray(MaxSize)] + internal struct ValueArray + { + public V _element0; + } + [InlineArray(MaxSize)] + internal struct WeightArray + { + public W _element0; + } + readonly ValueArray _values = new(); + readonly WeightArray _weights = new(); + byte _size = 0; + + /// + /// Current number of elements + /// + public readonly byte Size => _size; + + /// + /// Sorted list of values + /// + public readonly ReadOnlySpan Values => MemoryMarshal.CreateReadOnlySpan(ref Unsafe.As(ref Unsafe.AsRef(in _values)), _size); + + /// + /// Sorted list of weights + /// + public readonly ReadOnlySpan Weights => MemoryMarshal.CreateReadOnlySpan(ref Unsafe.As(ref Unsafe.AsRef(in _weights)), _size); + + /// + /// The smallest weight + /// + public readonly W MinWeight => _size > 0 ? Weights[_size - 1] : W.MaxValue; + + /// + /// The largest weight + /// + public readonly W MaxWeight => _size > 0 ? Weights[0] : W.MinValue; + + /// + /// The value with the smallest weight + /// + public readonly V? MinValue => _size > 0 ? Values[_size - 1] : default; + + /// + /// The value with the largest weight + /// + public readonly V? MaxValue => _size > 0 ? Values[0] : default; + + /// + /// Returns a value and weight + /// + /// Index to return + public readonly (V Value, W Weight) this[byte index] + { + get + { + if (index < Size) + return (Values[index], Weights[index]); + throw new ArgumentOutOfRangeException(); + } + } + + /// + /// Enumerates the values and weights + /// + public readonly IEnumerable<(V Value, W Weight)> Elements + { + get + { + for (byte i = 0; i < Size; i++) + yield return this[i]; + } + } + + /// + /// Tries to add a new element - will succeed if there aren't already max elements with a smaller weight + /// + /// Value to add + /// Weight to add + /// True if values should be unique - will return false if the value already exists + /// True if the element was added + public bool TryAdd(V value, W weight, bool enforceUnique = true) + { + var values = MemoryMarshal.CreateSpan(ref Unsafe.As(ref Unsafe.AsRef(in _values)), MaxSize); + var weights = MemoryMarshal.CreateSpan(ref Unsafe.As(ref Unsafe.AsRef(in _weights)), MaxSize); + return FixedSizeSortedArrayHelper.InsertIntoDescending(enforceUnique, ref _size, MaxSize, value, weight, values, weights); + } + + /// + /// Removes an element from the array + /// + /// Index of element to remove + /// + public void RemoveAt(byte index) + { + if(index >= _size) + throw new ArgumentOutOfRangeException(); + var values = MemoryMarshal.CreateSpan(ref Unsafe.As(ref Unsafe.AsRef(in _values)), _size); + var weights = MemoryMarshal.CreateSpan(ref Unsafe.As(ref Unsafe.AsRef(in _weights)), _size); + FixedSizeSortedArrayHelper.RemoveAt(index, values, weights); + --_size; + } + } + + /// + /// Fixed size sorted array of values and weights (max 4 elements) + /// that is sorted in ascending order based on each weight + /// + /// Type of value to store + /// Type of weight that will be used to sort + public record struct FixedSizeSortedAscending4Array() : IFixedSizeSortedArray + where V : IComparable + where W : unmanaged, INumber, IMinMaxValue + { + /// + /// Max size of the array + /// + public const int MaxSize = 4; + byte IFixedSizeSortedArray.MaxSize => MaxSize; + + [InlineArray(MaxSize)] + internal struct ValueArray + { + public V _element0; + } + [InlineArray(MaxSize)] + internal struct WeightArray + { + public W _element0; + } + readonly ValueArray _values = new(); + readonly WeightArray _weights = new(); + byte _size = 0; + + /// + /// Current number of elements + /// + public readonly byte Size => _size; + + /// + /// Sorted list of values + /// + public readonly ReadOnlySpan Values => MemoryMarshal.CreateReadOnlySpan(ref Unsafe.As(ref Unsafe.AsRef(in _values)), _size); + + /// + /// Sorted list of weights + /// + public readonly ReadOnlySpan Weights => MemoryMarshal.CreateReadOnlySpan(ref Unsafe.As(ref Unsafe.AsRef(in _weights)), _size); + + /// + /// The smallest weight + /// + public readonly W MinWeight => _size > 0 ? Weights[0] : W.MaxValue; + + /// + /// The largest weight + /// + public readonly W MaxWeight => _size > 0 ? Weights[_size - 1] : W.MinValue; + + /// + /// The value with the smallest weight + /// + public readonly V? MinValue => _size > 0 ? Values[0] : default; + + /// + /// The value with the largest weight + /// + public readonly V? MaxValue => _size > 0 ? Values[_size - 1] : default; + + /// + /// Returns a value and weight + /// + /// Index to return + public readonly (V Value, W Weight) this[byte index] + { + get + { + if (index < Size) + return (Values[index], Weights[index]); + throw new ArgumentOutOfRangeException(); + } + } + + /// + /// Enumerates the values and weights + /// + public readonly IEnumerable<(V Value, W Weight)> Elements + { + get + { + for (byte i = 0; i < Size; i++) + yield return this[i]; + } + } + + /// + /// Tries to add a new element - will succeed if there aren't already max elements with a smaller weight + /// + /// Value to add + /// Weight to add + /// True if values should be unique - will return false if the value already exists + /// True if the element was added + public bool TryAdd(V value, W weight, bool enforceUnique = true) + { + var values = MemoryMarshal.CreateSpan(ref Unsafe.As(ref Unsafe.AsRef(in _values)), MaxSize); + var weights = MemoryMarshal.CreateSpan(ref Unsafe.As(ref Unsafe.AsRef(in _weights)), MaxSize); + return FixedSizeSortedArrayHelper.InsertIntoAscending(enforceUnique, ref _size, MaxSize, value, weight, values, weights); + } + + /// + /// Removes an element from the array + /// + /// Index of element to remove + /// + public void RemoveAt(byte index) + { + if(index >= _size) + throw new ArgumentOutOfRangeException(); + var values = MemoryMarshal.CreateSpan(ref Unsafe.As(ref Unsafe.AsRef(in _values)), _size); + var weights = MemoryMarshal.CreateSpan(ref Unsafe.As(ref Unsafe.AsRef(in _weights)), _size); + FixedSizeSortedArrayHelper.RemoveAt(index, values, weights); + --_size; + } + } + + /// + /// Fixed size sorted array of values and weights (max 4 elements) + /// that is sorted in descending order based on each weight + /// + /// Type of value to store + /// Type of weight that will be used to sort + public record struct FixedSizeSortedDescending4Array() + where V : IComparable + where W : unmanaged, INumber, IMinMaxValue + { + /// + /// Max size of the array + /// + public const int MaxSize = 4; + + [InlineArray(MaxSize)] + internal struct ValueArray + { + public V _element0; + } + [InlineArray(MaxSize)] + internal struct WeightArray + { + public W _element0; + } + readonly ValueArray _values = new(); + readonly WeightArray _weights = new(); + byte _size = 0; + + /// + /// Current number of elements + /// + public readonly byte Size => _size; + + /// + /// Sorted list of values + /// + public readonly ReadOnlySpan Values => MemoryMarshal.CreateReadOnlySpan(ref Unsafe.As(ref Unsafe.AsRef(in _values)), _size); + + /// + /// Sorted list of weights + /// + public readonly ReadOnlySpan Weights => MemoryMarshal.CreateReadOnlySpan(ref Unsafe.As(ref Unsafe.AsRef(in _weights)), _size); + + /// + /// The smallest weight + /// + public readonly W MinWeight => _size > 0 ? Weights[_size - 1] : W.MaxValue; + + /// + /// The largest weight + /// + public readonly W MaxWeight => _size > 0 ? Weights[0] : W.MinValue; + + /// + /// The value with the smallest weight + /// + public readonly V? MinValue => _size > 0 ? Values[_size - 1] : default; + + /// + /// The value with the largest weight + /// + public readonly V? MaxValue => _size > 0 ? Values[0] : default; + + /// + /// Returns a value and weight + /// + /// Index to return + public readonly (V Value, W Weight) this[byte index] + { + get + { + if (index < Size) + return (Values[index], Weights[index]); + throw new ArgumentOutOfRangeException(); + } + } + + /// + /// Enumerates the values and weights + /// + public readonly IEnumerable<(V Value, W Weight)> Elements + { + get + { + for (byte i = 0; i < Size; i++) + yield return this[i]; + } + } + + /// + /// Tries to add a new element - will succeed if there aren't already max elements with a smaller weight + /// + /// Value to add + /// Weight to add + /// True if values should be unique - will return false if the value already exists + /// True if the element was added + public bool TryAdd(V value, W weight, bool enforceUnique = true) + { + var values = MemoryMarshal.CreateSpan(ref Unsafe.As(ref Unsafe.AsRef(in _values)), MaxSize); + var weights = MemoryMarshal.CreateSpan(ref Unsafe.As(ref Unsafe.AsRef(in _weights)), MaxSize); + return FixedSizeSortedArrayHelper.InsertIntoDescending(enforceUnique, ref _size, MaxSize, value, weight, values, weights); + } + + /// + /// Removes an element from the array + /// + /// Index of element to remove + /// + public void RemoveAt(byte index) + { + if(index >= _size) + throw new ArgumentOutOfRangeException(); + var values = MemoryMarshal.CreateSpan(ref Unsafe.As(ref Unsafe.AsRef(in _values)), _size); + var weights = MemoryMarshal.CreateSpan(ref Unsafe.As(ref Unsafe.AsRef(in _weights)), _size); + FixedSizeSortedArrayHelper.RemoveAt(index, values, weights); + --_size; + } + } + + /// + /// Fixed size sorted array of values and weights (max 5 elements) + /// that is sorted in ascending order based on each weight + /// + /// Type of value to store + /// Type of weight that will be used to sort + public record struct FixedSizeSortedAscending5Array() : IFixedSizeSortedArray + where V : IComparable + where W : unmanaged, INumber, IMinMaxValue + { + /// + /// Max size of the array + /// + public const int MaxSize = 5; + byte IFixedSizeSortedArray.MaxSize => MaxSize; + + [InlineArray(MaxSize)] + internal struct ValueArray + { + public V _element0; + } + [InlineArray(MaxSize)] + internal struct WeightArray + { + public W _element0; + } + readonly ValueArray _values = new(); + readonly WeightArray _weights = new(); + byte _size = 0; + + /// + /// Current number of elements + /// + public readonly byte Size => _size; + + /// + /// Sorted list of values + /// + public readonly ReadOnlySpan Values => MemoryMarshal.CreateReadOnlySpan(ref Unsafe.As(ref Unsafe.AsRef(in _values)), _size); + + /// + /// Sorted list of weights + /// + public readonly ReadOnlySpan Weights => MemoryMarshal.CreateReadOnlySpan(ref Unsafe.As(ref Unsafe.AsRef(in _weights)), _size); + + /// + /// The smallest weight + /// + public readonly W MinWeight => _size > 0 ? Weights[0] : W.MaxValue; + + /// + /// The largest weight + /// + public readonly W MaxWeight => _size > 0 ? Weights[_size - 1] : W.MinValue; + + /// + /// The value with the smallest weight + /// + public readonly V? MinValue => _size > 0 ? Values[0] : default; + + /// + /// The value with the largest weight + /// + public readonly V? MaxValue => _size > 0 ? Values[_size - 1] : default; + + /// + /// Returns a value and weight + /// + /// Index to return + public readonly (V Value, W Weight) this[byte index] + { + get + { + if (index < Size) + return (Values[index], Weights[index]); + throw new ArgumentOutOfRangeException(); + } + } + + /// + /// Enumerates the values and weights + /// + public readonly IEnumerable<(V Value, W Weight)> Elements + { + get + { + for (byte i = 0; i < Size; i++) + yield return this[i]; + } + } + + /// + /// Tries to add a new element - will succeed if there aren't already max elements with a smaller weight + /// + /// Value to add + /// Weight to add + /// True if values should be unique - will return false if the value already exists + /// True if the element was added + public bool TryAdd(V value, W weight, bool enforceUnique = true) + { + var values = MemoryMarshal.CreateSpan(ref Unsafe.As(ref Unsafe.AsRef(in _values)), MaxSize); + var weights = MemoryMarshal.CreateSpan(ref Unsafe.As(ref Unsafe.AsRef(in _weights)), MaxSize); + return FixedSizeSortedArrayHelper.InsertIntoAscending(enforceUnique, ref _size, MaxSize, value, weight, values, weights); + } + + /// + /// Removes an element from the array + /// + /// Index of element to remove + /// + public void RemoveAt(byte index) + { + if(index >= _size) + throw new ArgumentOutOfRangeException(); + var values = MemoryMarshal.CreateSpan(ref Unsafe.As(ref Unsafe.AsRef(in _values)), _size); + var weights = MemoryMarshal.CreateSpan(ref Unsafe.As(ref Unsafe.AsRef(in _weights)), _size); + FixedSizeSortedArrayHelper.RemoveAt(index, values, weights); + --_size; + } + } + + /// + /// Fixed size sorted array of values and weights (max 5 elements) + /// that is sorted in descending order based on each weight + /// + /// Type of value to store + /// Type of weight that will be used to sort + public record struct FixedSizeSortedDescending5Array() + where V : IComparable + where W : unmanaged, INumber, IMinMaxValue + { + /// + /// Max size of the array + /// + public const int MaxSize = 5; + + [InlineArray(MaxSize)] + internal struct ValueArray + { + public V _element0; + } + [InlineArray(MaxSize)] + internal struct WeightArray + { + public W _element0; + } + readonly ValueArray _values = new(); + readonly WeightArray _weights = new(); + byte _size = 0; + + /// + /// Current number of elements + /// + public readonly byte Size => _size; + + /// + /// Sorted list of values + /// + public readonly ReadOnlySpan Values => MemoryMarshal.CreateReadOnlySpan(ref Unsafe.As(ref Unsafe.AsRef(in _values)), _size); + + /// + /// Sorted list of weights + /// + public readonly ReadOnlySpan Weights => MemoryMarshal.CreateReadOnlySpan(ref Unsafe.As(ref Unsafe.AsRef(in _weights)), _size); + + /// + /// The smallest weight + /// + public readonly W MinWeight => _size > 0 ? Weights[_size - 1] : W.MaxValue; + + /// + /// The largest weight + /// + public readonly W MaxWeight => _size > 0 ? Weights[0] : W.MinValue; + + /// + /// The value with the smallest weight + /// + public readonly V? MinValue => _size > 0 ? Values[_size - 1] : default; + + /// + /// The value with the largest weight + /// + public readonly V? MaxValue => _size > 0 ? Values[0] : default; + + /// + /// Returns a value and weight + /// + /// Index to return + public readonly (V Value, W Weight) this[byte index] + { + get + { + if (index < Size) + return (Values[index], Weights[index]); + throw new ArgumentOutOfRangeException(); + } + } + + /// + /// Enumerates the values and weights + /// + public readonly IEnumerable<(V Value, W Weight)> Elements + { + get + { + for (byte i = 0; i < Size; i++) + yield return this[i]; + } + } + + /// + /// Tries to add a new element - will succeed if there aren't already max elements with a smaller weight + /// + /// Value to add + /// Weight to add + /// True if values should be unique - will return false if the value already exists + /// True if the element was added + public bool TryAdd(V value, W weight, bool enforceUnique = true) + { + var values = MemoryMarshal.CreateSpan(ref Unsafe.As(ref Unsafe.AsRef(in _values)), MaxSize); + var weights = MemoryMarshal.CreateSpan(ref Unsafe.As(ref Unsafe.AsRef(in _weights)), MaxSize); + return FixedSizeSortedArrayHelper.InsertIntoDescending(enforceUnique, ref _size, MaxSize, value, weight, values, weights); + } + + /// + /// Removes an element from the array + /// + /// Index of element to remove + /// + public void RemoveAt(byte index) + { + if(index >= _size) + throw new ArgumentOutOfRangeException(); + var values = MemoryMarshal.CreateSpan(ref Unsafe.As(ref Unsafe.AsRef(in _values)), _size); + var weights = MemoryMarshal.CreateSpan(ref Unsafe.As(ref Unsafe.AsRef(in _weights)), _size); + FixedSizeSortedArrayHelper.RemoveAt(index, values, weights); + --_size; + } + } + + /// + /// Fixed size sorted array of values and weights (max 6 elements) + /// that is sorted in ascending order based on each weight + /// + /// Type of value to store + /// Type of weight that will be used to sort + public record struct FixedSizeSortedAscending6Array() : IFixedSizeSortedArray + where V : IComparable + where W : unmanaged, INumber, IMinMaxValue + { + /// + /// Max size of the array + /// + public const int MaxSize = 6; + byte IFixedSizeSortedArray.MaxSize => MaxSize; + + [InlineArray(MaxSize)] + internal struct ValueArray + { + public V _element0; + } + [InlineArray(MaxSize)] + internal struct WeightArray + { + public W _element0; + } + readonly ValueArray _values = new(); + readonly WeightArray _weights = new(); + byte _size = 0; + + /// + /// Current number of elements + /// + public readonly byte Size => _size; + + /// + /// Sorted list of values + /// + public readonly ReadOnlySpan Values => MemoryMarshal.CreateReadOnlySpan(ref Unsafe.As(ref Unsafe.AsRef(in _values)), _size); + + /// + /// Sorted list of weights + /// + public readonly ReadOnlySpan Weights => MemoryMarshal.CreateReadOnlySpan(ref Unsafe.As(ref Unsafe.AsRef(in _weights)), _size); + + /// + /// The smallest weight + /// + public readonly W MinWeight => _size > 0 ? Weights[0] : W.MaxValue; + + /// + /// The largest weight + /// + public readonly W MaxWeight => _size > 0 ? Weights[_size - 1] : W.MinValue; + + /// + /// The value with the smallest weight + /// + public readonly V? MinValue => _size > 0 ? Values[0] : default; + + /// + /// The value with the largest weight + /// + public readonly V? MaxValue => _size > 0 ? Values[_size - 1] : default; + + /// + /// Returns a value and weight + /// + /// Index to return + public readonly (V Value, W Weight) this[byte index] + { + get + { + if (index < Size) + return (Values[index], Weights[index]); + throw new ArgumentOutOfRangeException(); + } + } + + /// + /// Enumerates the values and weights + /// + public readonly IEnumerable<(V Value, W Weight)> Elements + { + get + { + for (byte i = 0; i < Size; i++) + yield return this[i]; + } + } + + /// + /// Tries to add a new element - will succeed if there aren't already max elements with a smaller weight + /// + /// Value to add + /// Weight to add + /// True if values should be unique - will return false if the value already exists + /// True if the element was added + public bool TryAdd(V value, W weight, bool enforceUnique = true) + { + var values = MemoryMarshal.CreateSpan(ref Unsafe.As(ref Unsafe.AsRef(in _values)), MaxSize); + var weights = MemoryMarshal.CreateSpan(ref Unsafe.As(ref Unsafe.AsRef(in _weights)), MaxSize); + return FixedSizeSortedArrayHelper.InsertIntoAscending(enforceUnique, ref _size, MaxSize, value, weight, values, weights); + } + + /// + /// Removes an element from the array + /// + /// Index of element to remove + /// + public void RemoveAt(byte index) + { + if(index >= _size) + throw new ArgumentOutOfRangeException(); + var values = MemoryMarshal.CreateSpan(ref Unsafe.As(ref Unsafe.AsRef(in _values)), _size); + var weights = MemoryMarshal.CreateSpan(ref Unsafe.As(ref Unsafe.AsRef(in _weights)), _size); + FixedSizeSortedArrayHelper.RemoveAt(index, values, weights); + --_size; + } + } + + /// + /// Fixed size sorted array of values and weights (max 6 elements) + /// that is sorted in descending order based on each weight + /// + /// Type of value to store + /// Type of weight that will be used to sort + public record struct FixedSizeSortedDescending6Array() + where V : IComparable + where W : unmanaged, INumber, IMinMaxValue + { + /// + /// Max size of the array + /// + public const int MaxSize = 6; + + [InlineArray(MaxSize)] + internal struct ValueArray + { + public V _element0; + } + [InlineArray(MaxSize)] + internal struct WeightArray + { + public W _element0; + } + readonly ValueArray _values = new(); + readonly WeightArray _weights = new(); + byte _size = 0; + + /// + /// Current number of elements + /// + public readonly byte Size => _size; + + /// + /// Sorted list of values + /// + public readonly ReadOnlySpan Values => MemoryMarshal.CreateReadOnlySpan(ref Unsafe.As(ref Unsafe.AsRef(in _values)), _size); + + /// + /// Sorted list of weights + /// + public readonly ReadOnlySpan Weights => MemoryMarshal.CreateReadOnlySpan(ref Unsafe.As(ref Unsafe.AsRef(in _weights)), _size); + + /// + /// The smallest weight + /// + public readonly W MinWeight => _size > 0 ? Weights[_size - 1] : W.MaxValue; + + /// + /// The largest weight + /// + public readonly W MaxWeight => _size > 0 ? Weights[0] : W.MinValue; + + /// + /// The value with the smallest weight + /// + public readonly V? MinValue => _size > 0 ? Values[_size - 1] : default; + + /// + /// The value with the largest weight + /// + public readonly V? MaxValue => _size > 0 ? Values[0] : default; + + /// + /// Returns a value and weight + /// + /// Index to return + public readonly (V Value, W Weight) this[byte index] + { + get + { + if (index < Size) + return (Values[index], Weights[index]); + throw new ArgumentOutOfRangeException(); + } + } + + /// + /// Enumerates the values and weights + /// + public readonly IEnumerable<(V Value, W Weight)> Elements + { + get + { + for (byte i = 0; i < Size; i++) + yield return this[i]; + } + } + + /// + /// Tries to add a new element - will succeed if there aren't already max elements with a smaller weight + /// + /// Value to add + /// Weight to add + /// True if values should be unique - will return false if the value already exists + /// True if the element was added + public bool TryAdd(V value, W weight, bool enforceUnique = true) + { + var values = MemoryMarshal.CreateSpan(ref Unsafe.As(ref Unsafe.AsRef(in _values)), MaxSize); + var weights = MemoryMarshal.CreateSpan(ref Unsafe.As(ref Unsafe.AsRef(in _weights)), MaxSize); + return FixedSizeSortedArrayHelper.InsertIntoDescending(enforceUnique, ref _size, MaxSize, value, weight, values, weights); + } + + /// + /// Removes an element from the array + /// + /// Index of element to remove + /// + public void RemoveAt(byte index) + { + if(index >= _size) + throw new ArgumentOutOfRangeException(); + var values = MemoryMarshal.CreateSpan(ref Unsafe.As(ref Unsafe.AsRef(in _values)), _size); + var weights = MemoryMarshal.CreateSpan(ref Unsafe.As(ref Unsafe.AsRef(in _weights)), _size); + FixedSizeSortedArrayHelper.RemoveAt(index, values, weights); + --_size; + } + } + + /// + /// Fixed size sorted array of values and weights (max 7 elements) + /// that is sorted in ascending order based on each weight + /// + /// Type of value to store + /// Type of weight that will be used to sort + public record struct FixedSizeSortedAscending7Array() : IFixedSizeSortedArray + where V : IComparable + where W : unmanaged, INumber, IMinMaxValue + { + /// + /// Max size of the array + /// + public const int MaxSize = 7; + byte IFixedSizeSortedArray.MaxSize => MaxSize; + + [InlineArray(MaxSize)] + internal struct ValueArray + { + public V _element0; + } + [InlineArray(MaxSize)] + internal struct WeightArray + { + public W _element0; + } + readonly ValueArray _values = new(); + readonly WeightArray _weights = new(); + byte _size = 0; + + /// + /// Current number of elements + /// + public readonly byte Size => _size; + + /// + /// Sorted list of values + /// + public readonly ReadOnlySpan Values => MemoryMarshal.CreateReadOnlySpan(ref Unsafe.As(ref Unsafe.AsRef(in _values)), _size); + + /// + /// Sorted list of weights + /// + public readonly ReadOnlySpan Weights => MemoryMarshal.CreateReadOnlySpan(ref Unsafe.As(ref Unsafe.AsRef(in _weights)), _size); + + /// + /// The smallest weight + /// + public readonly W MinWeight => _size > 0 ? Weights[0] : W.MaxValue; + + /// + /// The largest weight + /// + public readonly W MaxWeight => _size > 0 ? Weights[_size - 1] : W.MinValue; + + /// + /// The value with the smallest weight + /// + public readonly V? MinValue => _size > 0 ? Values[0] : default; + + /// + /// The value with the largest weight + /// + public readonly V? MaxValue => _size > 0 ? Values[_size - 1] : default; + + /// + /// Returns a value and weight + /// + /// Index to return + public readonly (V Value, W Weight) this[byte index] + { + get + { + if (index < Size) + return (Values[index], Weights[index]); + throw new ArgumentOutOfRangeException(); + } + } + + /// + /// Enumerates the values and weights + /// + public readonly IEnumerable<(V Value, W Weight)> Elements + { + get + { + for (byte i = 0; i < Size; i++) + yield return this[i]; + } + } + + /// + /// Tries to add a new element - will succeed if there aren't already max elements with a smaller weight + /// + /// Value to add + /// Weight to add + /// True if values should be unique - will return false if the value already exists + /// True if the element was added + public bool TryAdd(V value, W weight, bool enforceUnique = true) + { + var values = MemoryMarshal.CreateSpan(ref Unsafe.As(ref Unsafe.AsRef(in _values)), MaxSize); + var weights = MemoryMarshal.CreateSpan(ref Unsafe.As(ref Unsafe.AsRef(in _weights)), MaxSize); + return FixedSizeSortedArrayHelper.InsertIntoAscending(enforceUnique, ref _size, MaxSize, value, weight, values, weights); + } + + /// + /// Removes an element from the array + /// + /// Index of element to remove + /// + public void RemoveAt(byte index) + { + if(index >= _size) + throw new ArgumentOutOfRangeException(); + var values = MemoryMarshal.CreateSpan(ref Unsafe.As(ref Unsafe.AsRef(in _values)), _size); + var weights = MemoryMarshal.CreateSpan(ref Unsafe.As(ref Unsafe.AsRef(in _weights)), _size); + FixedSizeSortedArrayHelper.RemoveAt(index, values, weights); + --_size; + } + } + + /// + /// Fixed size sorted array of values and weights (max 7 elements) + /// that is sorted in descending order based on each weight + /// + /// Type of value to store + /// Type of weight that will be used to sort + public record struct FixedSizeSortedDescending7Array() + where V : IComparable + where W : unmanaged, INumber, IMinMaxValue + { + /// + /// Max size of the array + /// + public const int MaxSize = 7; + + [InlineArray(MaxSize)] + internal struct ValueArray + { + public V _element0; + } + [InlineArray(MaxSize)] + internal struct WeightArray + { + public W _element0; + } + readonly ValueArray _values = new(); + readonly WeightArray _weights = new(); + byte _size = 0; + + /// + /// Current number of elements + /// + public readonly byte Size => _size; + + /// + /// Sorted list of values + /// + public readonly ReadOnlySpan Values => MemoryMarshal.CreateReadOnlySpan(ref Unsafe.As(ref Unsafe.AsRef(in _values)), _size); + + /// + /// Sorted list of weights + /// + public readonly ReadOnlySpan Weights => MemoryMarshal.CreateReadOnlySpan(ref Unsafe.As(ref Unsafe.AsRef(in _weights)), _size); + + /// + /// The smallest weight + /// + public readonly W MinWeight => _size > 0 ? Weights[_size - 1] : W.MaxValue; + + /// + /// The largest weight + /// + public readonly W MaxWeight => _size > 0 ? Weights[0] : W.MinValue; + + /// + /// The value with the smallest weight + /// + public readonly V? MinValue => _size > 0 ? Values[_size - 1] : default; + + /// + /// The value with the largest weight + /// + public readonly V? MaxValue => _size > 0 ? Values[0] : default; + + /// + /// Returns a value and weight + /// + /// Index to return + public readonly (V Value, W Weight) this[byte index] + { + get + { + if (index < Size) + return (Values[index], Weights[index]); + throw new ArgumentOutOfRangeException(); + } + } + + /// + /// Enumerates the values and weights + /// + public readonly IEnumerable<(V Value, W Weight)> Elements + { + get + { + for (byte i = 0; i < Size; i++) + yield return this[i]; + } + } + + /// + /// Tries to add a new element - will succeed if there aren't already max elements with a smaller weight + /// + /// Value to add + /// Weight to add + /// True if values should be unique - will return false if the value already exists + /// True if the element was added + public bool TryAdd(V value, W weight, bool enforceUnique = true) + { + var values = MemoryMarshal.CreateSpan(ref Unsafe.As(ref Unsafe.AsRef(in _values)), MaxSize); + var weights = MemoryMarshal.CreateSpan(ref Unsafe.As(ref Unsafe.AsRef(in _weights)), MaxSize); + return FixedSizeSortedArrayHelper.InsertIntoDescending(enforceUnique, ref _size, MaxSize, value, weight, values, weights); + } + + /// + /// Removes an element from the array + /// + /// Index of element to remove + /// + public void RemoveAt(byte index) + { + if(index >= _size) + throw new ArgumentOutOfRangeException(); + var values = MemoryMarshal.CreateSpan(ref Unsafe.As(ref Unsafe.AsRef(in _values)), _size); + var weights = MemoryMarshal.CreateSpan(ref Unsafe.As(ref Unsafe.AsRef(in _weights)), _size); + FixedSizeSortedArrayHelper.RemoveAt(index, values, weights); + --_size; + } + } + + /// + /// Fixed size sorted array of values and weights (max 8 elements) + /// that is sorted in ascending order based on each weight + /// + /// Type of value to store + /// Type of weight that will be used to sort + public record struct FixedSizeSortedAscending8Array() : IFixedSizeSortedArray + where V : IComparable + where W : unmanaged, INumber, IMinMaxValue + { + /// + /// Max size of the array + /// + public const int MaxSize = 8; + byte IFixedSizeSortedArray.MaxSize => MaxSize; + + [InlineArray(MaxSize)] + internal struct ValueArray + { + public V _element0; + } + [InlineArray(MaxSize)] + internal struct WeightArray + { + public W _element0; + } + readonly ValueArray _values = new(); + readonly WeightArray _weights = new(); + byte _size = 0; + + /// + /// Current number of elements + /// + public readonly byte Size => _size; + + /// + /// Sorted list of values + /// + public readonly ReadOnlySpan Values => MemoryMarshal.CreateReadOnlySpan(ref Unsafe.As(ref Unsafe.AsRef(in _values)), _size); + + /// + /// Sorted list of weights + /// + public readonly ReadOnlySpan Weights => MemoryMarshal.CreateReadOnlySpan(ref Unsafe.As(ref Unsafe.AsRef(in _weights)), _size); + + /// + /// The smallest weight + /// + public readonly W MinWeight => _size > 0 ? Weights[0] : W.MaxValue; + + /// + /// The largest weight + /// + public readonly W MaxWeight => _size > 0 ? Weights[_size - 1] : W.MinValue; + + /// + /// The value with the smallest weight + /// + public readonly V? MinValue => _size > 0 ? Values[0] : default; + + /// + /// The value with the largest weight + /// + public readonly V? MaxValue => _size > 0 ? Values[_size - 1] : default; + + /// + /// Returns a value and weight + /// + /// Index to return + public readonly (V Value, W Weight) this[byte index] + { + get + { + if (index < Size) + return (Values[index], Weights[index]); + throw new ArgumentOutOfRangeException(); + } + } + + /// + /// Enumerates the values and weights + /// + public readonly IEnumerable<(V Value, W Weight)> Elements + { + get + { + for (byte i = 0; i < Size; i++) + yield return this[i]; + } + } + + /// + /// Tries to add a new element - will succeed if there aren't already max elements with a smaller weight + /// + /// Value to add + /// Weight to add + /// True if values should be unique - will return false if the value already exists + /// True if the element was added + public bool TryAdd(V value, W weight, bool enforceUnique = true) + { + var values = MemoryMarshal.CreateSpan(ref Unsafe.As(ref Unsafe.AsRef(in _values)), MaxSize); + var weights = MemoryMarshal.CreateSpan(ref Unsafe.As(ref Unsafe.AsRef(in _weights)), MaxSize); + return FixedSizeSortedArrayHelper.InsertIntoAscending(enforceUnique, ref _size, MaxSize, value, weight, values, weights); + } + + /// + /// Removes an element from the array + /// + /// Index of element to remove + /// + public void RemoveAt(byte index) + { + if(index >= _size) + throw new ArgumentOutOfRangeException(); + var values = MemoryMarshal.CreateSpan(ref Unsafe.As(ref Unsafe.AsRef(in _values)), _size); + var weights = MemoryMarshal.CreateSpan(ref Unsafe.As(ref Unsafe.AsRef(in _weights)), _size); + FixedSizeSortedArrayHelper.RemoveAt(index, values, weights); + --_size; + } + } + + /// + /// Fixed size sorted array of values and weights (max 8 elements) + /// that is sorted in descending order based on each weight + /// + /// Type of value to store + /// Type of weight that will be used to sort + public record struct FixedSizeSortedDescending8Array() + where V : IComparable + where W : unmanaged, INumber, IMinMaxValue + { + /// + /// Max size of the array + /// + public const int MaxSize = 8; + + [InlineArray(MaxSize)] + internal struct ValueArray + { + public V _element0; + } + [InlineArray(MaxSize)] + internal struct WeightArray + { + public W _element0; + } + readonly ValueArray _values = new(); + readonly WeightArray _weights = new(); + byte _size = 0; + + /// + /// Current number of elements + /// + public readonly byte Size => _size; + + /// + /// Sorted list of values + /// + public readonly ReadOnlySpan Values => MemoryMarshal.CreateReadOnlySpan(ref Unsafe.As(ref Unsafe.AsRef(in _values)), _size); + + /// + /// Sorted list of weights + /// + public readonly ReadOnlySpan Weights => MemoryMarshal.CreateReadOnlySpan(ref Unsafe.As(ref Unsafe.AsRef(in _weights)), _size); + + /// + /// The smallest weight + /// + public readonly W MinWeight => _size > 0 ? Weights[_size - 1] : W.MaxValue; + + /// + /// The largest weight + /// + public readonly W MaxWeight => _size > 0 ? Weights[0] : W.MinValue; + + /// + /// The value with the smallest weight + /// + public readonly V? MinValue => _size > 0 ? Values[_size - 1] : default; + + /// + /// The value with the largest weight + /// + public readonly V? MaxValue => _size > 0 ? Values[0] : default; + + /// + /// Returns a value and weight + /// + /// Index to return + public readonly (V Value, W Weight) this[byte index] + { + get + { + if (index < Size) + return (Values[index], Weights[index]); + throw new ArgumentOutOfRangeException(); + } + } + + /// + /// Enumerates the values and weights + /// + public readonly IEnumerable<(V Value, W Weight)> Elements + { + get + { + for (byte i = 0; i < Size; i++) + yield return this[i]; + } + } + + /// + /// Tries to add a new element - will succeed if there aren't already max elements with a smaller weight + /// + /// Value to add + /// Weight to add + /// True if values should be unique - will return false if the value already exists + /// True if the element was added + public bool TryAdd(V value, W weight, bool enforceUnique = true) + { + var values = MemoryMarshal.CreateSpan(ref Unsafe.As(ref Unsafe.AsRef(in _values)), MaxSize); + var weights = MemoryMarshal.CreateSpan(ref Unsafe.As(ref Unsafe.AsRef(in _weights)), MaxSize); + return FixedSizeSortedArrayHelper.InsertIntoDescending(enforceUnique, ref _size, MaxSize, value, weight, values, weights); + } + + /// + /// Removes an element from the array + /// + /// Index of element to remove + /// + public void RemoveAt(byte index) + { + if(index >= _size) + throw new ArgumentOutOfRangeException(); + var values = MemoryMarshal.CreateSpan(ref Unsafe.As(ref Unsafe.AsRef(in _values)), _size); + var weights = MemoryMarshal.CreateSpan(ref Unsafe.As(ref Unsafe.AsRef(in _weights)), _size); + FixedSizeSortedArrayHelper.RemoveAt(index, values, weights); + --_size; + } + } + + /// + /// Fixed size sorted array of values and weights (max 9 elements) + /// that is sorted in ascending order based on each weight + /// + /// Type of value to store + /// Type of weight that will be used to sort + public record struct FixedSizeSortedAscending9Array() : IFixedSizeSortedArray + where V : IComparable + where W : unmanaged, INumber, IMinMaxValue + { + /// + /// Max size of the array + /// + public const int MaxSize = 9; + byte IFixedSizeSortedArray.MaxSize => MaxSize; + + [InlineArray(MaxSize)] + internal struct ValueArray + { + public V _element0; + } + [InlineArray(MaxSize)] + internal struct WeightArray + { + public W _element0; + } + readonly ValueArray _values = new(); + readonly WeightArray _weights = new(); + byte _size = 0; + + /// + /// Current number of elements + /// + public readonly byte Size => _size; + + /// + /// Sorted list of values + /// + public readonly ReadOnlySpan Values => MemoryMarshal.CreateReadOnlySpan(ref Unsafe.As(ref Unsafe.AsRef(in _values)), _size); + + /// + /// Sorted list of weights + /// + public readonly ReadOnlySpan Weights => MemoryMarshal.CreateReadOnlySpan(ref Unsafe.As(ref Unsafe.AsRef(in _weights)), _size); + + /// + /// The smallest weight + /// + public readonly W MinWeight => _size > 0 ? Weights[0] : W.MaxValue; + + /// + /// The largest weight + /// + public readonly W MaxWeight => _size > 0 ? Weights[_size - 1] : W.MinValue; + + /// + /// The value with the smallest weight + /// + public readonly V? MinValue => _size > 0 ? Values[0] : default; + + /// + /// The value with the largest weight + /// + public readonly V? MaxValue => _size > 0 ? Values[_size - 1] : default; + + /// + /// Returns a value and weight + /// + /// Index to return + public readonly (V Value, W Weight) this[byte index] + { + get + { + if (index < Size) + return (Values[index], Weights[index]); + throw new ArgumentOutOfRangeException(); + } + } + + /// + /// Enumerates the values and weights + /// + public readonly IEnumerable<(V Value, W Weight)> Elements + { + get + { + for (byte i = 0; i < Size; i++) + yield return this[i]; + } + } + + /// + /// Tries to add a new element - will succeed if there aren't already max elements with a smaller weight + /// + /// Value to add + /// Weight to add + /// True if values should be unique - will return false if the value already exists + /// True if the element was added + public bool TryAdd(V value, W weight, bool enforceUnique = true) + { + var values = MemoryMarshal.CreateSpan(ref Unsafe.As(ref Unsafe.AsRef(in _values)), MaxSize); + var weights = MemoryMarshal.CreateSpan(ref Unsafe.As(ref Unsafe.AsRef(in _weights)), MaxSize); + return FixedSizeSortedArrayHelper.InsertIntoAscending(enforceUnique, ref _size, MaxSize, value, weight, values, weights); + } + + /// + /// Removes an element from the array + /// + /// Index of element to remove + /// + public void RemoveAt(byte index) + { + if(index >= _size) + throw new ArgumentOutOfRangeException(); + var values = MemoryMarshal.CreateSpan(ref Unsafe.As(ref Unsafe.AsRef(in _values)), _size); + var weights = MemoryMarshal.CreateSpan(ref Unsafe.As(ref Unsafe.AsRef(in _weights)), _size); + FixedSizeSortedArrayHelper.RemoveAt(index, values, weights); + --_size; + } + } + + /// + /// Fixed size sorted array of values and weights (max 9 elements) + /// that is sorted in descending order based on each weight + /// + /// Type of value to store + /// Type of weight that will be used to sort + public record struct FixedSizeSortedDescending9Array() + where V : IComparable + where W : unmanaged, INumber, IMinMaxValue + { + /// + /// Max size of the array + /// + public const int MaxSize = 9; + + [InlineArray(MaxSize)] + internal struct ValueArray + { + public V _element0; + } + [InlineArray(MaxSize)] + internal struct WeightArray + { + public W _element0; + } + readonly ValueArray _values = new(); + readonly WeightArray _weights = new(); + byte _size = 0; + + /// + /// Current number of elements + /// + public readonly byte Size => _size; + + /// + /// Sorted list of values + /// + public readonly ReadOnlySpan Values => MemoryMarshal.CreateReadOnlySpan(ref Unsafe.As(ref Unsafe.AsRef(in _values)), _size); + + /// + /// Sorted list of weights + /// + public readonly ReadOnlySpan Weights => MemoryMarshal.CreateReadOnlySpan(ref Unsafe.As(ref Unsafe.AsRef(in _weights)), _size); + + /// + /// The smallest weight + /// + public readonly W MinWeight => _size > 0 ? Weights[_size - 1] : W.MaxValue; + + /// + /// The largest weight + /// + public readonly W MaxWeight => _size > 0 ? Weights[0] : W.MinValue; + + /// + /// The value with the smallest weight + /// + public readonly V? MinValue => _size > 0 ? Values[_size - 1] : default; + + /// + /// The value with the largest weight + /// + public readonly V? MaxValue => _size > 0 ? Values[0] : default; + + /// + /// Returns a value and weight + /// + /// Index to return + public readonly (V Value, W Weight) this[byte index] + { + get + { + if (index < Size) + return (Values[index], Weights[index]); + throw new ArgumentOutOfRangeException(); + } + } + + /// + /// Enumerates the values and weights + /// + public readonly IEnumerable<(V Value, W Weight)> Elements + { + get + { + for (byte i = 0; i < Size; i++) + yield return this[i]; + } + } + + /// + /// Tries to add a new element - will succeed if there aren't already max elements with a smaller weight + /// + /// Value to add + /// Weight to add + /// True if values should be unique - will return false if the value already exists + /// True if the element was added + public bool TryAdd(V value, W weight, bool enforceUnique = true) + { + var values = MemoryMarshal.CreateSpan(ref Unsafe.As(ref Unsafe.AsRef(in _values)), MaxSize); + var weights = MemoryMarshal.CreateSpan(ref Unsafe.As(ref Unsafe.AsRef(in _weights)), MaxSize); + return FixedSizeSortedArrayHelper.InsertIntoDescending(enforceUnique, ref _size, MaxSize, value, weight, values, weights); + } + + /// + /// Removes an element from the array + /// + /// Index of element to remove + /// + public void RemoveAt(byte index) + { + if(index >= _size) + throw new ArgumentOutOfRangeException(); + var values = MemoryMarshal.CreateSpan(ref Unsafe.As(ref Unsafe.AsRef(in _values)), _size); + var weights = MemoryMarshal.CreateSpan(ref Unsafe.As(ref Unsafe.AsRef(in _weights)), _size); + FixedSizeSortedArrayHelper.RemoveAt(index, values, weights); + --_size; + } + } + + /// + /// Fixed size sorted array of values and weights (max 10 elements) + /// that is sorted in ascending order based on each weight + /// + /// Type of value to store + /// Type of weight that will be used to sort + public record struct FixedSizeSortedAscending10Array() : IFixedSizeSortedArray + where V : IComparable + where W : unmanaged, INumber, IMinMaxValue + { + /// + /// Max size of the array + /// + public const int MaxSize = 10; + byte IFixedSizeSortedArray.MaxSize => MaxSize; + + [InlineArray(MaxSize)] + internal struct ValueArray + { + public V _element0; + } + [InlineArray(MaxSize)] + internal struct WeightArray + { + public W _element0; + } + readonly ValueArray _values = new(); + readonly WeightArray _weights = new(); + byte _size = 0; + + /// + /// Current number of elements + /// + public readonly byte Size => _size; + + /// + /// Sorted list of values + /// + public readonly ReadOnlySpan Values => MemoryMarshal.CreateReadOnlySpan(ref Unsafe.As(ref Unsafe.AsRef(in _values)), _size); + + /// + /// Sorted list of weights + /// + public readonly ReadOnlySpan Weights => MemoryMarshal.CreateReadOnlySpan(ref Unsafe.As(ref Unsafe.AsRef(in _weights)), _size); + + /// + /// The smallest weight + /// + public readonly W MinWeight => _size > 0 ? Weights[0] : W.MaxValue; + + /// + /// The largest weight + /// + public readonly W MaxWeight => _size > 0 ? Weights[_size - 1] : W.MinValue; + + /// + /// The value with the smallest weight + /// + public readonly V? MinValue => _size > 0 ? Values[0] : default; + + /// + /// The value with the largest weight + /// + public readonly V? MaxValue => _size > 0 ? Values[_size - 1] : default; + + /// + /// Returns a value and weight + /// + /// Index to return + public readonly (V Value, W Weight) this[byte index] + { + get + { + if (index < Size) + return (Values[index], Weights[index]); + throw new ArgumentOutOfRangeException(); + } + } + + /// + /// Enumerates the values and weights + /// + public readonly IEnumerable<(V Value, W Weight)> Elements + { + get + { + for (byte i = 0; i < Size; i++) + yield return this[i]; + } + } + + /// + /// Tries to add a new element - will succeed if there aren't already max elements with a smaller weight + /// + /// Value to add + /// Weight to add + /// True if values should be unique - will return false if the value already exists + /// True if the element was added + public bool TryAdd(V value, W weight, bool enforceUnique = true) + { + var values = MemoryMarshal.CreateSpan(ref Unsafe.As(ref Unsafe.AsRef(in _values)), MaxSize); + var weights = MemoryMarshal.CreateSpan(ref Unsafe.As(ref Unsafe.AsRef(in _weights)), MaxSize); + return FixedSizeSortedArrayHelper.InsertIntoAscending(enforceUnique, ref _size, MaxSize, value, weight, values, weights); + } + + /// + /// Removes an element from the array + /// + /// Index of element to remove + /// + public void RemoveAt(byte index) + { + if(index >= _size) + throw new ArgumentOutOfRangeException(); + var values = MemoryMarshal.CreateSpan(ref Unsafe.As(ref Unsafe.AsRef(in _values)), _size); + var weights = MemoryMarshal.CreateSpan(ref Unsafe.As(ref Unsafe.AsRef(in _weights)), _size); + FixedSizeSortedArrayHelper.RemoveAt(index, values, weights); + --_size; + } + } + + /// + /// Fixed size sorted array of values and weights (max 10 elements) + /// that is sorted in descending order based on each weight + /// + /// Type of value to store + /// Type of weight that will be used to sort + public record struct FixedSizeSortedDescending10Array() + where V : IComparable + where W : unmanaged, INumber, IMinMaxValue + { + /// + /// Max size of the array + /// + public const int MaxSize = 10; + + [InlineArray(MaxSize)] + internal struct ValueArray + { + public V _element0; + } + [InlineArray(MaxSize)] + internal struct WeightArray + { + public W _element0; + } + readonly ValueArray _values = new(); + readonly WeightArray _weights = new(); + byte _size = 0; + + /// + /// Current number of elements + /// + public readonly byte Size => _size; + + /// + /// Sorted list of values + /// + public readonly ReadOnlySpan Values => MemoryMarshal.CreateReadOnlySpan(ref Unsafe.As(ref Unsafe.AsRef(in _values)), _size); + + /// + /// Sorted list of weights + /// + public readonly ReadOnlySpan Weights => MemoryMarshal.CreateReadOnlySpan(ref Unsafe.As(ref Unsafe.AsRef(in _weights)), _size); + + /// + /// The smallest weight + /// + public readonly W MinWeight => _size > 0 ? Weights[_size - 1] : W.MaxValue; + + /// + /// The largest weight + /// + public readonly W MaxWeight => _size > 0 ? Weights[0] : W.MinValue; + + /// + /// The value with the smallest weight + /// + public readonly V? MinValue => _size > 0 ? Values[_size - 1] : default; + + /// + /// The value with the largest weight + /// + public readonly V? MaxValue => _size > 0 ? Values[0] : default; + + /// + /// Returns a value and weight + /// + /// Index to return + public readonly (V Value, W Weight) this[byte index] + { + get + { + if (index < Size) + return (Values[index], Weights[index]); + throw new ArgumentOutOfRangeException(); + } + } + + /// + /// Enumerates the values and weights + /// + public readonly IEnumerable<(V Value, W Weight)> Elements + { + get + { + for (byte i = 0; i < Size; i++) + yield return this[i]; + } + } + + /// + /// Tries to add a new element - will succeed if there aren't already max elements with a smaller weight + /// + /// Value to add + /// Weight to add + /// True if values should be unique - will return false if the value already exists + /// True if the element was added + public bool TryAdd(V value, W weight, bool enforceUnique = true) + { + var values = MemoryMarshal.CreateSpan(ref Unsafe.As(ref Unsafe.AsRef(in _values)), MaxSize); + var weights = MemoryMarshal.CreateSpan(ref Unsafe.As(ref Unsafe.AsRef(in _weights)), MaxSize); + return FixedSizeSortedArrayHelper.InsertIntoDescending(enforceUnique, ref _size, MaxSize, value, weight, values, weights); + } + + /// + /// Removes an element from the array + /// + /// Index of element to remove + /// + public void RemoveAt(byte index) + { + if(index >= _size) + throw new ArgumentOutOfRangeException(); + var values = MemoryMarshal.CreateSpan(ref Unsafe.As(ref Unsafe.AsRef(in _values)), _size); + var weights = MemoryMarshal.CreateSpan(ref Unsafe.As(ref Unsafe.AsRef(in _weights)), _size); + FixedSizeSortedArrayHelper.RemoveAt(index, values, weights); + --_size; + } + } + + /// + /// Fixed size sorted array of values and weights (max 11 elements) + /// that is sorted in ascending order based on each weight + /// + /// Type of value to store + /// Type of weight that will be used to sort + public record struct FixedSizeSortedAscending11Array() : IFixedSizeSortedArray + where V : IComparable + where W : unmanaged, INumber, IMinMaxValue + { + /// + /// Max size of the array + /// + public const int MaxSize = 11; + byte IFixedSizeSortedArray.MaxSize => MaxSize; + + [InlineArray(MaxSize)] + internal struct ValueArray + { + public V _element0; + } + [InlineArray(MaxSize)] + internal struct WeightArray + { + public W _element0; + } + readonly ValueArray _values = new(); + readonly WeightArray _weights = new(); + byte _size = 0; + + /// + /// Current number of elements + /// + public readonly byte Size => _size; + + /// + /// Sorted list of values + /// + public readonly ReadOnlySpan Values => MemoryMarshal.CreateReadOnlySpan(ref Unsafe.As(ref Unsafe.AsRef(in _values)), _size); + + /// + /// Sorted list of weights + /// + public readonly ReadOnlySpan Weights => MemoryMarshal.CreateReadOnlySpan(ref Unsafe.As(ref Unsafe.AsRef(in _weights)), _size); + + /// + /// The smallest weight + /// + public readonly W MinWeight => _size > 0 ? Weights[0] : W.MaxValue; + + /// + /// The largest weight + /// + public readonly W MaxWeight => _size > 0 ? Weights[_size - 1] : W.MinValue; + + /// + /// The value with the smallest weight + /// + public readonly V? MinValue => _size > 0 ? Values[0] : default; + + /// + /// The value with the largest weight + /// + public readonly V? MaxValue => _size > 0 ? Values[_size - 1] : default; + + /// + /// Returns a value and weight + /// + /// Index to return + public readonly (V Value, W Weight) this[byte index] + { + get + { + if (index < Size) + return (Values[index], Weights[index]); + throw new ArgumentOutOfRangeException(); + } + } + + /// + /// Enumerates the values and weights + /// + public readonly IEnumerable<(V Value, W Weight)> Elements + { + get + { + for (byte i = 0; i < Size; i++) + yield return this[i]; + } + } + + /// + /// Tries to add a new element - will succeed if there aren't already max elements with a smaller weight + /// + /// Value to add + /// Weight to add + /// True if values should be unique - will return false if the value already exists + /// True if the element was added + public bool TryAdd(V value, W weight, bool enforceUnique = true) + { + var values = MemoryMarshal.CreateSpan(ref Unsafe.As(ref Unsafe.AsRef(in _values)), MaxSize); + var weights = MemoryMarshal.CreateSpan(ref Unsafe.As(ref Unsafe.AsRef(in _weights)), MaxSize); + return FixedSizeSortedArrayHelper.InsertIntoAscending(enforceUnique, ref _size, MaxSize, value, weight, values, weights); + } + + /// + /// Removes an element from the array + /// + /// Index of element to remove + /// + public void RemoveAt(byte index) + { + if(index >= _size) + throw new ArgumentOutOfRangeException(); + var values = MemoryMarshal.CreateSpan(ref Unsafe.As(ref Unsafe.AsRef(in _values)), _size); + var weights = MemoryMarshal.CreateSpan(ref Unsafe.As(ref Unsafe.AsRef(in _weights)), _size); + FixedSizeSortedArrayHelper.RemoveAt(index, values, weights); + --_size; + } + } + + /// + /// Fixed size sorted array of values and weights (max 11 elements) + /// that is sorted in descending order based on each weight + /// + /// Type of value to store + /// Type of weight that will be used to sort + public record struct FixedSizeSortedDescending11Array() + where V : IComparable + where W : unmanaged, INumber, IMinMaxValue + { + /// + /// Max size of the array + /// + public const int MaxSize = 11; + + [InlineArray(MaxSize)] + internal struct ValueArray + { + public V _element0; + } + [InlineArray(MaxSize)] + internal struct WeightArray + { + public W _element0; + } + readonly ValueArray _values = new(); + readonly WeightArray _weights = new(); + byte _size = 0; + + /// + /// Current number of elements + /// + public readonly byte Size => _size; + + /// + /// Sorted list of values + /// + public readonly ReadOnlySpan Values => MemoryMarshal.CreateReadOnlySpan(ref Unsafe.As(ref Unsafe.AsRef(in _values)), _size); + + /// + /// Sorted list of weights + /// + public readonly ReadOnlySpan Weights => MemoryMarshal.CreateReadOnlySpan(ref Unsafe.As(ref Unsafe.AsRef(in _weights)), _size); + + /// + /// The smallest weight + /// + public readonly W MinWeight => _size > 0 ? Weights[_size - 1] : W.MaxValue; + + /// + /// The largest weight + /// + public readonly W MaxWeight => _size > 0 ? Weights[0] : W.MinValue; + + /// + /// The value with the smallest weight + /// + public readonly V? MinValue => _size > 0 ? Values[_size - 1] : default; + + /// + /// The value with the largest weight + /// + public readonly V? MaxValue => _size > 0 ? Values[0] : default; + + /// + /// Returns a value and weight + /// + /// Index to return + public readonly (V Value, W Weight) this[byte index] + { + get + { + if (index < Size) + return (Values[index], Weights[index]); + throw new ArgumentOutOfRangeException(); + } + } + + /// + /// Enumerates the values and weights + /// + public readonly IEnumerable<(V Value, W Weight)> Elements + { + get + { + for (byte i = 0; i < Size; i++) + yield return this[i]; + } + } + + /// + /// Tries to add a new element - will succeed if there aren't already max elements with a smaller weight + /// + /// Value to add + /// Weight to add + /// True if values should be unique - will return false if the value already exists + /// True if the element was added + public bool TryAdd(V value, W weight, bool enforceUnique = true) + { + var values = MemoryMarshal.CreateSpan(ref Unsafe.As(ref Unsafe.AsRef(in _values)), MaxSize); + var weights = MemoryMarshal.CreateSpan(ref Unsafe.As(ref Unsafe.AsRef(in _weights)), MaxSize); + return FixedSizeSortedArrayHelper.InsertIntoDescending(enforceUnique, ref _size, MaxSize, value, weight, values, weights); + } + + /// + /// Removes an element from the array + /// + /// Index of element to remove + /// + public void RemoveAt(byte index) + { + if(index >= _size) + throw new ArgumentOutOfRangeException(); + var values = MemoryMarshal.CreateSpan(ref Unsafe.As(ref Unsafe.AsRef(in _values)), _size); + var weights = MemoryMarshal.CreateSpan(ref Unsafe.As(ref Unsafe.AsRef(in _weights)), _size); + FixedSizeSortedArrayHelper.RemoveAt(index, values, weights); + --_size; + } + } + + /// + /// Fixed size sorted array of values and weights (max 12 elements) + /// that is sorted in ascending order based on each weight + /// + /// Type of value to store + /// Type of weight that will be used to sort + public record struct FixedSizeSortedAscending12Array() : IFixedSizeSortedArray + where V : IComparable + where W : unmanaged, INumber, IMinMaxValue + { + /// + /// Max size of the array + /// + public const int MaxSize = 12; + byte IFixedSizeSortedArray.MaxSize => MaxSize; + + [InlineArray(MaxSize)] + internal struct ValueArray + { + public V _element0; + } + [InlineArray(MaxSize)] + internal struct WeightArray + { + public W _element0; + } + readonly ValueArray _values = new(); + readonly WeightArray _weights = new(); + byte _size = 0; + + /// + /// Current number of elements + /// + public readonly byte Size => _size; + + /// + /// Sorted list of values + /// + public readonly ReadOnlySpan Values => MemoryMarshal.CreateReadOnlySpan(ref Unsafe.As(ref Unsafe.AsRef(in _values)), _size); + + /// + /// Sorted list of weights + /// + public readonly ReadOnlySpan Weights => MemoryMarshal.CreateReadOnlySpan(ref Unsafe.As(ref Unsafe.AsRef(in _weights)), _size); + + /// + /// The smallest weight + /// + public readonly W MinWeight => _size > 0 ? Weights[0] : W.MaxValue; + + /// + /// The largest weight + /// + public readonly W MaxWeight => _size > 0 ? Weights[_size - 1] : W.MinValue; + + /// + /// The value with the smallest weight + /// + public readonly V? MinValue => _size > 0 ? Values[0] : default; + + /// + /// The value with the largest weight + /// + public readonly V? MaxValue => _size > 0 ? Values[_size - 1] : default; + + /// + /// Returns a value and weight + /// + /// Index to return + public readonly (V Value, W Weight) this[byte index] + { + get + { + if (index < Size) + return (Values[index], Weights[index]); + throw new ArgumentOutOfRangeException(); + } + } + + /// + /// Enumerates the values and weights + /// + public readonly IEnumerable<(V Value, W Weight)> Elements + { + get + { + for (byte i = 0; i < Size; i++) + yield return this[i]; + } + } + + /// + /// Tries to add a new element - will succeed if there aren't already max elements with a smaller weight + /// + /// Value to add + /// Weight to add + /// True if values should be unique - will return false if the value already exists + /// True if the element was added + public bool TryAdd(V value, W weight, bool enforceUnique = true) + { + var values = MemoryMarshal.CreateSpan(ref Unsafe.As(ref Unsafe.AsRef(in _values)), MaxSize); + var weights = MemoryMarshal.CreateSpan(ref Unsafe.As(ref Unsafe.AsRef(in _weights)), MaxSize); + return FixedSizeSortedArrayHelper.InsertIntoAscending(enforceUnique, ref _size, MaxSize, value, weight, values, weights); + } + + /// + /// Removes an element from the array + /// + /// Index of element to remove + /// + public void RemoveAt(byte index) + { + if(index >= _size) + throw new ArgumentOutOfRangeException(); + var values = MemoryMarshal.CreateSpan(ref Unsafe.As(ref Unsafe.AsRef(in _values)), _size); + var weights = MemoryMarshal.CreateSpan(ref Unsafe.As(ref Unsafe.AsRef(in _weights)), _size); + FixedSizeSortedArrayHelper.RemoveAt(index, values, weights); + --_size; + } + } + + /// + /// Fixed size sorted array of values and weights (max 12 elements) + /// that is sorted in descending order based on each weight + /// + /// Type of value to store + /// Type of weight that will be used to sort + public record struct FixedSizeSortedDescending12Array() + where V : IComparable + where W : unmanaged, INumber, IMinMaxValue + { + /// + /// Max size of the array + /// + public const int MaxSize = 12; + + [InlineArray(MaxSize)] + internal struct ValueArray + { + public V _element0; + } + [InlineArray(MaxSize)] + internal struct WeightArray + { + public W _element0; + } + readonly ValueArray _values = new(); + readonly WeightArray _weights = new(); + byte _size = 0; + + /// + /// Current number of elements + /// + public readonly byte Size => _size; + + /// + /// Sorted list of values + /// + public readonly ReadOnlySpan Values => MemoryMarshal.CreateReadOnlySpan(ref Unsafe.As(ref Unsafe.AsRef(in _values)), _size); + + /// + /// Sorted list of weights + /// + public readonly ReadOnlySpan Weights => MemoryMarshal.CreateReadOnlySpan(ref Unsafe.As(ref Unsafe.AsRef(in _weights)), _size); + + /// + /// The smallest weight + /// + public readonly W MinWeight => _size > 0 ? Weights[_size - 1] : W.MaxValue; + + /// + /// The largest weight + /// + public readonly W MaxWeight => _size > 0 ? Weights[0] : W.MinValue; + + /// + /// The value with the smallest weight + /// + public readonly V? MinValue => _size > 0 ? Values[_size - 1] : default; + + /// + /// The value with the largest weight + /// + public readonly V? MaxValue => _size > 0 ? Values[0] : default; + + /// + /// Returns a value and weight + /// + /// Index to return + public readonly (V Value, W Weight) this[byte index] + { + get + { + if (index < Size) + return (Values[index], Weights[index]); + throw new ArgumentOutOfRangeException(); + } + } + + /// + /// Enumerates the values and weights + /// + public readonly IEnumerable<(V Value, W Weight)> Elements + { + get + { + for (byte i = 0; i < Size; i++) + yield return this[i]; + } + } + + /// + /// Tries to add a new element - will succeed if there aren't already max elements with a smaller weight + /// + /// Value to add + /// Weight to add + /// True if values should be unique - will return false if the value already exists + /// True if the element was added + public bool TryAdd(V value, W weight, bool enforceUnique = true) + { + var values = MemoryMarshal.CreateSpan(ref Unsafe.As(ref Unsafe.AsRef(in _values)), MaxSize); + var weights = MemoryMarshal.CreateSpan(ref Unsafe.As(ref Unsafe.AsRef(in _weights)), MaxSize); + return FixedSizeSortedArrayHelper.InsertIntoDescending(enforceUnique, ref _size, MaxSize, value, weight, values, weights); + } + + /// + /// Removes an element from the array + /// + /// Index of element to remove + /// + public void RemoveAt(byte index) + { + if(index >= _size) + throw new ArgumentOutOfRangeException(); + var values = MemoryMarshal.CreateSpan(ref Unsafe.As(ref Unsafe.AsRef(in _values)), _size); + var weights = MemoryMarshal.CreateSpan(ref Unsafe.As(ref Unsafe.AsRef(in _weights)), _size); + FixedSizeSortedArrayHelper.RemoveAt(index, values, weights); + --_size; + } + } + + /// + /// Fixed size sorted array of values and weights (max 13 elements) + /// that is sorted in ascending order based on each weight + /// + /// Type of value to store + /// Type of weight that will be used to sort + public record struct FixedSizeSortedAscending13Array() : IFixedSizeSortedArray + where V : IComparable + where W : unmanaged, INumber, IMinMaxValue + { + /// + /// Max size of the array + /// + public const int MaxSize = 13; + byte IFixedSizeSortedArray.MaxSize => MaxSize; + + [InlineArray(MaxSize)] + internal struct ValueArray + { + public V _element0; + } + [InlineArray(MaxSize)] + internal struct WeightArray + { + public W _element0; + } + readonly ValueArray _values = new(); + readonly WeightArray _weights = new(); + byte _size = 0; + + /// + /// Current number of elements + /// + public readonly byte Size => _size; + + /// + /// Sorted list of values + /// + public readonly ReadOnlySpan Values => MemoryMarshal.CreateReadOnlySpan(ref Unsafe.As(ref Unsafe.AsRef(in _values)), _size); + + /// + /// Sorted list of weights + /// + public readonly ReadOnlySpan Weights => MemoryMarshal.CreateReadOnlySpan(ref Unsafe.As(ref Unsafe.AsRef(in _weights)), _size); + + /// + /// The smallest weight + /// + public readonly W MinWeight => _size > 0 ? Weights[0] : W.MaxValue; + + /// + /// The largest weight + /// + public readonly W MaxWeight => _size > 0 ? Weights[_size - 1] : W.MinValue; + + /// + /// The value with the smallest weight + /// + public readonly V? MinValue => _size > 0 ? Values[0] : default; + + /// + /// The value with the largest weight + /// + public readonly V? MaxValue => _size > 0 ? Values[_size - 1] : default; + + /// + /// Returns a value and weight + /// + /// Index to return + public readonly (V Value, W Weight) this[byte index] + { + get + { + if (index < Size) + return (Values[index], Weights[index]); + throw new ArgumentOutOfRangeException(); + } + } + + /// + /// Enumerates the values and weights + /// + public readonly IEnumerable<(V Value, W Weight)> Elements + { + get + { + for (byte i = 0; i < Size; i++) + yield return this[i]; + } + } + + /// + /// Tries to add a new element - will succeed if there aren't already max elements with a smaller weight + /// + /// Value to add + /// Weight to add + /// True if values should be unique - will return false if the value already exists + /// True if the element was added + public bool TryAdd(V value, W weight, bool enforceUnique = true) + { + var values = MemoryMarshal.CreateSpan(ref Unsafe.As(ref Unsafe.AsRef(in _values)), MaxSize); + var weights = MemoryMarshal.CreateSpan(ref Unsafe.As(ref Unsafe.AsRef(in _weights)), MaxSize); + return FixedSizeSortedArrayHelper.InsertIntoAscending(enforceUnique, ref _size, MaxSize, value, weight, values, weights); + } + + /// + /// Removes an element from the array + /// + /// Index of element to remove + /// + public void RemoveAt(byte index) + { + if(index >= _size) + throw new ArgumentOutOfRangeException(); + var values = MemoryMarshal.CreateSpan(ref Unsafe.As(ref Unsafe.AsRef(in _values)), _size); + var weights = MemoryMarshal.CreateSpan(ref Unsafe.As(ref Unsafe.AsRef(in _weights)), _size); + FixedSizeSortedArrayHelper.RemoveAt(index, values, weights); + --_size; + } + } + + /// + /// Fixed size sorted array of values and weights (max 13 elements) + /// that is sorted in descending order based on each weight + /// + /// Type of value to store + /// Type of weight that will be used to sort + public record struct FixedSizeSortedDescending13Array() + where V : IComparable + where W : unmanaged, INumber, IMinMaxValue + { + /// + /// Max size of the array + /// + public const int MaxSize = 13; + + [InlineArray(MaxSize)] + internal struct ValueArray + { + public V _element0; + } + [InlineArray(MaxSize)] + internal struct WeightArray + { + public W _element0; + } + readonly ValueArray _values = new(); + readonly WeightArray _weights = new(); + byte _size = 0; + + /// + /// Current number of elements + /// + public readonly byte Size => _size; + + /// + /// Sorted list of values + /// + public readonly ReadOnlySpan Values => MemoryMarshal.CreateReadOnlySpan(ref Unsafe.As(ref Unsafe.AsRef(in _values)), _size); + + /// + /// Sorted list of weights + /// + public readonly ReadOnlySpan Weights => MemoryMarshal.CreateReadOnlySpan(ref Unsafe.As(ref Unsafe.AsRef(in _weights)), _size); + + /// + /// The smallest weight + /// + public readonly W MinWeight => _size > 0 ? Weights[_size - 1] : W.MaxValue; + + /// + /// The largest weight + /// + public readonly W MaxWeight => _size > 0 ? Weights[0] : W.MinValue; + + /// + /// The value with the smallest weight + /// + public readonly V? MinValue => _size > 0 ? Values[_size - 1] : default; + + /// + /// The value with the largest weight + /// + public readonly V? MaxValue => _size > 0 ? Values[0] : default; + + /// + /// Returns a value and weight + /// + /// Index to return + public readonly (V Value, W Weight) this[byte index] + { + get + { + if (index < Size) + return (Values[index], Weights[index]); + throw new ArgumentOutOfRangeException(); + } + } + + /// + /// Enumerates the values and weights + /// + public readonly IEnumerable<(V Value, W Weight)> Elements + { + get + { + for (byte i = 0; i < Size; i++) + yield return this[i]; + } + } + + /// + /// Tries to add a new element - will succeed if there aren't already max elements with a smaller weight + /// + /// Value to add + /// Weight to add + /// True if values should be unique - will return false if the value already exists + /// True if the element was added + public bool TryAdd(V value, W weight, bool enforceUnique = true) + { + var values = MemoryMarshal.CreateSpan(ref Unsafe.As(ref Unsafe.AsRef(in _values)), MaxSize); + var weights = MemoryMarshal.CreateSpan(ref Unsafe.As(ref Unsafe.AsRef(in _weights)), MaxSize); + return FixedSizeSortedArrayHelper.InsertIntoDescending(enforceUnique, ref _size, MaxSize, value, weight, values, weights); + } + + /// + /// Removes an element from the array + /// + /// Index of element to remove + /// + public void RemoveAt(byte index) + { + if(index >= _size) + throw new ArgumentOutOfRangeException(); + var values = MemoryMarshal.CreateSpan(ref Unsafe.As(ref Unsafe.AsRef(in _values)), _size); + var weights = MemoryMarshal.CreateSpan(ref Unsafe.As(ref Unsafe.AsRef(in _weights)), _size); + FixedSizeSortedArrayHelper.RemoveAt(index, values, weights); + --_size; + } + } + + /// + /// Fixed size sorted array of values and weights (max 14 elements) + /// that is sorted in ascending order based on each weight + /// + /// Type of value to store + /// Type of weight that will be used to sort + public record struct FixedSizeSortedAscending14Array() : IFixedSizeSortedArray + where V : IComparable + where W : unmanaged, INumber, IMinMaxValue + { + /// + /// Max size of the array + /// + public const int MaxSize = 14; + byte IFixedSizeSortedArray.MaxSize => MaxSize; + + [InlineArray(MaxSize)] + internal struct ValueArray + { + public V _element0; + } + [InlineArray(MaxSize)] + internal struct WeightArray + { + public W _element0; + } + readonly ValueArray _values = new(); + readonly WeightArray _weights = new(); + byte _size = 0; + + /// + /// Current number of elements + /// + public readonly byte Size => _size; + + /// + /// Sorted list of values + /// + public readonly ReadOnlySpan Values => MemoryMarshal.CreateReadOnlySpan(ref Unsafe.As(ref Unsafe.AsRef(in _values)), _size); + + /// + /// Sorted list of weights + /// + public readonly ReadOnlySpan Weights => MemoryMarshal.CreateReadOnlySpan(ref Unsafe.As(ref Unsafe.AsRef(in _weights)), _size); + + /// + /// The smallest weight + /// + public readonly W MinWeight => _size > 0 ? Weights[0] : W.MaxValue; + + /// + /// The largest weight + /// + public readonly W MaxWeight => _size > 0 ? Weights[_size - 1] : W.MinValue; + + /// + /// The value with the smallest weight + /// + public readonly V? MinValue => _size > 0 ? Values[0] : default; + + /// + /// The value with the largest weight + /// + public readonly V? MaxValue => _size > 0 ? Values[_size - 1] : default; + + /// + /// Returns a value and weight + /// + /// Index to return + public readonly (V Value, W Weight) this[byte index] + { + get + { + if (index < Size) + return (Values[index], Weights[index]); + throw new ArgumentOutOfRangeException(); + } + } + + /// + /// Enumerates the values and weights + /// + public readonly IEnumerable<(V Value, W Weight)> Elements + { + get + { + for (byte i = 0; i < Size; i++) + yield return this[i]; + } + } + + /// + /// Tries to add a new element - will succeed if there aren't already max elements with a smaller weight + /// + /// Value to add + /// Weight to add + /// True if values should be unique - will return false if the value already exists + /// True if the element was added + public bool TryAdd(V value, W weight, bool enforceUnique = true) + { + var values = MemoryMarshal.CreateSpan(ref Unsafe.As(ref Unsafe.AsRef(in _values)), MaxSize); + var weights = MemoryMarshal.CreateSpan(ref Unsafe.As(ref Unsafe.AsRef(in _weights)), MaxSize); + return FixedSizeSortedArrayHelper.InsertIntoAscending(enforceUnique, ref _size, MaxSize, value, weight, values, weights); + } + + /// + /// Removes an element from the array + /// + /// Index of element to remove + /// + public void RemoveAt(byte index) + { + if(index >= _size) + throw new ArgumentOutOfRangeException(); + var values = MemoryMarshal.CreateSpan(ref Unsafe.As(ref Unsafe.AsRef(in _values)), _size); + var weights = MemoryMarshal.CreateSpan(ref Unsafe.As(ref Unsafe.AsRef(in _weights)), _size); + FixedSizeSortedArrayHelper.RemoveAt(index, values, weights); + --_size; + } + } + + /// + /// Fixed size sorted array of values and weights (max 14 elements) + /// that is sorted in descending order based on each weight + /// + /// Type of value to store + /// Type of weight that will be used to sort + public record struct FixedSizeSortedDescending14Array() + where V : IComparable + where W : unmanaged, INumber, IMinMaxValue + { + /// + /// Max size of the array + /// + public const int MaxSize = 14; + + [InlineArray(MaxSize)] + internal struct ValueArray + { + public V _element0; + } + [InlineArray(MaxSize)] + internal struct WeightArray + { + public W _element0; + } + readonly ValueArray _values = new(); + readonly WeightArray _weights = new(); + byte _size = 0; + + /// + /// Current number of elements + /// + public readonly byte Size => _size; + + /// + /// Sorted list of values + /// + public readonly ReadOnlySpan Values => MemoryMarshal.CreateReadOnlySpan(ref Unsafe.As(ref Unsafe.AsRef(in _values)), _size); + + /// + /// Sorted list of weights + /// + public readonly ReadOnlySpan Weights => MemoryMarshal.CreateReadOnlySpan(ref Unsafe.As(ref Unsafe.AsRef(in _weights)), _size); + + /// + /// The smallest weight + /// + public readonly W MinWeight => _size > 0 ? Weights[_size - 1] : W.MaxValue; + + /// + /// The largest weight + /// + public readonly W MaxWeight => _size > 0 ? Weights[0] : W.MinValue; + + /// + /// The value with the smallest weight + /// + public readonly V? MinValue => _size > 0 ? Values[_size - 1] : default; + + /// + /// The value with the largest weight + /// + public readonly V? MaxValue => _size > 0 ? Values[0] : default; + + /// + /// Returns a value and weight + /// + /// Index to return + public readonly (V Value, W Weight) this[byte index] + { + get + { + if (index < Size) + return (Values[index], Weights[index]); + throw new ArgumentOutOfRangeException(); + } + } + + /// + /// Enumerates the values and weights + /// + public readonly IEnumerable<(V Value, W Weight)> Elements + { + get + { + for (byte i = 0; i < Size; i++) + yield return this[i]; + } + } + + /// + /// Tries to add a new element - will succeed if there aren't already max elements with a smaller weight + /// + /// Value to add + /// Weight to add + /// True if values should be unique - will return false if the value already exists + /// True if the element was added + public bool TryAdd(V value, W weight, bool enforceUnique = true) + { + var values = MemoryMarshal.CreateSpan(ref Unsafe.As(ref Unsafe.AsRef(in _values)), MaxSize); + var weights = MemoryMarshal.CreateSpan(ref Unsafe.As(ref Unsafe.AsRef(in _weights)), MaxSize); + return FixedSizeSortedArrayHelper.InsertIntoDescending(enforceUnique, ref _size, MaxSize, value, weight, values, weights); + } + + /// + /// Removes an element from the array + /// + /// Index of element to remove + /// + public void RemoveAt(byte index) + { + if(index >= _size) + throw new ArgumentOutOfRangeException(); + var values = MemoryMarshal.CreateSpan(ref Unsafe.As(ref Unsafe.AsRef(in _values)), _size); + var weights = MemoryMarshal.CreateSpan(ref Unsafe.As(ref Unsafe.AsRef(in _weights)), _size); + FixedSizeSortedArrayHelper.RemoveAt(index, values, weights); + --_size; + } + } + + /// + /// Fixed size sorted array of values and weights (max 15 elements) + /// that is sorted in ascending order based on each weight + /// + /// Type of value to store + /// Type of weight that will be used to sort + public record struct FixedSizeSortedAscending15Array() : IFixedSizeSortedArray + where V : IComparable + where W : unmanaged, INumber, IMinMaxValue + { + /// + /// Max size of the array + /// + public const int MaxSize = 15; + byte IFixedSizeSortedArray.MaxSize => MaxSize; + + [InlineArray(MaxSize)] + internal struct ValueArray + { + public V _element0; + } + [InlineArray(MaxSize)] + internal struct WeightArray + { + public W _element0; + } + readonly ValueArray _values = new(); + readonly WeightArray _weights = new(); + byte _size = 0; + + /// + /// Current number of elements + /// + public readonly byte Size => _size; + + /// + /// Sorted list of values + /// + public readonly ReadOnlySpan Values => MemoryMarshal.CreateReadOnlySpan(ref Unsafe.As(ref Unsafe.AsRef(in _values)), _size); + + /// + /// Sorted list of weights + /// + public readonly ReadOnlySpan Weights => MemoryMarshal.CreateReadOnlySpan(ref Unsafe.As(ref Unsafe.AsRef(in _weights)), _size); + + /// + /// The smallest weight + /// + public readonly W MinWeight => _size > 0 ? Weights[0] : W.MaxValue; + + /// + /// The largest weight + /// + public readonly W MaxWeight => _size > 0 ? Weights[_size - 1] : W.MinValue; + + /// + /// The value with the smallest weight + /// + public readonly V? MinValue => _size > 0 ? Values[0] : default; + + /// + /// The value with the largest weight + /// + public readonly V? MaxValue => _size > 0 ? Values[_size - 1] : default; + + /// + /// Returns a value and weight + /// + /// Index to return + public readonly (V Value, W Weight) this[byte index] + { + get + { + if (index < Size) + return (Values[index], Weights[index]); + throw new ArgumentOutOfRangeException(); + } + } + + /// + /// Enumerates the values and weights + /// + public readonly IEnumerable<(V Value, W Weight)> Elements + { + get + { + for (byte i = 0; i < Size; i++) + yield return this[i]; + } + } + + /// + /// Tries to add a new element - will succeed if there aren't already max elements with a smaller weight + /// + /// Value to add + /// Weight to add + /// True if values should be unique - will return false if the value already exists + /// True if the element was added + public bool TryAdd(V value, W weight, bool enforceUnique = true) + { + var values = MemoryMarshal.CreateSpan(ref Unsafe.As(ref Unsafe.AsRef(in _values)), MaxSize); + var weights = MemoryMarshal.CreateSpan(ref Unsafe.As(ref Unsafe.AsRef(in _weights)), MaxSize); + return FixedSizeSortedArrayHelper.InsertIntoAscending(enforceUnique, ref _size, MaxSize, value, weight, values, weights); + } + + /// + /// Removes an element from the array + /// + /// Index of element to remove + /// + public void RemoveAt(byte index) + { + if(index >= _size) + throw new ArgumentOutOfRangeException(); + var values = MemoryMarshal.CreateSpan(ref Unsafe.As(ref Unsafe.AsRef(in _values)), _size); + var weights = MemoryMarshal.CreateSpan(ref Unsafe.As(ref Unsafe.AsRef(in _weights)), _size); + FixedSizeSortedArrayHelper.RemoveAt(index, values, weights); + --_size; + } + } + + /// + /// Fixed size sorted array of values and weights (max 15 elements) + /// that is sorted in descending order based on each weight + /// + /// Type of value to store + /// Type of weight that will be used to sort + public record struct FixedSizeSortedDescending15Array() + where V : IComparable + where W : unmanaged, INumber, IMinMaxValue + { + /// + /// Max size of the array + /// + public const int MaxSize = 15; + + [InlineArray(MaxSize)] + internal struct ValueArray + { + public V _element0; + } + [InlineArray(MaxSize)] + internal struct WeightArray + { + public W _element0; + } + readonly ValueArray _values = new(); + readonly WeightArray _weights = new(); + byte _size = 0; + + /// + /// Current number of elements + /// + public readonly byte Size => _size; + + /// + /// Sorted list of values + /// + public readonly ReadOnlySpan Values => MemoryMarshal.CreateReadOnlySpan(ref Unsafe.As(ref Unsafe.AsRef(in _values)), _size); + + /// + /// Sorted list of weights + /// + public readonly ReadOnlySpan Weights => MemoryMarshal.CreateReadOnlySpan(ref Unsafe.As(ref Unsafe.AsRef(in _weights)), _size); + + /// + /// The smallest weight + /// + public readonly W MinWeight => _size > 0 ? Weights[_size - 1] : W.MaxValue; + + /// + /// The largest weight + /// + public readonly W MaxWeight => _size > 0 ? Weights[0] : W.MinValue; + + /// + /// The value with the smallest weight + /// + public readonly V? MinValue => _size > 0 ? Values[_size - 1] : default; + + /// + /// The value with the largest weight + /// + public readonly V? MaxValue => _size > 0 ? Values[0] : default; + + /// + /// Returns a value and weight + /// + /// Index to return + public readonly (V Value, W Weight) this[byte index] + { + get + { + if (index < Size) + return (Values[index], Weights[index]); + throw new ArgumentOutOfRangeException(); + } + } + + /// + /// Enumerates the values and weights + /// + public readonly IEnumerable<(V Value, W Weight)> Elements + { + get + { + for (byte i = 0; i < Size; i++) + yield return this[i]; + } + } + + /// + /// Tries to add a new element - will succeed if there aren't already max elements with a smaller weight + /// + /// Value to add + /// Weight to add + /// True if values should be unique - will return false if the value already exists + /// True if the element was added + public bool TryAdd(V value, W weight, bool enforceUnique = true) + { + var values = MemoryMarshal.CreateSpan(ref Unsafe.As(ref Unsafe.AsRef(in _values)), MaxSize); + var weights = MemoryMarshal.CreateSpan(ref Unsafe.As(ref Unsafe.AsRef(in _weights)), MaxSize); + return FixedSizeSortedArrayHelper.InsertIntoDescending(enforceUnique, ref _size, MaxSize, value, weight, values, weights); + } + + /// + /// Removes an element from the array + /// + /// Index of element to remove + /// + public void RemoveAt(byte index) + { + if(index >= _size) + throw new ArgumentOutOfRangeException(); + var values = MemoryMarshal.CreateSpan(ref Unsafe.As(ref Unsafe.AsRef(in _values)), _size); + var weights = MemoryMarshal.CreateSpan(ref Unsafe.As(ref Unsafe.AsRef(in _weights)), _size); + FixedSizeSortedArrayHelper.RemoveAt(index, values, weights); + --_size; + } + } + + /// + /// Fixed size sorted array of values and weights (max 16 elements) + /// that is sorted in ascending order based on each weight + /// + /// Type of value to store + /// Type of weight that will be used to sort + public record struct FixedSizeSortedAscending16Array() : IFixedSizeSortedArray + where V : IComparable + where W : unmanaged, INumber, IMinMaxValue + { + /// + /// Max size of the array + /// + public const int MaxSize = 16; + byte IFixedSizeSortedArray.MaxSize => MaxSize; + + [InlineArray(MaxSize)] + internal struct ValueArray + { + public V _element0; + } + [InlineArray(MaxSize)] + internal struct WeightArray + { + public W _element0; + } + readonly ValueArray _values = new(); + readonly WeightArray _weights = new(); + byte _size = 0; + + /// + /// Current number of elements + /// + public readonly byte Size => _size; + + /// + /// Sorted list of values + /// + public readonly ReadOnlySpan Values => MemoryMarshal.CreateReadOnlySpan(ref Unsafe.As(ref Unsafe.AsRef(in _values)), _size); + + /// + /// Sorted list of weights + /// + public readonly ReadOnlySpan Weights => MemoryMarshal.CreateReadOnlySpan(ref Unsafe.As(ref Unsafe.AsRef(in _weights)), _size); + + /// + /// The smallest weight + /// + public readonly W MinWeight => _size > 0 ? Weights[0] : W.MaxValue; + + /// + /// The largest weight + /// + public readonly W MaxWeight => _size > 0 ? Weights[_size - 1] : W.MinValue; + + /// + /// The value with the smallest weight + /// + public readonly V? MinValue => _size > 0 ? Values[0] : default; + + /// + /// The value with the largest weight + /// + public readonly V? MaxValue => _size > 0 ? Values[_size - 1] : default; + + /// + /// Returns a value and weight + /// + /// Index to return + public readonly (V Value, W Weight) this[byte index] + { + get + { + if (index < Size) + return (Values[index], Weights[index]); + throw new ArgumentOutOfRangeException(); + } + } + + /// + /// Enumerates the values and weights + /// + public readonly IEnumerable<(V Value, W Weight)> Elements + { + get + { + for (byte i = 0; i < Size; i++) + yield return this[i]; + } + } + + /// + /// Tries to add a new element - will succeed if there aren't already max elements with a smaller weight + /// + /// Value to add + /// Weight to add + /// True if values should be unique - will return false if the value already exists + /// True if the element was added + public bool TryAdd(V value, W weight, bool enforceUnique = true) + { + var values = MemoryMarshal.CreateSpan(ref Unsafe.As(ref Unsafe.AsRef(in _values)), MaxSize); + var weights = MemoryMarshal.CreateSpan(ref Unsafe.As(ref Unsafe.AsRef(in _weights)), MaxSize); + return FixedSizeSortedArrayHelper.InsertIntoAscending(enforceUnique, ref _size, MaxSize, value, weight, values, weights); + } + + /// + /// Removes an element from the array + /// + /// Index of element to remove + /// + public void RemoveAt(byte index) + { + if(index >= _size) + throw new ArgumentOutOfRangeException(); + var values = MemoryMarshal.CreateSpan(ref Unsafe.As(ref Unsafe.AsRef(in _values)), _size); + var weights = MemoryMarshal.CreateSpan(ref Unsafe.As(ref Unsafe.AsRef(in _weights)), _size); + FixedSizeSortedArrayHelper.RemoveAt(index, values, weights); + --_size; + } + } + + /// + /// Fixed size sorted array of values and weights (max 16 elements) + /// that is sorted in descending order based on each weight + /// + /// Type of value to store + /// Type of weight that will be used to sort + public record struct FixedSizeSortedDescending16Array() + where V : IComparable + where W : unmanaged, INumber, IMinMaxValue + { + /// + /// Max size of the array + /// + public const int MaxSize = 16; + + [InlineArray(MaxSize)] + internal struct ValueArray + { + public V _element0; + } + [InlineArray(MaxSize)] + internal struct WeightArray + { + public W _element0; + } + readonly ValueArray _values = new(); + readonly WeightArray _weights = new(); + byte _size = 0; + + /// + /// Current number of elements + /// + public readonly byte Size => _size; + + /// + /// Sorted list of values + /// + public readonly ReadOnlySpan Values => MemoryMarshal.CreateReadOnlySpan(ref Unsafe.As(ref Unsafe.AsRef(in _values)), _size); + + /// + /// Sorted list of weights + /// + public readonly ReadOnlySpan Weights => MemoryMarshal.CreateReadOnlySpan(ref Unsafe.As(ref Unsafe.AsRef(in _weights)), _size); + + /// + /// The smallest weight + /// + public readonly W MinWeight => _size > 0 ? Weights[_size - 1] : W.MaxValue; + + /// + /// The largest weight + /// + public readonly W MaxWeight => _size > 0 ? Weights[0] : W.MinValue; + + /// + /// The value with the smallest weight + /// + public readonly V? MinValue => _size > 0 ? Values[_size - 1] : default; + + /// + /// The value with the largest weight + /// + public readonly V? MaxValue => _size > 0 ? Values[0] : default; + + /// + /// Returns a value and weight + /// + /// Index to return + public readonly (V Value, W Weight) this[byte index] + { + get + { + if (index < Size) + return (Values[index], Weights[index]); + throw new ArgumentOutOfRangeException(); + } + } + + /// + /// Enumerates the values and weights + /// + public readonly IEnumerable<(V Value, W Weight)> Elements + { + get + { + for (byte i = 0; i < Size; i++) + yield return this[i]; + } + } + + /// + /// Tries to add a new element - will succeed if there aren't already max elements with a smaller weight + /// + /// Value to add + /// Weight to add + /// True if values should be unique - will return false if the value already exists + /// True if the element was added + public bool TryAdd(V value, W weight, bool enforceUnique = true) + { + var values = MemoryMarshal.CreateSpan(ref Unsafe.As(ref Unsafe.AsRef(in _values)), MaxSize); + var weights = MemoryMarshal.CreateSpan(ref Unsafe.As(ref Unsafe.AsRef(in _weights)), MaxSize); + return FixedSizeSortedArrayHelper.InsertIntoDescending(enforceUnique, ref _size, MaxSize, value, weight, values, weights); + } + + /// + /// Removes an element from the array + /// + /// Index of element to remove + /// + public void RemoveAt(byte index) + { + if(index >= _size) + throw new ArgumentOutOfRangeException(); + var values = MemoryMarshal.CreateSpan(ref Unsafe.As(ref Unsafe.AsRef(in _values)), _size); + var weights = MemoryMarshal.CreateSpan(ref Unsafe.As(ref Unsafe.AsRef(in _weights)), _size); + FixedSizeSortedArrayHelper.RemoveAt(index, values, weights); + --_size; + } + } + + /// + /// Fixed size sorted array of values and weights (max 17 elements) + /// that is sorted in ascending order based on each weight + /// + /// Type of value to store + /// Type of weight that will be used to sort + public record struct FixedSizeSortedAscending17Array() : IFixedSizeSortedArray + where V : IComparable + where W : unmanaged, INumber, IMinMaxValue + { + /// + /// Max size of the array + /// + public const int MaxSize = 17; + byte IFixedSizeSortedArray.MaxSize => MaxSize; + + [InlineArray(MaxSize)] + internal struct ValueArray + { + public V _element0; + } + [InlineArray(MaxSize)] + internal struct WeightArray + { + public W _element0; + } + readonly ValueArray _values = new(); + readonly WeightArray _weights = new(); + byte _size = 0; + + /// + /// Current number of elements + /// + public readonly byte Size => _size; + + /// + /// Sorted list of values + /// + public readonly ReadOnlySpan Values => MemoryMarshal.CreateReadOnlySpan(ref Unsafe.As(ref Unsafe.AsRef(in _values)), _size); + + /// + /// Sorted list of weights + /// + public readonly ReadOnlySpan Weights => MemoryMarshal.CreateReadOnlySpan(ref Unsafe.As(ref Unsafe.AsRef(in _weights)), _size); + + /// + /// The smallest weight + /// + public readonly W MinWeight => _size > 0 ? Weights[0] : W.MaxValue; + + /// + /// The largest weight + /// + public readonly W MaxWeight => _size > 0 ? Weights[_size - 1] : W.MinValue; + + /// + /// The value with the smallest weight + /// + public readonly V? MinValue => _size > 0 ? Values[0] : default; + + /// + /// The value with the largest weight + /// + public readonly V? MaxValue => _size > 0 ? Values[_size - 1] : default; + + /// + /// Returns a value and weight + /// + /// Index to return + public readonly (V Value, W Weight) this[byte index] + { + get + { + if (index < Size) + return (Values[index], Weights[index]); + throw new ArgumentOutOfRangeException(); + } + } + + /// + /// Enumerates the values and weights + /// + public readonly IEnumerable<(V Value, W Weight)> Elements + { + get + { + for (byte i = 0; i < Size; i++) + yield return this[i]; + } + } + + /// + /// Tries to add a new element - will succeed if there aren't already max elements with a smaller weight + /// + /// Value to add + /// Weight to add + /// True if values should be unique - will return false if the value already exists + /// True if the element was added + public bool TryAdd(V value, W weight, bool enforceUnique = true) + { + var values = MemoryMarshal.CreateSpan(ref Unsafe.As(ref Unsafe.AsRef(in _values)), MaxSize); + var weights = MemoryMarshal.CreateSpan(ref Unsafe.As(ref Unsafe.AsRef(in _weights)), MaxSize); + return FixedSizeSortedArrayHelper.InsertIntoAscending(enforceUnique, ref _size, MaxSize, value, weight, values, weights); + } + + /// + /// Removes an element from the array + /// + /// Index of element to remove + /// + public void RemoveAt(byte index) + { + if(index >= _size) + throw new ArgumentOutOfRangeException(); + var values = MemoryMarshal.CreateSpan(ref Unsafe.As(ref Unsafe.AsRef(in _values)), _size); + var weights = MemoryMarshal.CreateSpan(ref Unsafe.As(ref Unsafe.AsRef(in _weights)), _size); + FixedSizeSortedArrayHelper.RemoveAt(index, values, weights); + --_size; + } + } + + /// + /// Fixed size sorted array of values and weights (max 17 elements) + /// that is sorted in descending order based on each weight + /// + /// Type of value to store + /// Type of weight that will be used to sort + public record struct FixedSizeSortedDescending17Array() + where V : IComparable + where W : unmanaged, INumber, IMinMaxValue + { + /// + /// Max size of the array + /// + public const int MaxSize = 17; + + [InlineArray(MaxSize)] + internal struct ValueArray + { + public V _element0; + } + [InlineArray(MaxSize)] + internal struct WeightArray + { + public W _element0; + } + readonly ValueArray _values = new(); + readonly WeightArray _weights = new(); + byte _size = 0; + + /// + /// Current number of elements + /// + public readonly byte Size => _size; + + /// + /// Sorted list of values + /// + public readonly ReadOnlySpan Values => MemoryMarshal.CreateReadOnlySpan(ref Unsafe.As(ref Unsafe.AsRef(in _values)), _size); + + /// + /// Sorted list of weights + /// + public readonly ReadOnlySpan Weights => MemoryMarshal.CreateReadOnlySpan(ref Unsafe.As(ref Unsafe.AsRef(in _weights)), _size); + + /// + /// The smallest weight + /// + public readonly W MinWeight => _size > 0 ? Weights[_size - 1] : W.MaxValue; + + /// + /// The largest weight + /// + public readonly W MaxWeight => _size > 0 ? Weights[0] : W.MinValue; + + /// + /// The value with the smallest weight + /// + public readonly V? MinValue => _size > 0 ? Values[_size - 1] : default; + + /// + /// The value with the largest weight + /// + public readonly V? MaxValue => _size > 0 ? Values[0] : default; + + /// + /// Returns a value and weight + /// + /// Index to return + public readonly (V Value, W Weight) this[byte index] + { + get + { + if (index < Size) + return (Values[index], Weights[index]); + throw new ArgumentOutOfRangeException(); + } + } + + /// + /// Enumerates the values and weights + /// + public readonly IEnumerable<(V Value, W Weight)> Elements + { + get + { + for (byte i = 0; i < Size; i++) + yield return this[i]; + } + } + + /// + /// Tries to add a new element - will succeed if there aren't already max elements with a smaller weight + /// + /// Value to add + /// Weight to add + /// True if values should be unique - will return false if the value already exists + /// True if the element was added + public bool TryAdd(V value, W weight, bool enforceUnique = true) + { + var values = MemoryMarshal.CreateSpan(ref Unsafe.As(ref Unsafe.AsRef(in _values)), MaxSize); + var weights = MemoryMarshal.CreateSpan(ref Unsafe.As(ref Unsafe.AsRef(in _weights)), MaxSize); + return FixedSizeSortedArrayHelper.InsertIntoDescending(enforceUnique, ref _size, MaxSize, value, weight, values, weights); + } + + /// + /// Removes an element from the array + /// + /// Index of element to remove + /// + public void RemoveAt(byte index) + { + if(index >= _size) + throw new ArgumentOutOfRangeException(); + var values = MemoryMarshal.CreateSpan(ref Unsafe.As(ref Unsafe.AsRef(in _values)), _size); + var weights = MemoryMarshal.CreateSpan(ref Unsafe.As(ref Unsafe.AsRef(in _weights)), _size); + FixedSizeSortedArrayHelper.RemoveAt(index, values, weights); + --_size; + } + } + + /// + /// Fixed size sorted array of values and weights (max 18 elements) + /// that is sorted in ascending order based on each weight + /// + /// Type of value to store + /// Type of weight that will be used to sort + public record struct FixedSizeSortedAscending18Array() : IFixedSizeSortedArray + where V : IComparable + where W : unmanaged, INumber, IMinMaxValue + { + /// + /// Max size of the array + /// + public const int MaxSize = 18; + byte IFixedSizeSortedArray.MaxSize => MaxSize; + + [InlineArray(MaxSize)] + internal struct ValueArray + { + public V _element0; + } + [InlineArray(MaxSize)] + internal struct WeightArray + { + public W _element0; + } + readonly ValueArray _values = new(); + readonly WeightArray _weights = new(); + byte _size = 0; + + /// + /// Current number of elements + /// + public readonly byte Size => _size; + + /// + /// Sorted list of values + /// + public readonly ReadOnlySpan Values => MemoryMarshal.CreateReadOnlySpan(ref Unsafe.As(ref Unsafe.AsRef(in _values)), _size); + + /// + /// Sorted list of weights + /// + public readonly ReadOnlySpan Weights => MemoryMarshal.CreateReadOnlySpan(ref Unsafe.As(ref Unsafe.AsRef(in _weights)), _size); + + /// + /// The smallest weight + /// + public readonly W MinWeight => _size > 0 ? Weights[0] : W.MaxValue; + + /// + /// The largest weight + /// + public readonly W MaxWeight => _size > 0 ? Weights[_size - 1] : W.MinValue; + + /// + /// The value with the smallest weight + /// + public readonly V? MinValue => _size > 0 ? Values[0] : default; + + /// + /// The value with the largest weight + /// + public readonly V? MaxValue => _size > 0 ? Values[_size - 1] : default; + + /// + /// Returns a value and weight + /// + /// Index to return + public readonly (V Value, W Weight) this[byte index] + { + get + { + if (index < Size) + return (Values[index], Weights[index]); + throw new ArgumentOutOfRangeException(); + } + } + + /// + /// Enumerates the values and weights + /// + public readonly IEnumerable<(V Value, W Weight)> Elements + { + get + { + for (byte i = 0; i < Size; i++) + yield return this[i]; + } + } + + /// + /// Tries to add a new element - will succeed if there aren't already max elements with a smaller weight + /// + /// Value to add + /// Weight to add + /// True if values should be unique - will return false if the value already exists + /// True if the element was added + public bool TryAdd(V value, W weight, bool enforceUnique = true) + { + var values = MemoryMarshal.CreateSpan(ref Unsafe.As(ref Unsafe.AsRef(in _values)), MaxSize); + var weights = MemoryMarshal.CreateSpan(ref Unsafe.As(ref Unsafe.AsRef(in _weights)), MaxSize); + return FixedSizeSortedArrayHelper.InsertIntoAscending(enforceUnique, ref _size, MaxSize, value, weight, values, weights); + } + + /// + /// Removes an element from the array + /// + /// Index of element to remove + /// + public void RemoveAt(byte index) + { + if(index >= _size) + throw new ArgumentOutOfRangeException(); + var values = MemoryMarshal.CreateSpan(ref Unsafe.As(ref Unsafe.AsRef(in _values)), _size); + var weights = MemoryMarshal.CreateSpan(ref Unsafe.As(ref Unsafe.AsRef(in _weights)), _size); + FixedSizeSortedArrayHelper.RemoveAt(index, values, weights); + --_size; + } + } + + /// + /// Fixed size sorted array of values and weights (max 18 elements) + /// that is sorted in descending order based on each weight + /// + /// Type of value to store + /// Type of weight that will be used to sort + public record struct FixedSizeSortedDescending18Array() + where V : IComparable + where W : unmanaged, INumber, IMinMaxValue + { + /// + /// Max size of the array + /// + public const int MaxSize = 18; + + [InlineArray(MaxSize)] + internal struct ValueArray + { + public V _element0; + } + [InlineArray(MaxSize)] + internal struct WeightArray + { + public W _element0; + } + readonly ValueArray _values = new(); + readonly WeightArray _weights = new(); + byte _size = 0; + + /// + /// Current number of elements + /// + public readonly byte Size => _size; + + /// + /// Sorted list of values + /// + public readonly ReadOnlySpan Values => MemoryMarshal.CreateReadOnlySpan(ref Unsafe.As(ref Unsafe.AsRef(in _values)), _size); + + /// + /// Sorted list of weights + /// + public readonly ReadOnlySpan Weights => MemoryMarshal.CreateReadOnlySpan(ref Unsafe.As(ref Unsafe.AsRef(in _weights)), _size); + + /// + /// The smallest weight + /// + public readonly W MinWeight => _size > 0 ? Weights[_size - 1] : W.MaxValue; + + /// + /// The largest weight + /// + public readonly W MaxWeight => _size > 0 ? Weights[0] : W.MinValue; + + /// + /// The value with the smallest weight + /// + public readonly V? MinValue => _size > 0 ? Values[_size - 1] : default; + + /// + /// The value with the largest weight + /// + public readonly V? MaxValue => _size > 0 ? Values[0] : default; + + /// + /// Returns a value and weight + /// + /// Index to return + public readonly (V Value, W Weight) this[byte index] + { + get + { + if (index < Size) + return (Values[index], Weights[index]); + throw new ArgumentOutOfRangeException(); + } + } + + /// + /// Enumerates the values and weights + /// + public readonly IEnumerable<(V Value, W Weight)> Elements + { + get + { + for (byte i = 0; i < Size; i++) + yield return this[i]; + } + } + + /// + /// Tries to add a new element - will succeed if there aren't already max elements with a smaller weight + /// + /// Value to add + /// Weight to add + /// True if values should be unique - will return false if the value already exists + /// True if the element was added + public bool TryAdd(V value, W weight, bool enforceUnique = true) + { + var values = MemoryMarshal.CreateSpan(ref Unsafe.As(ref Unsafe.AsRef(in _values)), MaxSize); + var weights = MemoryMarshal.CreateSpan(ref Unsafe.As(ref Unsafe.AsRef(in _weights)), MaxSize); + return FixedSizeSortedArrayHelper.InsertIntoDescending(enforceUnique, ref _size, MaxSize, value, weight, values, weights); + } + + /// + /// Removes an element from the array + /// + /// Index of element to remove + /// + public void RemoveAt(byte index) + { + if(index >= _size) + throw new ArgumentOutOfRangeException(); + var values = MemoryMarshal.CreateSpan(ref Unsafe.As(ref Unsafe.AsRef(in _values)), _size); + var weights = MemoryMarshal.CreateSpan(ref Unsafe.As(ref Unsafe.AsRef(in _weights)), _size); + FixedSizeSortedArrayHelper.RemoveAt(index, values, weights); + --_size; + } + } + + /// + /// Fixed size sorted array of values and weights (max 19 elements) + /// that is sorted in ascending order based on each weight + /// + /// Type of value to store + /// Type of weight that will be used to sort + public record struct FixedSizeSortedAscending19Array() : IFixedSizeSortedArray + where V : IComparable + where W : unmanaged, INumber, IMinMaxValue + { + /// + /// Max size of the array + /// + public const int MaxSize = 19; + byte IFixedSizeSortedArray.MaxSize => MaxSize; + + [InlineArray(MaxSize)] + internal struct ValueArray + { + public V _element0; + } + [InlineArray(MaxSize)] + internal struct WeightArray + { + public W _element0; + } + readonly ValueArray _values = new(); + readonly WeightArray _weights = new(); + byte _size = 0; + + /// + /// Current number of elements + /// + public readonly byte Size => _size; + + /// + /// Sorted list of values + /// + public readonly ReadOnlySpan Values => MemoryMarshal.CreateReadOnlySpan(ref Unsafe.As(ref Unsafe.AsRef(in _values)), _size); + + /// + /// Sorted list of weights + /// + public readonly ReadOnlySpan Weights => MemoryMarshal.CreateReadOnlySpan(ref Unsafe.As(ref Unsafe.AsRef(in _weights)), _size); + + /// + /// The smallest weight + /// + public readonly W MinWeight => _size > 0 ? Weights[0] : W.MaxValue; + + /// + /// The largest weight + /// + public readonly W MaxWeight => _size > 0 ? Weights[_size - 1] : W.MinValue; + + /// + /// The value with the smallest weight + /// + public readonly V? MinValue => _size > 0 ? Values[0] : default; + + /// + /// The value with the largest weight + /// + public readonly V? MaxValue => _size > 0 ? Values[_size - 1] : default; + + /// + /// Returns a value and weight + /// + /// Index to return + public readonly (V Value, W Weight) this[byte index] + { + get + { + if (index < Size) + return (Values[index], Weights[index]); + throw new ArgumentOutOfRangeException(); + } + } + + /// + /// Enumerates the values and weights + /// + public readonly IEnumerable<(V Value, W Weight)> Elements + { + get + { + for (byte i = 0; i < Size; i++) + yield return this[i]; + } + } + + /// + /// Tries to add a new element - will succeed if there aren't already max elements with a smaller weight + /// + /// Value to add + /// Weight to add + /// True if values should be unique - will return false if the value already exists + /// True if the element was added + public bool TryAdd(V value, W weight, bool enforceUnique = true) + { + var values = MemoryMarshal.CreateSpan(ref Unsafe.As(ref Unsafe.AsRef(in _values)), MaxSize); + var weights = MemoryMarshal.CreateSpan(ref Unsafe.As(ref Unsafe.AsRef(in _weights)), MaxSize); + return FixedSizeSortedArrayHelper.InsertIntoAscending(enforceUnique, ref _size, MaxSize, value, weight, values, weights); + } + + /// + /// Removes an element from the array + /// + /// Index of element to remove + /// + public void RemoveAt(byte index) + { + if(index >= _size) + throw new ArgumentOutOfRangeException(); + var values = MemoryMarshal.CreateSpan(ref Unsafe.As(ref Unsafe.AsRef(in _values)), _size); + var weights = MemoryMarshal.CreateSpan(ref Unsafe.As(ref Unsafe.AsRef(in _weights)), _size); + FixedSizeSortedArrayHelper.RemoveAt(index, values, weights); + --_size; + } + } + + /// + /// Fixed size sorted array of values and weights (max 19 elements) + /// that is sorted in descending order based on each weight + /// + /// Type of value to store + /// Type of weight that will be used to sort + public record struct FixedSizeSortedDescending19Array() + where V : IComparable + where W : unmanaged, INumber, IMinMaxValue + { + /// + /// Max size of the array + /// + public const int MaxSize = 19; + + [InlineArray(MaxSize)] + internal struct ValueArray + { + public V _element0; + } + [InlineArray(MaxSize)] + internal struct WeightArray + { + public W _element0; + } + readonly ValueArray _values = new(); + readonly WeightArray _weights = new(); + byte _size = 0; + + /// + /// Current number of elements + /// + public readonly byte Size => _size; + + /// + /// Sorted list of values + /// + public readonly ReadOnlySpan Values => MemoryMarshal.CreateReadOnlySpan(ref Unsafe.As(ref Unsafe.AsRef(in _values)), _size); + + /// + /// Sorted list of weights + /// + public readonly ReadOnlySpan Weights => MemoryMarshal.CreateReadOnlySpan(ref Unsafe.As(ref Unsafe.AsRef(in _weights)), _size); + + /// + /// The smallest weight + /// + public readonly W MinWeight => _size > 0 ? Weights[_size - 1] : W.MaxValue; + + /// + /// The largest weight + /// + public readonly W MaxWeight => _size > 0 ? Weights[0] : W.MinValue; + + /// + /// The value with the smallest weight + /// + public readonly V? MinValue => _size > 0 ? Values[_size - 1] : default; + + /// + /// The value with the largest weight + /// + public readonly V? MaxValue => _size > 0 ? Values[0] : default; + + /// + /// Returns a value and weight + /// + /// Index to return + public readonly (V Value, W Weight) this[byte index] + { + get + { + if (index < Size) + return (Values[index], Weights[index]); + throw new ArgumentOutOfRangeException(); + } + } + + /// + /// Enumerates the values and weights + /// + public readonly IEnumerable<(V Value, W Weight)> Elements + { + get + { + for (byte i = 0; i < Size; i++) + yield return this[i]; + } + } + + /// + /// Tries to add a new element - will succeed if there aren't already max elements with a smaller weight + /// + /// Value to add + /// Weight to add + /// True if values should be unique - will return false if the value already exists + /// True if the element was added + public bool TryAdd(V value, W weight, bool enforceUnique = true) + { + var values = MemoryMarshal.CreateSpan(ref Unsafe.As(ref Unsafe.AsRef(in _values)), MaxSize); + var weights = MemoryMarshal.CreateSpan(ref Unsafe.As(ref Unsafe.AsRef(in _weights)), MaxSize); + return FixedSizeSortedArrayHelper.InsertIntoDescending(enforceUnique, ref _size, MaxSize, value, weight, values, weights); + } + + /// + /// Removes an element from the array + /// + /// Index of element to remove + /// + public void RemoveAt(byte index) + { + if(index >= _size) + throw new ArgumentOutOfRangeException(); + var values = MemoryMarshal.CreateSpan(ref Unsafe.As(ref Unsafe.AsRef(in _values)), _size); + var weights = MemoryMarshal.CreateSpan(ref Unsafe.As(ref Unsafe.AsRef(in _weights)), _size); + FixedSizeSortedArrayHelper.RemoveAt(index, values, weights); + --_size; + } + } + + /// + /// Fixed size sorted array of values and weights (max 20 elements) + /// that is sorted in ascending order based on each weight + /// + /// Type of value to store + /// Type of weight that will be used to sort + public record struct FixedSizeSortedAscending20Array() : IFixedSizeSortedArray + where V : IComparable + where W : unmanaged, INumber, IMinMaxValue + { + /// + /// Max size of the array + /// + public const int MaxSize = 20; + byte IFixedSizeSortedArray.MaxSize => MaxSize; + + [InlineArray(MaxSize)] + internal struct ValueArray + { + public V _element0; + } + [InlineArray(MaxSize)] + internal struct WeightArray + { + public W _element0; + } + readonly ValueArray _values = new(); + readonly WeightArray _weights = new(); + byte _size = 0; + + /// + /// Current number of elements + /// + public readonly byte Size => _size; + + /// + /// Sorted list of values + /// + public readonly ReadOnlySpan Values => MemoryMarshal.CreateReadOnlySpan(ref Unsafe.As(ref Unsafe.AsRef(in _values)), _size); + + /// + /// Sorted list of weights + /// + public readonly ReadOnlySpan Weights => MemoryMarshal.CreateReadOnlySpan(ref Unsafe.As(ref Unsafe.AsRef(in _weights)), _size); + + /// + /// The smallest weight + /// + public readonly W MinWeight => _size > 0 ? Weights[0] : W.MaxValue; + + /// + /// The largest weight + /// + public readonly W MaxWeight => _size > 0 ? Weights[_size - 1] : W.MinValue; + + /// + /// The value with the smallest weight + /// + public readonly V? MinValue => _size > 0 ? Values[0] : default; + + /// + /// The value with the largest weight + /// + public readonly V? MaxValue => _size > 0 ? Values[_size - 1] : default; + + /// + /// Returns a value and weight + /// + /// Index to return + public readonly (V Value, W Weight) this[byte index] + { + get + { + if (index < Size) + return (Values[index], Weights[index]); + throw new ArgumentOutOfRangeException(); + } + } + + /// + /// Enumerates the values and weights + /// + public readonly IEnumerable<(V Value, W Weight)> Elements + { + get + { + for (byte i = 0; i < Size; i++) + yield return this[i]; + } + } + + /// + /// Tries to add a new element - will succeed if there aren't already max elements with a smaller weight + /// + /// Value to add + /// Weight to add + /// True if values should be unique - will return false if the value already exists + /// True if the element was added + public bool TryAdd(V value, W weight, bool enforceUnique = true) + { + var values = MemoryMarshal.CreateSpan(ref Unsafe.As(ref Unsafe.AsRef(in _values)), MaxSize); + var weights = MemoryMarshal.CreateSpan(ref Unsafe.As(ref Unsafe.AsRef(in _weights)), MaxSize); + return FixedSizeSortedArrayHelper.InsertIntoAscending(enforceUnique, ref _size, MaxSize, value, weight, values, weights); + } + + /// + /// Removes an element from the array + /// + /// Index of element to remove + /// + public void RemoveAt(byte index) + { + if(index >= _size) + throw new ArgumentOutOfRangeException(); + var values = MemoryMarshal.CreateSpan(ref Unsafe.As(ref Unsafe.AsRef(in _values)), _size); + var weights = MemoryMarshal.CreateSpan(ref Unsafe.As(ref Unsafe.AsRef(in _weights)), _size); + FixedSizeSortedArrayHelper.RemoveAt(index, values, weights); + --_size; + } + } + + /// + /// Fixed size sorted array of values and weights (max 20 elements) + /// that is sorted in descending order based on each weight + /// + /// Type of value to store + /// Type of weight that will be used to sort + public record struct FixedSizeSortedDescending20Array() + where V : IComparable + where W : unmanaged, INumber, IMinMaxValue + { + /// + /// Max size of the array + /// + public const int MaxSize = 20; + + [InlineArray(MaxSize)] + internal struct ValueArray + { + public V _element0; + } + [InlineArray(MaxSize)] + internal struct WeightArray + { + public W _element0; + } + readonly ValueArray _values = new(); + readonly WeightArray _weights = new(); + byte _size = 0; + + /// + /// Current number of elements + /// + public readonly byte Size => _size; + + /// + /// Sorted list of values + /// + public readonly ReadOnlySpan Values => MemoryMarshal.CreateReadOnlySpan(ref Unsafe.As(ref Unsafe.AsRef(in _values)), _size); + + /// + /// Sorted list of weights + /// + public readonly ReadOnlySpan Weights => MemoryMarshal.CreateReadOnlySpan(ref Unsafe.As(ref Unsafe.AsRef(in _weights)), _size); + + /// + /// The smallest weight + /// + public readonly W MinWeight => _size > 0 ? Weights[_size - 1] : W.MaxValue; + + /// + /// The largest weight + /// + public readonly W MaxWeight => _size > 0 ? Weights[0] : W.MinValue; + + /// + /// The value with the smallest weight + /// + public readonly V? MinValue => _size > 0 ? Values[_size - 1] : default; + + /// + /// The value with the largest weight + /// + public readonly V? MaxValue => _size > 0 ? Values[0] : default; + + /// + /// Returns a value and weight + /// + /// Index to return + public readonly (V Value, W Weight) this[byte index] + { + get + { + if (index < Size) + return (Values[index], Weights[index]); + throw new ArgumentOutOfRangeException(); + } + } + + /// + /// Enumerates the values and weights + /// + public readonly IEnumerable<(V Value, W Weight)> Elements + { + get + { + for (byte i = 0; i < Size; i++) + yield return this[i]; + } + } + + /// + /// Tries to add a new element - will succeed if there aren't already max elements with a smaller weight + /// + /// Value to add + /// Weight to add + /// True if values should be unique - will return false if the value already exists + /// True if the element was added + public bool TryAdd(V value, W weight, bool enforceUnique = true) + { + var values = MemoryMarshal.CreateSpan(ref Unsafe.As(ref Unsafe.AsRef(in _values)), MaxSize); + var weights = MemoryMarshal.CreateSpan(ref Unsafe.As(ref Unsafe.AsRef(in _weights)), MaxSize); + return FixedSizeSortedArrayHelper.InsertIntoDescending(enforceUnique, ref _size, MaxSize, value, weight, values, weights); + } + + /// + /// Removes an element from the array + /// + /// Index of element to remove + /// + public void RemoveAt(byte index) + { + if(index >= _size) + throw new ArgumentOutOfRangeException(); + var values = MemoryMarshal.CreateSpan(ref Unsafe.As(ref Unsafe.AsRef(in _values)), _size); + var weights = MemoryMarshal.CreateSpan(ref Unsafe.As(ref Unsafe.AsRef(in _weights)), _size); + FixedSizeSortedArrayHelper.RemoveAt(index, values, weights); + --_size; + } + } + + /// + /// Fixed size sorted array of values and weights (max 21 elements) + /// that is sorted in ascending order based on each weight + /// + /// Type of value to store + /// Type of weight that will be used to sort + public record struct FixedSizeSortedAscending21Array() : IFixedSizeSortedArray + where V : IComparable + where W : unmanaged, INumber, IMinMaxValue + { + /// + /// Max size of the array + /// + public const int MaxSize = 21; + byte IFixedSizeSortedArray.MaxSize => MaxSize; + + [InlineArray(MaxSize)] + internal struct ValueArray + { + public V _element0; + } + [InlineArray(MaxSize)] + internal struct WeightArray + { + public W _element0; + } + readonly ValueArray _values = new(); + readonly WeightArray _weights = new(); + byte _size = 0; + + /// + /// Current number of elements + /// + public readonly byte Size => _size; + + /// + /// Sorted list of values + /// + public readonly ReadOnlySpan Values => MemoryMarshal.CreateReadOnlySpan(ref Unsafe.As(ref Unsafe.AsRef(in _values)), _size); + + /// + /// Sorted list of weights + /// + public readonly ReadOnlySpan Weights => MemoryMarshal.CreateReadOnlySpan(ref Unsafe.As(ref Unsafe.AsRef(in _weights)), _size); + + /// + /// The smallest weight + /// + public readonly W MinWeight => _size > 0 ? Weights[0] : W.MaxValue; + + /// + /// The largest weight + /// + public readonly W MaxWeight => _size > 0 ? Weights[_size - 1] : W.MinValue; + + /// + /// The value with the smallest weight + /// + public readonly V? MinValue => _size > 0 ? Values[0] : default; + + /// + /// The value with the largest weight + /// + public readonly V? MaxValue => _size > 0 ? Values[_size - 1] : default; + + /// + /// Returns a value and weight + /// + /// Index to return + public readonly (V Value, W Weight) this[byte index] + { + get + { + if (index < Size) + return (Values[index], Weights[index]); + throw new ArgumentOutOfRangeException(); + } + } + + /// + /// Enumerates the values and weights + /// + public readonly IEnumerable<(V Value, W Weight)> Elements + { + get + { + for (byte i = 0; i < Size; i++) + yield return this[i]; + } + } + + /// + /// Tries to add a new element - will succeed if there aren't already max elements with a smaller weight + /// + /// Value to add + /// Weight to add + /// True if values should be unique - will return false if the value already exists + /// True if the element was added + public bool TryAdd(V value, W weight, bool enforceUnique = true) + { + var values = MemoryMarshal.CreateSpan(ref Unsafe.As(ref Unsafe.AsRef(in _values)), MaxSize); + var weights = MemoryMarshal.CreateSpan(ref Unsafe.As(ref Unsafe.AsRef(in _weights)), MaxSize); + return FixedSizeSortedArrayHelper.InsertIntoAscending(enforceUnique, ref _size, MaxSize, value, weight, values, weights); + } + + /// + /// Removes an element from the array + /// + /// Index of element to remove + /// + public void RemoveAt(byte index) + { + if(index >= _size) + throw new ArgumentOutOfRangeException(); + var values = MemoryMarshal.CreateSpan(ref Unsafe.As(ref Unsafe.AsRef(in _values)), _size); + var weights = MemoryMarshal.CreateSpan(ref Unsafe.As(ref Unsafe.AsRef(in _weights)), _size); + FixedSizeSortedArrayHelper.RemoveAt(index, values, weights); + --_size; + } + } + + /// + /// Fixed size sorted array of values and weights (max 21 elements) + /// that is sorted in descending order based on each weight + /// + /// Type of value to store + /// Type of weight that will be used to sort + public record struct FixedSizeSortedDescending21Array() + where V : IComparable + where W : unmanaged, INumber, IMinMaxValue + { + /// + /// Max size of the array + /// + public const int MaxSize = 21; + + [InlineArray(MaxSize)] + internal struct ValueArray + { + public V _element0; + } + [InlineArray(MaxSize)] + internal struct WeightArray + { + public W _element0; + } + readonly ValueArray _values = new(); + readonly WeightArray _weights = new(); + byte _size = 0; + + /// + /// Current number of elements + /// + public readonly byte Size => _size; + + /// + /// Sorted list of values + /// + public readonly ReadOnlySpan Values => MemoryMarshal.CreateReadOnlySpan(ref Unsafe.As(ref Unsafe.AsRef(in _values)), _size); + + /// + /// Sorted list of weights + /// + public readonly ReadOnlySpan Weights => MemoryMarshal.CreateReadOnlySpan(ref Unsafe.As(ref Unsafe.AsRef(in _weights)), _size); + + /// + /// The smallest weight + /// + public readonly W MinWeight => _size > 0 ? Weights[_size - 1] : W.MaxValue; + + /// + /// The largest weight + /// + public readonly W MaxWeight => _size > 0 ? Weights[0] : W.MinValue; + + /// + /// The value with the smallest weight + /// + public readonly V? MinValue => _size > 0 ? Values[_size - 1] : default; + + /// + /// The value with the largest weight + /// + public readonly V? MaxValue => _size > 0 ? Values[0] : default; + + /// + /// Returns a value and weight + /// + /// Index to return + public readonly (V Value, W Weight) this[byte index] + { + get + { + if (index < Size) + return (Values[index], Weights[index]); + throw new ArgumentOutOfRangeException(); + } + } + + /// + /// Enumerates the values and weights + /// + public readonly IEnumerable<(V Value, W Weight)> Elements + { + get + { + for (byte i = 0; i < Size; i++) + yield return this[i]; + } + } + + /// + /// Tries to add a new element - will succeed if there aren't already max elements with a smaller weight + /// + /// Value to add + /// Weight to add + /// True if values should be unique - will return false if the value already exists + /// True if the element was added + public bool TryAdd(V value, W weight, bool enforceUnique = true) + { + var values = MemoryMarshal.CreateSpan(ref Unsafe.As(ref Unsafe.AsRef(in _values)), MaxSize); + var weights = MemoryMarshal.CreateSpan(ref Unsafe.As(ref Unsafe.AsRef(in _weights)), MaxSize); + return FixedSizeSortedArrayHelper.InsertIntoDescending(enforceUnique, ref _size, MaxSize, value, weight, values, weights); + } + + /// + /// Removes an element from the array + /// + /// Index of element to remove + /// + public void RemoveAt(byte index) + { + if(index >= _size) + throw new ArgumentOutOfRangeException(); + var values = MemoryMarshal.CreateSpan(ref Unsafe.As(ref Unsafe.AsRef(in _values)), _size); + var weights = MemoryMarshal.CreateSpan(ref Unsafe.As(ref Unsafe.AsRef(in _weights)), _size); + FixedSizeSortedArrayHelper.RemoveAt(index, values, weights); + --_size; + } + } + + /// + /// Fixed size sorted array of values and weights (max 22 elements) + /// that is sorted in ascending order based on each weight + /// + /// Type of value to store + /// Type of weight that will be used to sort + public record struct FixedSizeSortedAscending22Array() : IFixedSizeSortedArray + where V : IComparable + where W : unmanaged, INumber, IMinMaxValue + { + /// + /// Max size of the array + /// + public const int MaxSize = 22; + byte IFixedSizeSortedArray.MaxSize => MaxSize; + + [InlineArray(MaxSize)] + internal struct ValueArray + { + public V _element0; + } + [InlineArray(MaxSize)] + internal struct WeightArray + { + public W _element0; + } + readonly ValueArray _values = new(); + readonly WeightArray _weights = new(); + byte _size = 0; + + /// + /// Current number of elements + /// + public readonly byte Size => _size; + + /// + /// Sorted list of values + /// + public readonly ReadOnlySpan Values => MemoryMarshal.CreateReadOnlySpan(ref Unsafe.As(ref Unsafe.AsRef(in _values)), _size); + + /// + /// Sorted list of weights + /// + public readonly ReadOnlySpan Weights => MemoryMarshal.CreateReadOnlySpan(ref Unsafe.As(ref Unsafe.AsRef(in _weights)), _size); + + /// + /// The smallest weight + /// + public readonly W MinWeight => _size > 0 ? Weights[0] : W.MaxValue; + + /// + /// The largest weight + /// + public readonly W MaxWeight => _size > 0 ? Weights[_size - 1] : W.MinValue; + + /// + /// The value with the smallest weight + /// + public readonly V? MinValue => _size > 0 ? Values[0] : default; + + /// + /// The value with the largest weight + /// + public readonly V? MaxValue => _size > 0 ? Values[_size - 1] : default; + + /// + /// Returns a value and weight + /// + /// Index to return + public readonly (V Value, W Weight) this[byte index] + { + get + { + if (index < Size) + return (Values[index], Weights[index]); + throw new ArgumentOutOfRangeException(); + } + } + + /// + /// Enumerates the values and weights + /// + public readonly IEnumerable<(V Value, W Weight)> Elements + { + get + { + for (byte i = 0; i < Size; i++) + yield return this[i]; + } + } + + /// + /// Tries to add a new element - will succeed if there aren't already max elements with a smaller weight + /// + /// Value to add + /// Weight to add + /// True if values should be unique - will return false if the value already exists + /// True if the element was added + public bool TryAdd(V value, W weight, bool enforceUnique = true) + { + var values = MemoryMarshal.CreateSpan(ref Unsafe.As(ref Unsafe.AsRef(in _values)), MaxSize); + var weights = MemoryMarshal.CreateSpan(ref Unsafe.As(ref Unsafe.AsRef(in _weights)), MaxSize); + return FixedSizeSortedArrayHelper.InsertIntoAscending(enforceUnique, ref _size, MaxSize, value, weight, values, weights); + } + + /// + /// Removes an element from the array + /// + /// Index of element to remove + /// + public void RemoveAt(byte index) + { + if(index >= _size) + throw new ArgumentOutOfRangeException(); + var values = MemoryMarshal.CreateSpan(ref Unsafe.As(ref Unsafe.AsRef(in _values)), _size); + var weights = MemoryMarshal.CreateSpan(ref Unsafe.As(ref Unsafe.AsRef(in _weights)), _size); + FixedSizeSortedArrayHelper.RemoveAt(index, values, weights); + --_size; + } + } + + /// + /// Fixed size sorted array of values and weights (max 22 elements) + /// that is sorted in descending order based on each weight + /// + /// Type of value to store + /// Type of weight that will be used to sort + public record struct FixedSizeSortedDescending22Array() + where V : IComparable + where W : unmanaged, INumber, IMinMaxValue + { + /// + /// Max size of the array + /// + public const int MaxSize = 22; + + [InlineArray(MaxSize)] + internal struct ValueArray + { + public V _element0; + } + [InlineArray(MaxSize)] + internal struct WeightArray + { + public W _element0; + } + readonly ValueArray _values = new(); + readonly WeightArray _weights = new(); + byte _size = 0; + + /// + /// Current number of elements + /// + public readonly byte Size => _size; + + /// + /// Sorted list of values + /// + public readonly ReadOnlySpan Values => MemoryMarshal.CreateReadOnlySpan(ref Unsafe.As(ref Unsafe.AsRef(in _values)), _size); + + /// + /// Sorted list of weights + /// + public readonly ReadOnlySpan Weights => MemoryMarshal.CreateReadOnlySpan(ref Unsafe.As(ref Unsafe.AsRef(in _weights)), _size); + + /// + /// The smallest weight + /// + public readonly W MinWeight => _size > 0 ? Weights[_size - 1] : W.MaxValue; + + /// + /// The largest weight + /// + public readonly W MaxWeight => _size > 0 ? Weights[0] : W.MinValue; + + /// + /// The value with the smallest weight + /// + public readonly V? MinValue => _size > 0 ? Values[_size - 1] : default; + + /// + /// The value with the largest weight + /// + public readonly V? MaxValue => _size > 0 ? Values[0] : default; + + /// + /// Returns a value and weight + /// + /// Index to return + public readonly (V Value, W Weight) this[byte index] + { + get + { + if (index < Size) + return (Values[index], Weights[index]); + throw new ArgumentOutOfRangeException(); + } + } + + /// + /// Enumerates the values and weights + /// + public readonly IEnumerable<(V Value, W Weight)> Elements + { + get + { + for (byte i = 0; i < Size; i++) + yield return this[i]; + } + } + + /// + /// Tries to add a new element - will succeed if there aren't already max elements with a smaller weight + /// + /// Value to add + /// Weight to add + /// True if values should be unique - will return false if the value already exists + /// True if the element was added + public bool TryAdd(V value, W weight, bool enforceUnique = true) + { + var values = MemoryMarshal.CreateSpan(ref Unsafe.As(ref Unsafe.AsRef(in _values)), MaxSize); + var weights = MemoryMarshal.CreateSpan(ref Unsafe.As(ref Unsafe.AsRef(in _weights)), MaxSize); + return FixedSizeSortedArrayHelper.InsertIntoDescending(enforceUnique, ref _size, MaxSize, value, weight, values, weights); + } + + /// + /// Removes an element from the array + /// + /// Index of element to remove + /// + public void RemoveAt(byte index) + { + if(index >= _size) + throw new ArgumentOutOfRangeException(); + var values = MemoryMarshal.CreateSpan(ref Unsafe.As(ref Unsafe.AsRef(in _values)), _size); + var weights = MemoryMarshal.CreateSpan(ref Unsafe.As(ref Unsafe.AsRef(in _weights)), _size); + FixedSizeSortedArrayHelper.RemoveAt(index, values, weights); + --_size; + } + } + + /// + /// Fixed size sorted array of values and weights (max 23 elements) + /// that is sorted in ascending order based on each weight + /// + /// Type of value to store + /// Type of weight that will be used to sort + public record struct FixedSizeSortedAscending23Array() : IFixedSizeSortedArray + where V : IComparable + where W : unmanaged, INumber, IMinMaxValue + { + /// + /// Max size of the array + /// + public const int MaxSize = 23; + byte IFixedSizeSortedArray.MaxSize => MaxSize; + + [InlineArray(MaxSize)] + internal struct ValueArray + { + public V _element0; + } + [InlineArray(MaxSize)] + internal struct WeightArray + { + public W _element0; + } + readonly ValueArray _values = new(); + readonly WeightArray _weights = new(); + byte _size = 0; + + /// + /// Current number of elements + /// + public readonly byte Size => _size; + + /// + /// Sorted list of values + /// + public readonly ReadOnlySpan Values => MemoryMarshal.CreateReadOnlySpan(ref Unsafe.As(ref Unsafe.AsRef(in _values)), _size); + + /// + /// Sorted list of weights + /// + public readonly ReadOnlySpan Weights => MemoryMarshal.CreateReadOnlySpan(ref Unsafe.As(ref Unsafe.AsRef(in _weights)), _size); + + /// + /// The smallest weight + /// + public readonly W MinWeight => _size > 0 ? Weights[0] : W.MaxValue; + + /// + /// The largest weight + /// + public readonly W MaxWeight => _size > 0 ? Weights[_size - 1] : W.MinValue; + + /// + /// The value with the smallest weight + /// + public readonly V? MinValue => _size > 0 ? Values[0] : default; + + /// + /// The value with the largest weight + /// + public readonly V? MaxValue => _size > 0 ? Values[_size - 1] : default; + + /// + /// Returns a value and weight + /// + /// Index to return + public readonly (V Value, W Weight) this[byte index] + { + get + { + if (index < Size) + return (Values[index], Weights[index]); + throw new ArgumentOutOfRangeException(); + } + } + + /// + /// Enumerates the values and weights + /// + public readonly IEnumerable<(V Value, W Weight)> Elements + { + get + { + for (byte i = 0; i < Size; i++) + yield return this[i]; + } + } + + /// + /// Tries to add a new element - will succeed if there aren't already max elements with a smaller weight + /// + /// Value to add + /// Weight to add + /// True if values should be unique - will return false if the value already exists + /// True if the element was added + public bool TryAdd(V value, W weight, bool enforceUnique = true) + { + var values = MemoryMarshal.CreateSpan(ref Unsafe.As(ref Unsafe.AsRef(in _values)), MaxSize); + var weights = MemoryMarshal.CreateSpan(ref Unsafe.As(ref Unsafe.AsRef(in _weights)), MaxSize); + return FixedSizeSortedArrayHelper.InsertIntoAscending(enforceUnique, ref _size, MaxSize, value, weight, values, weights); + } + + /// + /// Removes an element from the array + /// + /// Index of element to remove + /// + public void RemoveAt(byte index) + { + if(index >= _size) + throw new ArgumentOutOfRangeException(); + var values = MemoryMarshal.CreateSpan(ref Unsafe.As(ref Unsafe.AsRef(in _values)), _size); + var weights = MemoryMarshal.CreateSpan(ref Unsafe.As(ref Unsafe.AsRef(in _weights)), _size); + FixedSizeSortedArrayHelper.RemoveAt(index, values, weights); + --_size; + } + } + + /// + /// Fixed size sorted array of values and weights (max 23 elements) + /// that is sorted in descending order based on each weight + /// + /// Type of value to store + /// Type of weight that will be used to sort + public record struct FixedSizeSortedDescending23Array() + where V : IComparable + where W : unmanaged, INumber, IMinMaxValue + { + /// + /// Max size of the array + /// + public const int MaxSize = 23; + + [InlineArray(MaxSize)] + internal struct ValueArray + { + public V _element0; + } + [InlineArray(MaxSize)] + internal struct WeightArray + { + public W _element0; + } + readonly ValueArray _values = new(); + readonly WeightArray _weights = new(); + byte _size = 0; + + /// + /// Current number of elements + /// + public readonly byte Size => _size; + + /// + /// Sorted list of values + /// + public readonly ReadOnlySpan Values => MemoryMarshal.CreateReadOnlySpan(ref Unsafe.As(ref Unsafe.AsRef(in _values)), _size); + + /// + /// Sorted list of weights + /// + public readonly ReadOnlySpan Weights => MemoryMarshal.CreateReadOnlySpan(ref Unsafe.As(ref Unsafe.AsRef(in _weights)), _size); + + /// + /// The smallest weight + /// + public readonly W MinWeight => _size > 0 ? Weights[_size - 1] : W.MaxValue; + + /// + /// The largest weight + /// + public readonly W MaxWeight => _size > 0 ? Weights[0] : W.MinValue; + + /// + /// The value with the smallest weight + /// + public readonly V? MinValue => _size > 0 ? Values[_size - 1] : default; + + /// + /// The value with the largest weight + /// + public readonly V? MaxValue => _size > 0 ? Values[0] : default; + + /// + /// Returns a value and weight + /// + /// Index to return + public readonly (V Value, W Weight) this[byte index] + { + get + { + if (index < Size) + return (Values[index], Weights[index]); + throw new ArgumentOutOfRangeException(); + } + } + + /// + /// Enumerates the values and weights + /// + public readonly IEnumerable<(V Value, W Weight)> Elements + { + get + { + for (byte i = 0; i < Size; i++) + yield return this[i]; + } + } + + /// + /// Tries to add a new element - will succeed if there aren't already max elements with a smaller weight + /// + /// Value to add + /// Weight to add + /// True if values should be unique - will return false if the value already exists + /// True if the element was added + public bool TryAdd(V value, W weight, bool enforceUnique = true) + { + var values = MemoryMarshal.CreateSpan(ref Unsafe.As(ref Unsafe.AsRef(in _values)), MaxSize); + var weights = MemoryMarshal.CreateSpan(ref Unsafe.As(ref Unsafe.AsRef(in _weights)), MaxSize); + return FixedSizeSortedArrayHelper.InsertIntoDescending(enforceUnique, ref _size, MaxSize, value, weight, values, weights); + } + + /// + /// Removes an element from the array + /// + /// Index of element to remove + /// + public void RemoveAt(byte index) + { + if(index >= _size) + throw new ArgumentOutOfRangeException(); + var values = MemoryMarshal.CreateSpan(ref Unsafe.As(ref Unsafe.AsRef(in _values)), _size); + var weights = MemoryMarshal.CreateSpan(ref Unsafe.As(ref Unsafe.AsRef(in _weights)), _size); + FixedSizeSortedArrayHelper.RemoveAt(index, values, weights); + --_size; + } + } + + /// + /// Fixed size sorted array of values and weights (max 24 elements) + /// that is sorted in ascending order based on each weight + /// + /// Type of value to store + /// Type of weight that will be used to sort + public record struct FixedSizeSortedAscending24Array() : IFixedSizeSortedArray + where V : IComparable + where W : unmanaged, INumber, IMinMaxValue + { + /// + /// Max size of the array + /// + public const int MaxSize = 24; + byte IFixedSizeSortedArray.MaxSize => MaxSize; + + [InlineArray(MaxSize)] + internal struct ValueArray + { + public V _element0; + } + [InlineArray(MaxSize)] + internal struct WeightArray + { + public W _element0; + } + readonly ValueArray _values = new(); + readonly WeightArray _weights = new(); + byte _size = 0; + + /// + /// Current number of elements + /// + public readonly byte Size => _size; + + /// + /// Sorted list of values + /// + public readonly ReadOnlySpan Values => MemoryMarshal.CreateReadOnlySpan(ref Unsafe.As(ref Unsafe.AsRef(in _values)), _size); + + /// + /// Sorted list of weights + /// + public readonly ReadOnlySpan Weights => MemoryMarshal.CreateReadOnlySpan(ref Unsafe.As(ref Unsafe.AsRef(in _weights)), _size); + + /// + /// The smallest weight + /// + public readonly W MinWeight => _size > 0 ? Weights[0] : W.MaxValue; + + /// + /// The largest weight + /// + public readonly W MaxWeight => _size > 0 ? Weights[_size - 1] : W.MinValue; + + /// + /// The value with the smallest weight + /// + public readonly V? MinValue => _size > 0 ? Values[0] : default; + + /// + /// The value with the largest weight + /// + public readonly V? MaxValue => _size > 0 ? Values[_size - 1] : default; + + /// + /// Returns a value and weight + /// + /// Index to return + public readonly (V Value, W Weight) this[byte index] + { + get + { + if (index < Size) + return (Values[index], Weights[index]); + throw new ArgumentOutOfRangeException(); + } + } + + /// + /// Enumerates the values and weights + /// + public readonly IEnumerable<(V Value, W Weight)> Elements + { + get + { + for (byte i = 0; i < Size; i++) + yield return this[i]; + } + } + + /// + /// Tries to add a new element - will succeed if there aren't already max elements with a smaller weight + /// + /// Value to add + /// Weight to add + /// True if values should be unique - will return false if the value already exists + /// True if the element was added + public bool TryAdd(V value, W weight, bool enforceUnique = true) + { + var values = MemoryMarshal.CreateSpan(ref Unsafe.As(ref Unsafe.AsRef(in _values)), MaxSize); + var weights = MemoryMarshal.CreateSpan(ref Unsafe.As(ref Unsafe.AsRef(in _weights)), MaxSize); + return FixedSizeSortedArrayHelper.InsertIntoAscending(enforceUnique, ref _size, MaxSize, value, weight, values, weights); + } + + /// + /// Removes an element from the array + /// + /// Index of element to remove + /// + public void RemoveAt(byte index) + { + if(index >= _size) + throw new ArgumentOutOfRangeException(); + var values = MemoryMarshal.CreateSpan(ref Unsafe.As(ref Unsafe.AsRef(in _values)), _size); + var weights = MemoryMarshal.CreateSpan(ref Unsafe.As(ref Unsafe.AsRef(in _weights)), _size); + FixedSizeSortedArrayHelper.RemoveAt(index, values, weights); + --_size; + } + } + + /// + /// Fixed size sorted array of values and weights (max 24 elements) + /// that is sorted in descending order based on each weight + /// + /// Type of value to store + /// Type of weight that will be used to sort + public record struct FixedSizeSortedDescending24Array() + where V : IComparable + where W : unmanaged, INumber, IMinMaxValue + { + /// + /// Max size of the array + /// + public const int MaxSize = 24; + + [InlineArray(MaxSize)] + internal struct ValueArray + { + public V _element0; + } + [InlineArray(MaxSize)] + internal struct WeightArray + { + public W _element0; + } + readonly ValueArray _values = new(); + readonly WeightArray _weights = new(); + byte _size = 0; + + /// + /// Current number of elements + /// + public readonly byte Size => _size; + + /// + /// Sorted list of values + /// + public readonly ReadOnlySpan Values => MemoryMarshal.CreateReadOnlySpan(ref Unsafe.As(ref Unsafe.AsRef(in _values)), _size); + + /// + /// Sorted list of weights + /// + public readonly ReadOnlySpan Weights => MemoryMarshal.CreateReadOnlySpan(ref Unsafe.As(ref Unsafe.AsRef(in _weights)), _size); + + /// + /// The smallest weight + /// + public readonly W MinWeight => _size > 0 ? Weights[_size - 1] : W.MaxValue; + + /// + /// The largest weight + /// + public readonly W MaxWeight => _size > 0 ? Weights[0] : W.MinValue; + + /// + /// The value with the smallest weight + /// + public readonly V? MinValue => _size > 0 ? Values[_size - 1] : default; + + /// + /// The value with the largest weight + /// + public readonly V? MaxValue => _size > 0 ? Values[0] : default; + + /// + /// Returns a value and weight + /// + /// Index to return + public readonly (V Value, W Weight) this[byte index] + { + get + { + if (index < Size) + return (Values[index], Weights[index]); + throw new ArgumentOutOfRangeException(); + } + } + + /// + /// Enumerates the values and weights + /// + public readonly IEnumerable<(V Value, W Weight)> Elements + { + get + { + for (byte i = 0; i < Size; i++) + yield return this[i]; + } + } + + /// + /// Tries to add a new element - will succeed if there aren't already max elements with a smaller weight + /// + /// Value to add + /// Weight to add + /// True if values should be unique - will return false if the value already exists + /// True if the element was added + public bool TryAdd(V value, W weight, bool enforceUnique = true) + { + var values = MemoryMarshal.CreateSpan(ref Unsafe.As(ref Unsafe.AsRef(in _values)), MaxSize); + var weights = MemoryMarshal.CreateSpan(ref Unsafe.As(ref Unsafe.AsRef(in _weights)), MaxSize); + return FixedSizeSortedArrayHelper.InsertIntoDescending(enforceUnique, ref _size, MaxSize, value, weight, values, weights); + } + + /// + /// Removes an element from the array + /// + /// Index of element to remove + /// + public void RemoveAt(byte index) + { + if(index >= _size) + throw new ArgumentOutOfRangeException(); + var values = MemoryMarshal.CreateSpan(ref Unsafe.As(ref Unsafe.AsRef(in _values)), _size); + var weights = MemoryMarshal.CreateSpan(ref Unsafe.As(ref Unsafe.AsRef(in _weights)), _size); + FixedSizeSortedArrayHelper.RemoveAt(index, values, weights); + --_size; + } + } + + /// + /// Fixed size sorted array of values and weights (max 25 elements) + /// that is sorted in ascending order based on each weight + /// + /// Type of value to store + /// Type of weight that will be used to sort + public record struct FixedSizeSortedAscending25Array() : IFixedSizeSortedArray + where V : IComparable + where W : unmanaged, INumber, IMinMaxValue + { + /// + /// Max size of the array + /// + public const int MaxSize = 25; + byte IFixedSizeSortedArray.MaxSize => MaxSize; + + [InlineArray(MaxSize)] + internal struct ValueArray + { + public V _element0; + } + [InlineArray(MaxSize)] + internal struct WeightArray + { + public W _element0; + } + readonly ValueArray _values = new(); + readonly WeightArray _weights = new(); + byte _size = 0; + + /// + /// Current number of elements + /// + public readonly byte Size => _size; + + /// + /// Sorted list of values + /// + public readonly ReadOnlySpan Values => MemoryMarshal.CreateReadOnlySpan(ref Unsafe.As(ref Unsafe.AsRef(in _values)), _size); + + /// + /// Sorted list of weights + /// + public readonly ReadOnlySpan Weights => MemoryMarshal.CreateReadOnlySpan(ref Unsafe.As(ref Unsafe.AsRef(in _weights)), _size); + + /// + /// The smallest weight + /// + public readonly W MinWeight => _size > 0 ? Weights[0] : W.MaxValue; + + /// + /// The largest weight + /// + public readonly W MaxWeight => _size > 0 ? Weights[_size - 1] : W.MinValue; + + /// + /// The value with the smallest weight + /// + public readonly V? MinValue => _size > 0 ? Values[0] : default; + + /// + /// The value with the largest weight + /// + public readonly V? MaxValue => _size > 0 ? Values[_size - 1] : default; + + /// + /// Returns a value and weight + /// + /// Index to return + public readonly (V Value, W Weight) this[byte index] + { + get + { + if (index < Size) + return (Values[index], Weights[index]); + throw new ArgumentOutOfRangeException(); + } + } + + /// + /// Enumerates the values and weights + /// + public readonly IEnumerable<(V Value, W Weight)> Elements + { + get + { + for (byte i = 0; i < Size; i++) + yield return this[i]; + } + } + + /// + /// Tries to add a new element - will succeed if there aren't already max elements with a smaller weight + /// + /// Value to add + /// Weight to add + /// True if values should be unique - will return false if the value already exists + /// True if the element was added + public bool TryAdd(V value, W weight, bool enforceUnique = true) + { + var values = MemoryMarshal.CreateSpan(ref Unsafe.As(ref Unsafe.AsRef(in _values)), MaxSize); + var weights = MemoryMarshal.CreateSpan(ref Unsafe.As(ref Unsafe.AsRef(in _weights)), MaxSize); + return FixedSizeSortedArrayHelper.InsertIntoAscending(enforceUnique, ref _size, MaxSize, value, weight, values, weights); + } + + /// + /// Removes an element from the array + /// + /// Index of element to remove + /// + public void RemoveAt(byte index) + { + if(index >= _size) + throw new ArgumentOutOfRangeException(); + var values = MemoryMarshal.CreateSpan(ref Unsafe.As(ref Unsafe.AsRef(in _values)), _size); + var weights = MemoryMarshal.CreateSpan(ref Unsafe.As(ref Unsafe.AsRef(in _weights)), _size); + FixedSizeSortedArrayHelper.RemoveAt(index, values, weights); + --_size; + } + } + + /// + /// Fixed size sorted array of values and weights (max 25 elements) + /// that is sorted in descending order based on each weight + /// + /// Type of value to store + /// Type of weight that will be used to sort + public record struct FixedSizeSortedDescending25Array() + where V : IComparable + where W : unmanaged, INumber, IMinMaxValue + { + /// + /// Max size of the array + /// + public const int MaxSize = 25; + + [InlineArray(MaxSize)] + internal struct ValueArray + { + public V _element0; + } + [InlineArray(MaxSize)] + internal struct WeightArray + { + public W _element0; + } + readonly ValueArray _values = new(); + readonly WeightArray _weights = new(); + byte _size = 0; + + /// + /// Current number of elements + /// + public readonly byte Size => _size; + + /// + /// Sorted list of values + /// + public readonly ReadOnlySpan Values => MemoryMarshal.CreateReadOnlySpan(ref Unsafe.As(ref Unsafe.AsRef(in _values)), _size); + + /// + /// Sorted list of weights + /// + public readonly ReadOnlySpan Weights => MemoryMarshal.CreateReadOnlySpan(ref Unsafe.As(ref Unsafe.AsRef(in _weights)), _size); + + /// + /// The smallest weight + /// + public readonly W MinWeight => _size > 0 ? Weights[_size - 1] : W.MaxValue; + + /// + /// The largest weight + /// + public readonly W MaxWeight => _size > 0 ? Weights[0] : W.MinValue; + + /// + /// The value with the smallest weight + /// + public readonly V? MinValue => _size > 0 ? Values[_size - 1] : default; + + /// + /// The value with the largest weight + /// + public readonly V? MaxValue => _size > 0 ? Values[0] : default; + + /// + /// Returns a value and weight + /// + /// Index to return + public readonly (V Value, W Weight) this[byte index] + { + get + { + if (index < Size) + return (Values[index], Weights[index]); + throw new ArgumentOutOfRangeException(); + } + } + + /// + /// Enumerates the values and weights + /// + public readonly IEnumerable<(V Value, W Weight)> Elements + { + get + { + for (byte i = 0; i < Size; i++) + yield return this[i]; + } + } + + /// + /// Tries to add a new element - will succeed if there aren't already max elements with a smaller weight + /// + /// Value to add + /// Weight to add + /// True if values should be unique - will return false if the value already exists + /// True if the element was added + public bool TryAdd(V value, W weight, bool enforceUnique = true) + { + var values = MemoryMarshal.CreateSpan(ref Unsafe.As(ref Unsafe.AsRef(in _values)), MaxSize); + var weights = MemoryMarshal.CreateSpan(ref Unsafe.As(ref Unsafe.AsRef(in _weights)), MaxSize); + return FixedSizeSortedArrayHelper.InsertIntoDescending(enforceUnique, ref _size, MaxSize, value, weight, values, weights); + } + + /// + /// Removes an element from the array + /// + /// Index of element to remove + /// + public void RemoveAt(byte index) + { + if(index >= _size) + throw new ArgumentOutOfRangeException(); + var values = MemoryMarshal.CreateSpan(ref Unsafe.As(ref Unsafe.AsRef(in _values)), _size); + var weights = MemoryMarshal.CreateSpan(ref Unsafe.As(ref Unsafe.AsRef(in _weights)), _size); + FixedSizeSortedArrayHelper.RemoveAt(index, values, weights); + --_size; + } + } + + /// + /// Fixed size sorted array of values and weights (max 26 elements) + /// that is sorted in ascending order based on each weight + /// + /// Type of value to store + /// Type of weight that will be used to sort + public record struct FixedSizeSortedAscending26Array() : IFixedSizeSortedArray + where V : IComparable + where W : unmanaged, INumber, IMinMaxValue + { + /// + /// Max size of the array + /// + public const int MaxSize = 26; + byte IFixedSizeSortedArray.MaxSize => MaxSize; + + [InlineArray(MaxSize)] + internal struct ValueArray + { + public V _element0; + } + [InlineArray(MaxSize)] + internal struct WeightArray + { + public W _element0; + } + readonly ValueArray _values = new(); + readonly WeightArray _weights = new(); + byte _size = 0; + + /// + /// Current number of elements + /// + public readonly byte Size => _size; + + /// + /// Sorted list of values + /// + public readonly ReadOnlySpan Values => MemoryMarshal.CreateReadOnlySpan(ref Unsafe.As(ref Unsafe.AsRef(in _values)), _size); + + /// + /// Sorted list of weights + /// + public readonly ReadOnlySpan Weights => MemoryMarshal.CreateReadOnlySpan(ref Unsafe.As(ref Unsafe.AsRef(in _weights)), _size); + + /// + /// The smallest weight + /// + public readonly W MinWeight => _size > 0 ? Weights[0] : W.MaxValue; + + /// + /// The largest weight + /// + public readonly W MaxWeight => _size > 0 ? Weights[_size - 1] : W.MinValue; + + /// + /// The value with the smallest weight + /// + public readonly V? MinValue => _size > 0 ? Values[0] : default; + + /// + /// The value with the largest weight + /// + public readonly V? MaxValue => _size > 0 ? Values[_size - 1] : default; + + /// + /// Returns a value and weight + /// + /// Index to return + public readonly (V Value, W Weight) this[byte index] + { + get + { + if (index < Size) + return (Values[index], Weights[index]); + throw new ArgumentOutOfRangeException(); + } + } + + /// + /// Enumerates the values and weights + /// + public readonly IEnumerable<(V Value, W Weight)> Elements + { + get + { + for (byte i = 0; i < Size; i++) + yield return this[i]; + } + } + + /// + /// Tries to add a new element - will succeed if there aren't already max elements with a smaller weight + /// + /// Value to add + /// Weight to add + /// True if values should be unique - will return false if the value already exists + /// True if the element was added + public bool TryAdd(V value, W weight, bool enforceUnique = true) + { + var values = MemoryMarshal.CreateSpan(ref Unsafe.As(ref Unsafe.AsRef(in _values)), MaxSize); + var weights = MemoryMarshal.CreateSpan(ref Unsafe.As(ref Unsafe.AsRef(in _weights)), MaxSize); + return FixedSizeSortedArrayHelper.InsertIntoAscending(enforceUnique, ref _size, MaxSize, value, weight, values, weights); + } + + /// + /// Removes an element from the array + /// + /// Index of element to remove + /// + public void RemoveAt(byte index) + { + if(index >= _size) + throw new ArgumentOutOfRangeException(); + var values = MemoryMarshal.CreateSpan(ref Unsafe.As(ref Unsafe.AsRef(in _values)), _size); + var weights = MemoryMarshal.CreateSpan(ref Unsafe.As(ref Unsafe.AsRef(in _weights)), _size); + FixedSizeSortedArrayHelper.RemoveAt(index, values, weights); + --_size; + } + } + + /// + /// Fixed size sorted array of values and weights (max 26 elements) + /// that is sorted in descending order based on each weight + /// + /// Type of value to store + /// Type of weight that will be used to sort + public record struct FixedSizeSortedDescending26Array() + where V : IComparable + where W : unmanaged, INumber, IMinMaxValue + { + /// + /// Max size of the array + /// + public const int MaxSize = 26; + + [InlineArray(MaxSize)] + internal struct ValueArray + { + public V _element0; + } + [InlineArray(MaxSize)] + internal struct WeightArray + { + public W _element0; + } + readonly ValueArray _values = new(); + readonly WeightArray _weights = new(); + byte _size = 0; + + /// + /// Current number of elements + /// + public readonly byte Size => _size; + + /// + /// Sorted list of values + /// + public readonly ReadOnlySpan Values => MemoryMarshal.CreateReadOnlySpan(ref Unsafe.As(ref Unsafe.AsRef(in _values)), _size); + + /// + /// Sorted list of weights + /// + public readonly ReadOnlySpan Weights => MemoryMarshal.CreateReadOnlySpan(ref Unsafe.As(ref Unsafe.AsRef(in _weights)), _size); + + /// + /// The smallest weight + /// + public readonly W MinWeight => _size > 0 ? Weights[_size - 1] : W.MaxValue; + + /// + /// The largest weight + /// + public readonly W MaxWeight => _size > 0 ? Weights[0] : W.MinValue; + + /// + /// The value with the smallest weight + /// + public readonly V? MinValue => _size > 0 ? Values[_size - 1] : default; + + /// + /// The value with the largest weight + /// + public readonly V? MaxValue => _size > 0 ? Values[0] : default; + + /// + /// Returns a value and weight + /// + /// Index to return + public readonly (V Value, W Weight) this[byte index] + { + get + { + if (index < Size) + return (Values[index], Weights[index]); + throw new ArgumentOutOfRangeException(); + } + } + + /// + /// Enumerates the values and weights + /// + public readonly IEnumerable<(V Value, W Weight)> Elements + { + get + { + for (byte i = 0; i < Size; i++) + yield return this[i]; + } + } + + /// + /// Tries to add a new element - will succeed if there aren't already max elements with a smaller weight + /// + /// Value to add + /// Weight to add + /// True if values should be unique - will return false if the value already exists + /// True if the element was added + public bool TryAdd(V value, W weight, bool enforceUnique = true) + { + var values = MemoryMarshal.CreateSpan(ref Unsafe.As(ref Unsafe.AsRef(in _values)), MaxSize); + var weights = MemoryMarshal.CreateSpan(ref Unsafe.As(ref Unsafe.AsRef(in _weights)), MaxSize); + return FixedSizeSortedArrayHelper.InsertIntoDescending(enforceUnique, ref _size, MaxSize, value, weight, values, weights); + } + + /// + /// Removes an element from the array + /// + /// Index of element to remove + /// + public void RemoveAt(byte index) + { + if(index >= _size) + throw new ArgumentOutOfRangeException(); + var values = MemoryMarshal.CreateSpan(ref Unsafe.As(ref Unsafe.AsRef(in _values)), _size); + var weights = MemoryMarshal.CreateSpan(ref Unsafe.As(ref Unsafe.AsRef(in _weights)), _size); + FixedSizeSortedArrayHelper.RemoveAt(index, values, weights); + --_size; + } + } + + /// + /// Fixed size sorted array of values and weights (max 27 elements) + /// that is sorted in ascending order based on each weight + /// + /// Type of value to store + /// Type of weight that will be used to sort + public record struct FixedSizeSortedAscending27Array() : IFixedSizeSortedArray + where V : IComparable + where W : unmanaged, INumber, IMinMaxValue + { + /// + /// Max size of the array + /// + public const int MaxSize = 27; + byte IFixedSizeSortedArray.MaxSize => MaxSize; + + [InlineArray(MaxSize)] + internal struct ValueArray + { + public V _element0; + } + [InlineArray(MaxSize)] + internal struct WeightArray + { + public W _element0; + } + readonly ValueArray _values = new(); + readonly WeightArray _weights = new(); + byte _size = 0; + + /// + /// Current number of elements + /// + public readonly byte Size => _size; + + /// + /// Sorted list of values + /// + public readonly ReadOnlySpan Values => MemoryMarshal.CreateReadOnlySpan(ref Unsafe.As(ref Unsafe.AsRef(in _values)), _size); + + /// + /// Sorted list of weights + /// + public readonly ReadOnlySpan Weights => MemoryMarshal.CreateReadOnlySpan(ref Unsafe.As(ref Unsafe.AsRef(in _weights)), _size); + + /// + /// The smallest weight + /// + public readonly W MinWeight => _size > 0 ? Weights[0] : W.MaxValue; + + /// + /// The largest weight + /// + public readonly W MaxWeight => _size > 0 ? Weights[_size - 1] : W.MinValue; + + /// + /// The value with the smallest weight + /// + public readonly V? MinValue => _size > 0 ? Values[0] : default; + + /// + /// The value with the largest weight + /// + public readonly V? MaxValue => _size > 0 ? Values[_size - 1] : default; + + /// + /// Returns a value and weight + /// + /// Index to return + public readonly (V Value, W Weight) this[byte index] + { + get + { + if (index < Size) + return (Values[index], Weights[index]); + throw new ArgumentOutOfRangeException(); + } + } + + /// + /// Enumerates the values and weights + /// + public readonly IEnumerable<(V Value, W Weight)> Elements + { + get + { + for (byte i = 0; i < Size; i++) + yield return this[i]; + } + } + + /// + /// Tries to add a new element - will succeed if there aren't already max elements with a smaller weight + /// + /// Value to add + /// Weight to add + /// True if values should be unique - will return false if the value already exists + /// True if the element was added + public bool TryAdd(V value, W weight, bool enforceUnique = true) + { + var values = MemoryMarshal.CreateSpan(ref Unsafe.As(ref Unsafe.AsRef(in _values)), MaxSize); + var weights = MemoryMarshal.CreateSpan(ref Unsafe.As(ref Unsafe.AsRef(in _weights)), MaxSize); + return FixedSizeSortedArrayHelper.InsertIntoAscending(enforceUnique, ref _size, MaxSize, value, weight, values, weights); + } + + /// + /// Removes an element from the array + /// + /// Index of element to remove + /// + public void RemoveAt(byte index) + { + if(index >= _size) + throw new ArgumentOutOfRangeException(); + var values = MemoryMarshal.CreateSpan(ref Unsafe.As(ref Unsafe.AsRef(in _values)), _size); + var weights = MemoryMarshal.CreateSpan(ref Unsafe.As(ref Unsafe.AsRef(in _weights)), _size); + FixedSizeSortedArrayHelper.RemoveAt(index, values, weights); + --_size; + } + } + + /// + /// Fixed size sorted array of values and weights (max 27 elements) + /// that is sorted in descending order based on each weight + /// + /// Type of value to store + /// Type of weight that will be used to sort + public record struct FixedSizeSortedDescending27Array() + where V : IComparable + where W : unmanaged, INumber, IMinMaxValue + { + /// + /// Max size of the array + /// + public const int MaxSize = 27; + + [InlineArray(MaxSize)] + internal struct ValueArray + { + public V _element0; + } + [InlineArray(MaxSize)] + internal struct WeightArray + { + public W _element0; + } + readonly ValueArray _values = new(); + readonly WeightArray _weights = new(); + byte _size = 0; + + /// + /// Current number of elements + /// + public readonly byte Size => _size; + + /// + /// Sorted list of values + /// + public readonly ReadOnlySpan Values => MemoryMarshal.CreateReadOnlySpan(ref Unsafe.As(ref Unsafe.AsRef(in _values)), _size); + + /// + /// Sorted list of weights + /// + public readonly ReadOnlySpan Weights => MemoryMarshal.CreateReadOnlySpan(ref Unsafe.As(ref Unsafe.AsRef(in _weights)), _size); + + /// + /// The smallest weight + /// + public readonly W MinWeight => _size > 0 ? Weights[_size - 1] : W.MaxValue; + + /// + /// The largest weight + /// + public readonly W MaxWeight => _size > 0 ? Weights[0] : W.MinValue; + + /// + /// The value with the smallest weight + /// + public readonly V? MinValue => _size > 0 ? Values[_size - 1] : default; + + /// + /// The value with the largest weight + /// + public readonly V? MaxValue => _size > 0 ? Values[0] : default; + + /// + /// Returns a value and weight + /// + /// Index to return + public readonly (V Value, W Weight) this[byte index] + { + get + { + if (index < Size) + return (Values[index], Weights[index]); + throw new ArgumentOutOfRangeException(); + } + } + + /// + /// Enumerates the values and weights + /// + public readonly IEnumerable<(V Value, W Weight)> Elements + { + get + { + for (byte i = 0; i < Size; i++) + yield return this[i]; + } + } + + /// + /// Tries to add a new element - will succeed if there aren't already max elements with a smaller weight + /// + /// Value to add + /// Weight to add + /// True if values should be unique - will return false if the value already exists + /// True if the element was added + public bool TryAdd(V value, W weight, bool enforceUnique = true) + { + var values = MemoryMarshal.CreateSpan(ref Unsafe.As(ref Unsafe.AsRef(in _values)), MaxSize); + var weights = MemoryMarshal.CreateSpan(ref Unsafe.As(ref Unsafe.AsRef(in _weights)), MaxSize); + return FixedSizeSortedArrayHelper.InsertIntoDescending(enforceUnique, ref _size, MaxSize, value, weight, values, weights); + } + + /// + /// Removes an element from the array + /// + /// Index of element to remove + /// + public void RemoveAt(byte index) + { + if(index >= _size) + throw new ArgumentOutOfRangeException(); + var values = MemoryMarshal.CreateSpan(ref Unsafe.As(ref Unsafe.AsRef(in _values)), _size); + var weights = MemoryMarshal.CreateSpan(ref Unsafe.As(ref Unsafe.AsRef(in _weights)), _size); + FixedSizeSortedArrayHelper.RemoveAt(index, values, weights); + --_size; + } + } + + /// + /// Fixed size sorted array of values and weights (max 28 elements) + /// that is sorted in ascending order based on each weight + /// + /// Type of value to store + /// Type of weight that will be used to sort + public record struct FixedSizeSortedAscending28Array() : IFixedSizeSortedArray + where V : IComparable + where W : unmanaged, INumber, IMinMaxValue + { + /// + /// Max size of the array + /// + public const int MaxSize = 28; + byte IFixedSizeSortedArray.MaxSize => MaxSize; + + [InlineArray(MaxSize)] + internal struct ValueArray + { + public V _element0; + } + [InlineArray(MaxSize)] + internal struct WeightArray + { + public W _element0; + } + readonly ValueArray _values = new(); + readonly WeightArray _weights = new(); + byte _size = 0; + + /// + /// Current number of elements + /// + public readonly byte Size => _size; + + /// + /// Sorted list of values + /// + public readonly ReadOnlySpan Values => MemoryMarshal.CreateReadOnlySpan(ref Unsafe.As(ref Unsafe.AsRef(in _values)), _size); + + /// + /// Sorted list of weights + /// + public readonly ReadOnlySpan Weights => MemoryMarshal.CreateReadOnlySpan(ref Unsafe.As(ref Unsafe.AsRef(in _weights)), _size); + + /// + /// The smallest weight + /// + public readonly W MinWeight => _size > 0 ? Weights[0] : W.MaxValue; + + /// + /// The largest weight + /// + public readonly W MaxWeight => _size > 0 ? Weights[_size - 1] : W.MinValue; + + /// + /// The value with the smallest weight + /// + public readonly V? MinValue => _size > 0 ? Values[0] : default; + + /// + /// The value with the largest weight + /// + public readonly V? MaxValue => _size > 0 ? Values[_size - 1] : default; + + /// + /// Returns a value and weight + /// + /// Index to return + public readonly (V Value, W Weight) this[byte index] + { + get + { + if (index < Size) + return (Values[index], Weights[index]); + throw new ArgumentOutOfRangeException(); + } + } + + /// + /// Enumerates the values and weights + /// + public readonly IEnumerable<(V Value, W Weight)> Elements + { + get + { + for (byte i = 0; i < Size; i++) + yield return this[i]; + } + } + + /// + /// Tries to add a new element - will succeed if there aren't already max elements with a smaller weight + /// + /// Value to add + /// Weight to add + /// True if values should be unique - will return false if the value already exists + /// True if the element was added + public bool TryAdd(V value, W weight, bool enforceUnique = true) + { + var values = MemoryMarshal.CreateSpan(ref Unsafe.As(ref Unsafe.AsRef(in _values)), MaxSize); + var weights = MemoryMarshal.CreateSpan(ref Unsafe.As(ref Unsafe.AsRef(in _weights)), MaxSize); + return FixedSizeSortedArrayHelper.InsertIntoAscending(enforceUnique, ref _size, MaxSize, value, weight, values, weights); + } + + /// + /// Removes an element from the array + /// + /// Index of element to remove + /// + public void RemoveAt(byte index) + { + if(index >= _size) + throw new ArgumentOutOfRangeException(); + var values = MemoryMarshal.CreateSpan(ref Unsafe.As(ref Unsafe.AsRef(in _values)), _size); + var weights = MemoryMarshal.CreateSpan(ref Unsafe.As(ref Unsafe.AsRef(in _weights)), _size); + FixedSizeSortedArrayHelper.RemoveAt(index, values, weights); + --_size; + } + } + + /// + /// Fixed size sorted array of values and weights (max 28 elements) + /// that is sorted in descending order based on each weight + /// + /// Type of value to store + /// Type of weight that will be used to sort + public record struct FixedSizeSortedDescending28Array() + where V : IComparable + where W : unmanaged, INumber, IMinMaxValue + { + /// + /// Max size of the array + /// + public const int MaxSize = 28; + + [InlineArray(MaxSize)] + internal struct ValueArray + { + public V _element0; + } + [InlineArray(MaxSize)] + internal struct WeightArray + { + public W _element0; + } + readonly ValueArray _values = new(); + readonly WeightArray _weights = new(); + byte _size = 0; + + /// + /// Current number of elements + /// + public readonly byte Size => _size; + + /// + /// Sorted list of values + /// + public readonly ReadOnlySpan Values => MemoryMarshal.CreateReadOnlySpan(ref Unsafe.As(ref Unsafe.AsRef(in _values)), _size); + + /// + /// Sorted list of weights + /// + public readonly ReadOnlySpan Weights => MemoryMarshal.CreateReadOnlySpan(ref Unsafe.As(ref Unsafe.AsRef(in _weights)), _size); + + /// + /// The smallest weight + /// + public readonly W MinWeight => _size > 0 ? Weights[_size - 1] : W.MaxValue; + + /// + /// The largest weight + /// + public readonly W MaxWeight => _size > 0 ? Weights[0] : W.MinValue; + + /// + /// The value with the smallest weight + /// + public readonly V? MinValue => _size > 0 ? Values[_size - 1] : default; + + /// + /// The value with the largest weight + /// + public readonly V? MaxValue => _size > 0 ? Values[0] : default; + + /// + /// Returns a value and weight + /// + /// Index to return + public readonly (V Value, W Weight) this[byte index] + { + get + { + if (index < Size) + return (Values[index], Weights[index]); + throw new ArgumentOutOfRangeException(); + } + } + + /// + /// Enumerates the values and weights + /// + public readonly IEnumerable<(V Value, W Weight)> Elements + { + get + { + for (byte i = 0; i < Size; i++) + yield return this[i]; + } + } + + /// + /// Tries to add a new element - will succeed if there aren't already max elements with a smaller weight + /// + /// Value to add + /// Weight to add + /// True if values should be unique - will return false if the value already exists + /// True if the element was added + public bool TryAdd(V value, W weight, bool enforceUnique = true) + { + var values = MemoryMarshal.CreateSpan(ref Unsafe.As(ref Unsafe.AsRef(in _values)), MaxSize); + var weights = MemoryMarshal.CreateSpan(ref Unsafe.As(ref Unsafe.AsRef(in _weights)), MaxSize); + return FixedSizeSortedArrayHelper.InsertIntoDescending(enforceUnique, ref _size, MaxSize, value, weight, values, weights); + } + + /// + /// Removes an element from the array + /// + /// Index of element to remove + /// + public void RemoveAt(byte index) + { + if(index >= _size) + throw new ArgumentOutOfRangeException(); + var values = MemoryMarshal.CreateSpan(ref Unsafe.As(ref Unsafe.AsRef(in _values)), _size); + var weights = MemoryMarshal.CreateSpan(ref Unsafe.As(ref Unsafe.AsRef(in _weights)), _size); + FixedSizeSortedArrayHelper.RemoveAt(index, values, weights); + --_size; + } + } + + /// + /// Fixed size sorted array of values and weights (max 29 elements) + /// that is sorted in ascending order based on each weight + /// + /// Type of value to store + /// Type of weight that will be used to sort + public record struct FixedSizeSortedAscending29Array() : IFixedSizeSortedArray + where V : IComparable + where W : unmanaged, INumber, IMinMaxValue + { + /// + /// Max size of the array + /// + public const int MaxSize = 29; + byte IFixedSizeSortedArray.MaxSize => MaxSize; + + [InlineArray(MaxSize)] + internal struct ValueArray + { + public V _element0; + } + [InlineArray(MaxSize)] + internal struct WeightArray + { + public W _element0; + } + readonly ValueArray _values = new(); + readonly WeightArray _weights = new(); + byte _size = 0; + + /// + /// Current number of elements + /// + public readonly byte Size => _size; + + /// + /// Sorted list of values + /// + public readonly ReadOnlySpan Values => MemoryMarshal.CreateReadOnlySpan(ref Unsafe.As(ref Unsafe.AsRef(in _values)), _size); + + /// + /// Sorted list of weights + /// + public readonly ReadOnlySpan Weights => MemoryMarshal.CreateReadOnlySpan(ref Unsafe.As(ref Unsafe.AsRef(in _weights)), _size); + + /// + /// The smallest weight + /// + public readonly W MinWeight => _size > 0 ? Weights[0] : W.MaxValue; + + /// + /// The largest weight + /// + public readonly W MaxWeight => _size > 0 ? Weights[_size - 1] : W.MinValue; + + /// + /// The value with the smallest weight + /// + public readonly V? MinValue => _size > 0 ? Values[0] : default; + + /// + /// The value with the largest weight + /// + public readonly V? MaxValue => _size > 0 ? Values[_size - 1] : default; + + /// + /// Returns a value and weight + /// + /// Index to return + public readonly (V Value, W Weight) this[byte index] + { + get + { + if (index < Size) + return (Values[index], Weights[index]); + throw new ArgumentOutOfRangeException(); + } + } + + /// + /// Enumerates the values and weights + /// + public readonly IEnumerable<(V Value, W Weight)> Elements + { + get + { + for (byte i = 0; i < Size; i++) + yield return this[i]; + } + } + + /// + /// Tries to add a new element - will succeed if there aren't already max elements with a smaller weight + /// + /// Value to add + /// Weight to add + /// True if values should be unique - will return false if the value already exists + /// True if the element was added + public bool TryAdd(V value, W weight, bool enforceUnique = true) + { + var values = MemoryMarshal.CreateSpan(ref Unsafe.As(ref Unsafe.AsRef(in _values)), MaxSize); + var weights = MemoryMarshal.CreateSpan(ref Unsafe.As(ref Unsafe.AsRef(in _weights)), MaxSize); + return FixedSizeSortedArrayHelper.InsertIntoAscending(enforceUnique, ref _size, MaxSize, value, weight, values, weights); + } + + /// + /// Removes an element from the array + /// + /// Index of element to remove + /// + public void RemoveAt(byte index) + { + if(index >= _size) + throw new ArgumentOutOfRangeException(); + var values = MemoryMarshal.CreateSpan(ref Unsafe.As(ref Unsafe.AsRef(in _values)), _size); + var weights = MemoryMarshal.CreateSpan(ref Unsafe.As(ref Unsafe.AsRef(in _weights)), _size); + FixedSizeSortedArrayHelper.RemoveAt(index, values, weights); + --_size; + } + } + + /// + /// Fixed size sorted array of values and weights (max 29 elements) + /// that is sorted in descending order based on each weight + /// + /// Type of value to store + /// Type of weight that will be used to sort + public record struct FixedSizeSortedDescending29Array() + where V : IComparable + where W : unmanaged, INumber, IMinMaxValue + { + /// + /// Max size of the array + /// + public const int MaxSize = 29; + + [InlineArray(MaxSize)] + internal struct ValueArray + { + public V _element0; + } + [InlineArray(MaxSize)] + internal struct WeightArray + { + public W _element0; + } + readonly ValueArray _values = new(); + readonly WeightArray _weights = new(); + byte _size = 0; + + /// + /// Current number of elements + /// + public readonly byte Size => _size; + + /// + /// Sorted list of values + /// + public readonly ReadOnlySpan Values => MemoryMarshal.CreateReadOnlySpan(ref Unsafe.As(ref Unsafe.AsRef(in _values)), _size); + + /// + /// Sorted list of weights + /// + public readonly ReadOnlySpan Weights => MemoryMarshal.CreateReadOnlySpan(ref Unsafe.As(ref Unsafe.AsRef(in _weights)), _size); + + /// + /// The smallest weight + /// + public readonly W MinWeight => _size > 0 ? Weights[_size - 1] : W.MaxValue; + + /// + /// The largest weight + /// + public readonly W MaxWeight => _size > 0 ? Weights[0] : W.MinValue; + + /// + /// The value with the smallest weight + /// + public readonly V? MinValue => _size > 0 ? Values[_size - 1] : default; + + /// + /// The value with the largest weight + /// + public readonly V? MaxValue => _size > 0 ? Values[0] : default; + + /// + /// Returns a value and weight + /// + /// Index to return + public readonly (V Value, W Weight) this[byte index] + { + get + { + if (index < Size) + return (Values[index], Weights[index]); + throw new ArgumentOutOfRangeException(); + } + } + + /// + /// Enumerates the values and weights + /// + public readonly IEnumerable<(V Value, W Weight)> Elements + { + get + { + for (byte i = 0; i < Size; i++) + yield return this[i]; + } + } + + /// + /// Tries to add a new element - will succeed if there aren't already max elements with a smaller weight + /// + /// Value to add + /// Weight to add + /// True if values should be unique - will return false if the value already exists + /// True if the element was added + public bool TryAdd(V value, W weight, bool enforceUnique = true) + { + var values = MemoryMarshal.CreateSpan(ref Unsafe.As(ref Unsafe.AsRef(in _values)), MaxSize); + var weights = MemoryMarshal.CreateSpan(ref Unsafe.As(ref Unsafe.AsRef(in _weights)), MaxSize); + return FixedSizeSortedArrayHelper.InsertIntoDescending(enforceUnique, ref _size, MaxSize, value, weight, values, weights); + } + + /// + /// Removes an element from the array + /// + /// Index of element to remove + /// + public void RemoveAt(byte index) + { + if(index >= _size) + throw new ArgumentOutOfRangeException(); + var values = MemoryMarshal.CreateSpan(ref Unsafe.As(ref Unsafe.AsRef(in _values)), _size); + var weights = MemoryMarshal.CreateSpan(ref Unsafe.As(ref Unsafe.AsRef(in _weights)), _size); + FixedSizeSortedArrayHelper.RemoveAt(index, values, weights); + --_size; + } + } + + /// + /// Fixed size sorted array of values and weights (max 30 elements) + /// that is sorted in ascending order based on each weight + /// + /// Type of value to store + /// Type of weight that will be used to sort + public record struct FixedSizeSortedAscending30Array() : IFixedSizeSortedArray + where V : IComparable + where W : unmanaged, INumber, IMinMaxValue + { + /// + /// Max size of the array + /// + public const int MaxSize = 30; + byte IFixedSizeSortedArray.MaxSize => MaxSize; + + [InlineArray(MaxSize)] + internal struct ValueArray + { + public V _element0; + } + [InlineArray(MaxSize)] + internal struct WeightArray + { + public W _element0; + } + readonly ValueArray _values = new(); + readonly WeightArray _weights = new(); + byte _size = 0; + + /// + /// Current number of elements + /// + public readonly byte Size => _size; + + /// + /// Sorted list of values + /// + public readonly ReadOnlySpan Values => MemoryMarshal.CreateReadOnlySpan(ref Unsafe.As(ref Unsafe.AsRef(in _values)), _size); + + /// + /// Sorted list of weights + /// + public readonly ReadOnlySpan Weights => MemoryMarshal.CreateReadOnlySpan(ref Unsafe.As(ref Unsafe.AsRef(in _weights)), _size); + + /// + /// The smallest weight + /// + public readonly W MinWeight => _size > 0 ? Weights[0] : W.MaxValue; + + /// + /// The largest weight + /// + public readonly W MaxWeight => _size > 0 ? Weights[_size - 1] : W.MinValue; + + /// + /// The value with the smallest weight + /// + public readonly V? MinValue => _size > 0 ? Values[0] : default; + + /// + /// The value with the largest weight + /// + public readonly V? MaxValue => _size > 0 ? Values[_size - 1] : default; + + /// + /// Returns a value and weight + /// + /// Index to return + public readonly (V Value, W Weight) this[byte index] + { + get + { + if (index < Size) + return (Values[index], Weights[index]); + throw new ArgumentOutOfRangeException(); + } + } + + /// + /// Enumerates the values and weights + /// + public readonly IEnumerable<(V Value, W Weight)> Elements + { + get + { + for (byte i = 0; i < Size; i++) + yield return this[i]; + } + } + + /// + /// Tries to add a new element - will succeed if there aren't already max elements with a smaller weight + /// + /// Value to add + /// Weight to add + /// True if values should be unique - will return false if the value already exists + /// True if the element was added + public bool TryAdd(V value, W weight, bool enforceUnique = true) + { + var values = MemoryMarshal.CreateSpan(ref Unsafe.As(ref Unsafe.AsRef(in _values)), MaxSize); + var weights = MemoryMarshal.CreateSpan(ref Unsafe.As(ref Unsafe.AsRef(in _weights)), MaxSize); + return FixedSizeSortedArrayHelper.InsertIntoAscending(enforceUnique, ref _size, MaxSize, value, weight, values, weights); + } + + /// + /// Removes an element from the array + /// + /// Index of element to remove + /// + public void RemoveAt(byte index) + { + if(index >= _size) + throw new ArgumentOutOfRangeException(); + var values = MemoryMarshal.CreateSpan(ref Unsafe.As(ref Unsafe.AsRef(in _values)), _size); + var weights = MemoryMarshal.CreateSpan(ref Unsafe.As(ref Unsafe.AsRef(in _weights)), _size); + FixedSizeSortedArrayHelper.RemoveAt(index, values, weights); + --_size; + } + } + + /// + /// Fixed size sorted array of values and weights (max 30 elements) + /// that is sorted in descending order based on each weight + /// + /// Type of value to store + /// Type of weight that will be used to sort + public record struct FixedSizeSortedDescending30Array() + where V : IComparable + where W : unmanaged, INumber, IMinMaxValue + { + /// + /// Max size of the array + /// + public const int MaxSize = 30; + + [InlineArray(MaxSize)] + internal struct ValueArray + { + public V _element0; + } + [InlineArray(MaxSize)] + internal struct WeightArray + { + public W _element0; + } + readonly ValueArray _values = new(); + readonly WeightArray _weights = new(); + byte _size = 0; + + /// + /// Current number of elements + /// + public readonly byte Size => _size; + + /// + /// Sorted list of values + /// + public readonly ReadOnlySpan Values => MemoryMarshal.CreateReadOnlySpan(ref Unsafe.As(ref Unsafe.AsRef(in _values)), _size); + + /// + /// Sorted list of weights + /// + public readonly ReadOnlySpan Weights => MemoryMarshal.CreateReadOnlySpan(ref Unsafe.As(ref Unsafe.AsRef(in _weights)), _size); + + /// + /// The smallest weight + /// + public readonly W MinWeight => _size > 0 ? Weights[_size - 1] : W.MaxValue; + + /// + /// The largest weight + /// + public readonly W MaxWeight => _size > 0 ? Weights[0] : W.MinValue; + + /// + /// The value with the smallest weight + /// + public readonly V? MinValue => _size > 0 ? Values[_size - 1] : default; + + /// + /// The value with the largest weight + /// + public readonly V? MaxValue => _size > 0 ? Values[0] : default; + + /// + /// Returns a value and weight + /// + /// Index to return + public readonly (V Value, W Weight) this[byte index] + { + get + { + if (index < Size) + return (Values[index], Weights[index]); + throw new ArgumentOutOfRangeException(); + } + } + + /// + /// Enumerates the values and weights + /// + public readonly IEnumerable<(V Value, W Weight)> Elements + { + get + { + for (byte i = 0; i < Size; i++) + yield return this[i]; + } + } + + /// + /// Tries to add a new element - will succeed if there aren't already max elements with a smaller weight + /// + /// Value to add + /// Weight to add + /// True if values should be unique - will return false if the value already exists + /// True if the element was added + public bool TryAdd(V value, W weight, bool enforceUnique = true) + { + var values = MemoryMarshal.CreateSpan(ref Unsafe.As(ref Unsafe.AsRef(in _values)), MaxSize); + var weights = MemoryMarshal.CreateSpan(ref Unsafe.As(ref Unsafe.AsRef(in _weights)), MaxSize); + return FixedSizeSortedArrayHelper.InsertIntoDescending(enforceUnique, ref _size, MaxSize, value, weight, values, weights); + } + + /// + /// Removes an element from the array + /// + /// Index of element to remove + /// + public void RemoveAt(byte index) + { + if(index >= _size) + throw new ArgumentOutOfRangeException(); + var values = MemoryMarshal.CreateSpan(ref Unsafe.As(ref Unsafe.AsRef(in _values)), _size); + var weights = MemoryMarshal.CreateSpan(ref Unsafe.As(ref Unsafe.AsRef(in _weights)), _size); + FixedSizeSortedArrayHelper.RemoveAt(index, values, weights); + --_size; + } + } + + /// + /// Fixed size sorted array of values and weights (max 31 elements) + /// that is sorted in ascending order based on each weight + /// + /// Type of value to store + /// Type of weight that will be used to sort + public record struct FixedSizeSortedAscending31Array() : IFixedSizeSortedArray + where V : IComparable + where W : unmanaged, INumber, IMinMaxValue + { + /// + /// Max size of the array + /// + public const int MaxSize = 31; + byte IFixedSizeSortedArray.MaxSize => MaxSize; + + [InlineArray(MaxSize)] + internal struct ValueArray + { + public V _element0; + } + [InlineArray(MaxSize)] + internal struct WeightArray + { + public W _element0; + } + readonly ValueArray _values = new(); + readonly WeightArray _weights = new(); + byte _size = 0; + + /// + /// Current number of elements + /// + public readonly byte Size => _size; + + /// + /// Sorted list of values + /// + public readonly ReadOnlySpan Values => MemoryMarshal.CreateReadOnlySpan(ref Unsafe.As(ref Unsafe.AsRef(in _values)), _size); + + /// + /// Sorted list of weights + /// + public readonly ReadOnlySpan Weights => MemoryMarshal.CreateReadOnlySpan(ref Unsafe.As(ref Unsafe.AsRef(in _weights)), _size); + + /// + /// The smallest weight + /// + public readonly W MinWeight => _size > 0 ? Weights[0] : W.MaxValue; + + /// + /// The largest weight + /// + public readonly W MaxWeight => _size > 0 ? Weights[_size - 1] : W.MinValue; + + /// + /// The value with the smallest weight + /// + public readonly V? MinValue => _size > 0 ? Values[0] : default; + + /// + /// The value with the largest weight + /// + public readonly V? MaxValue => _size > 0 ? Values[_size - 1] : default; + + /// + /// Returns a value and weight + /// + /// Index to return + public readonly (V Value, W Weight) this[byte index] + { + get + { + if (index < Size) + return (Values[index], Weights[index]); + throw new ArgumentOutOfRangeException(); + } + } + + /// + /// Enumerates the values and weights + /// + public readonly IEnumerable<(V Value, W Weight)> Elements + { + get + { + for (byte i = 0; i < Size; i++) + yield return this[i]; + } + } + + /// + /// Tries to add a new element - will succeed if there aren't already max elements with a smaller weight + /// + /// Value to add + /// Weight to add + /// True if values should be unique - will return false if the value already exists + /// True if the element was added + public bool TryAdd(V value, W weight, bool enforceUnique = true) + { + var values = MemoryMarshal.CreateSpan(ref Unsafe.As(ref Unsafe.AsRef(in _values)), MaxSize); + var weights = MemoryMarshal.CreateSpan(ref Unsafe.As(ref Unsafe.AsRef(in _weights)), MaxSize); + return FixedSizeSortedArrayHelper.InsertIntoAscending(enforceUnique, ref _size, MaxSize, value, weight, values, weights); + } + + /// + /// Removes an element from the array + /// + /// Index of element to remove + /// + public void RemoveAt(byte index) + { + if(index >= _size) + throw new ArgumentOutOfRangeException(); + var values = MemoryMarshal.CreateSpan(ref Unsafe.As(ref Unsafe.AsRef(in _values)), _size); + var weights = MemoryMarshal.CreateSpan(ref Unsafe.As(ref Unsafe.AsRef(in _weights)), _size); + FixedSizeSortedArrayHelper.RemoveAt(index, values, weights); + --_size; + } + } + + /// + /// Fixed size sorted array of values and weights (max 31 elements) + /// that is sorted in descending order based on each weight + /// + /// Type of value to store + /// Type of weight that will be used to sort + public record struct FixedSizeSortedDescending31Array() + where V : IComparable + where W : unmanaged, INumber, IMinMaxValue + { + /// + /// Max size of the array + /// + public const int MaxSize = 31; + + [InlineArray(MaxSize)] + internal struct ValueArray + { + public V _element0; + } + [InlineArray(MaxSize)] + internal struct WeightArray + { + public W _element0; + } + readonly ValueArray _values = new(); + readonly WeightArray _weights = new(); + byte _size = 0; + + /// + /// Current number of elements + /// + public readonly byte Size => _size; + + /// + /// Sorted list of values + /// + public readonly ReadOnlySpan Values => MemoryMarshal.CreateReadOnlySpan(ref Unsafe.As(ref Unsafe.AsRef(in _values)), _size); + + /// + /// Sorted list of weights + /// + public readonly ReadOnlySpan Weights => MemoryMarshal.CreateReadOnlySpan(ref Unsafe.As(ref Unsafe.AsRef(in _weights)), _size); + + /// + /// The smallest weight + /// + public readonly W MinWeight => _size > 0 ? Weights[_size - 1] : W.MaxValue; + + /// + /// The largest weight + /// + public readonly W MaxWeight => _size > 0 ? Weights[0] : W.MinValue; + + /// + /// The value with the smallest weight + /// + public readonly V? MinValue => _size > 0 ? Values[_size - 1] : default; + + /// + /// The value with the largest weight + /// + public readonly V? MaxValue => _size > 0 ? Values[0] : default; + + /// + /// Returns a value and weight + /// + /// Index to return + public readonly (V Value, W Weight) this[byte index] + { + get + { + if (index < Size) + return (Values[index], Weights[index]); + throw new ArgumentOutOfRangeException(); + } + } + + /// + /// Enumerates the values and weights + /// + public readonly IEnumerable<(V Value, W Weight)> Elements + { + get + { + for (byte i = 0; i < Size; i++) + yield return this[i]; + } + } + + /// + /// Tries to add a new element - will succeed if there aren't already max elements with a smaller weight + /// + /// Value to add + /// Weight to add + /// True if values should be unique - will return false if the value already exists + /// True if the element was added + public bool TryAdd(V value, W weight, bool enforceUnique = true) + { + var values = MemoryMarshal.CreateSpan(ref Unsafe.As(ref Unsafe.AsRef(in _values)), MaxSize); + var weights = MemoryMarshal.CreateSpan(ref Unsafe.As(ref Unsafe.AsRef(in _weights)), MaxSize); + return FixedSizeSortedArrayHelper.InsertIntoDescending(enforceUnique, ref _size, MaxSize, value, weight, values, weights); + } + + /// + /// Removes an element from the array + /// + /// Index of element to remove + /// + public void RemoveAt(byte index) + { + if(index >= _size) + throw new ArgumentOutOfRangeException(); + var values = MemoryMarshal.CreateSpan(ref Unsafe.As(ref Unsafe.AsRef(in _values)), _size); + var weights = MemoryMarshal.CreateSpan(ref Unsafe.As(ref Unsafe.AsRef(in _weights)), _size); + FixedSizeSortedArrayHelper.RemoveAt(index, values, weights); + --_size; + } + } + + /// + /// Fixed size sorted array of values and weights (max 32 elements) + /// that is sorted in ascending order based on each weight + /// + /// Type of value to store + /// Type of weight that will be used to sort + public record struct FixedSizeSortedAscending32Array() : IFixedSizeSortedArray + where V : IComparable + where W : unmanaged, INumber, IMinMaxValue + { + /// + /// Max size of the array + /// + public const int MaxSize = 32; + byte IFixedSizeSortedArray.MaxSize => MaxSize; + + [InlineArray(MaxSize)] + internal struct ValueArray + { + public V _element0; + } + [InlineArray(MaxSize)] + internal struct WeightArray + { + public W _element0; + } + readonly ValueArray _values = new(); + readonly WeightArray _weights = new(); + byte _size = 0; + + /// + /// Current number of elements + /// + public readonly byte Size => _size; + + /// + /// Sorted list of values + /// + public readonly ReadOnlySpan Values => MemoryMarshal.CreateReadOnlySpan(ref Unsafe.As(ref Unsafe.AsRef(in _values)), _size); + + /// + /// Sorted list of weights + /// + public readonly ReadOnlySpan Weights => MemoryMarshal.CreateReadOnlySpan(ref Unsafe.As(ref Unsafe.AsRef(in _weights)), _size); + + /// + /// The smallest weight + /// + public readonly W MinWeight => _size > 0 ? Weights[0] : W.MaxValue; + + /// + /// The largest weight + /// + public readonly W MaxWeight => _size > 0 ? Weights[_size - 1] : W.MinValue; + + /// + /// The value with the smallest weight + /// + public readonly V? MinValue => _size > 0 ? Values[0] : default; + + /// + /// The value with the largest weight + /// + public readonly V? MaxValue => _size > 0 ? Values[_size - 1] : default; + + /// + /// Returns a value and weight + /// + /// Index to return + public readonly (V Value, W Weight) this[byte index] + { + get + { + if (index < Size) + return (Values[index], Weights[index]); + throw new ArgumentOutOfRangeException(); + } + } + + /// + /// Enumerates the values and weights + /// + public readonly IEnumerable<(V Value, W Weight)> Elements + { + get + { + for (byte i = 0; i < Size; i++) + yield return this[i]; + } + } + + /// + /// Tries to add a new element - will succeed if there aren't already max elements with a smaller weight + /// + /// Value to add + /// Weight to add + /// True if values should be unique - will return false if the value already exists + /// True if the element was added + public bool TryAdd(V value, W weight, bool enforceUnique = true) + { + var values = MemoryMarshal.CreateSpan(ref Unsafe.As(ref Unsafe.AsRef(in _values)), MaxSize); + var weights = MemoryMarshal.CreateSpan(ref Unsafe.As(ref Unsafe.AsRef(in _weights)), MaxSize); + return FixedSizeSortedArrayHelper.InsertIntoAscending(enforceUnique, ref _size, MaxSize, value, weight, values, weights); + } + + /// + /// Removes an element from the array + /// + /// Index of element to remove + /// + public void RemoveAt(byte index) + { + if(index >= _size) + throw new ArgumentOutOfRangeException(); + var values = MemoryMarshal.CreateSpan(ref Unsafe.As(ref Unsafe.AsRef(in _values)), _size); + var weights = MemoryMarshal.CreateSpan(ref Unsafe.As(ref Unsafe.AsRef(in _weights)), _size); + FixedSizeSortedArrayHelper.RemoveAt(index, values, weights); + --_size; + } + } + + /// + /// Fixed size sorted array of values and weights (max 32 elements) + /// that is sorted in descending order based on each weight + /// + /// Type of value to store + /// Type of weight that will be used to sort + public record struct FixedSizeSortedDescending32Array() + where V : IComparable + where W : unmanaged, INumber, IMinMaxValue + { + /// + /// Max size of the array + /// + public const int MaxSize = 32; + + [InlineArray(MaxSize)] + internal struct ValueArray + { + public V _element0; + } + [InlineArray(MaxSize)] + internal struct WeightArray + { + public W _element0; + } + readonly ValueArray _values = new(); + readonly WeightArray _weights = new(); + byte _size = 0; + + /// + /// Current number of elements + /// + public readonly byte Size => _size; + + /// + /// Sorted list of values + /// + public readonly ReadOnlySpan Values => MemoryMarshal.CreateReadOnlySpan(ref Unsafe.As(ref Unsafe.AsRef(in _values)), _size); + + /// + /// Sorted list of weights + /// + public readonly ReadOnlySpan Weights => MemoryMarshal.CreateReadOnlySpan(ref Unsafe.As(ref Unsafe.AsRef(in _weights)), _size); + + /// + /// The smallest weight + /// + public readonly W MinWeight => _size > 0 ? Weights[_size - 1] : W.MaxValue; + + /// + /// The largest weight + /// + public readonly W MaxWeight => _size > 0 ? Weights[0] : W.MinValue; + + /// + /// The value with the smallest weight + /// + public readonly V? MinValue => _size > 0 ? Values[_size - 1] : default; + + /// + /// The value with the largest weight + /// + public readonly V? MaxValue => _size > 0 ? Values[0] : default; + + /// + /// Returns a value and weight + /// + /// Index to return + public readonly (V Value, W Weight) this[byte index] + { + get + { + if (index < Size) + return (Values[index], Weights[index]); + throw new ArgumentOutOfRangeException(); + } + } + + /// + /// Enumerates the values and weights + /// + public readonly IEnumerable<(V Value, W Weight)> Elements + { + get + { + for (byte i = 0; i < Size; i++) + yield return this[i]; + } + } + + /// + /// Tries to add a new element - will succeed if there aren't already max elements with a smaller weight + /// + /// Value to add + /// Weight to add + /// True if values should be unique - will return false if the value already exists + /// True if the element was added + public bool TryAdd(V value, W weight, bool enforceUnique = true) + { + var values = MemoryMarshal.CreateSpan(ref Unsafe.As(ref Unsafe.AsRef(in _values)), MaxSize); + var weights = MemoryMarshal.CreateSpan(ref Unsafe.As(ref Unsafe.AsRef(in _weights)), MaxSize); + return FixedSizeSortedArrayHelper.InsertIntoDescending(enforceUnique, ref _size, MaxSize, value, weight, values, weights); + } + + /// + /// Removes an element from the array + /// + /// Index of element to remove + /// + public void RemoveAt(byte index) + { + if(index >= _size) + throw new ArgumentOutOfRangeException(); + var values = MemoryMarshal.CreateSpan(ref Unsafe.As(ref Unsafe.AsRef(in _values)), _size); + var weights = MemoryMarshal.CreateSpan(ref Unsafe.As(ref Unsafe.AsRef(in _weights)), _size); + FixedSizeSortedArrayHelper.RemoveAt(index, values, weights); + --_size; + } + } + +} \ No newline at end of file diff --git a/BrightData/Types/FixedSizeSortedArray/FixedSizeSortedArray.tt b/BrightData/Types/FixedSizeSortedArray/FixedSizeSortedArray.tt new file mode 100644 index 00000000..49e9c088 --- /dev/null +++ b/BrightData/Types/FixedSizeSortedArray/FixedSizeSortedArray.tt @@ -0,0 +1,259 @@ +<#@ template debug="false" hostspecific="false" language="C#" #> +<#@ assembly name="System.Core" #> +<#@ import namespace="System.Linq" #> +<#@ import namespace="System.Text" #> +<#@ import namespace="System.Collections.Generic" #> +<#@ output extension=".cs" #> +using System; +using System.Numerics; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Collections.Generic; +using BrightData.Types.FixedSizeSortedArray; + +namespace BrightData.Types +{ +<# for(var i = 2; i <= 32; i++) { #> + /// + /// Fixed size sorted array of values and weights (max <#= i #> elements) + /// that is sorted in ascending order based on each weight + /// + /// Type of value to store + /// Type of weight that will be used to sort + public record struct FixedSizeSortedAscending<#= i #>Array() : IFixedSizeSortedArray + where V : IComparable + where W : unmanaged, INumber, IMinMaxValue + { + /// + /// Max size of the array + /// + public const int MaxSize = <#= i #>; + byte IFixedSizeSortedArray.MaxSize => MaxSize; + + [InlineArray(MaxSize)] + internal struct ValueArray + { + public V _element0; + } + [InlineArray(MaxSize)] + internal struct WeightArray + { + public W _element0; + } + readonly ValueArray _values = new(); + readonly WeightArray _weights = new(); + byte _size = 0; + + /// + /// Current number of elements + /// + public readonly byte Size => _size; + + /// + /// Sorted list of values + /// + public readonly ReadOnlySpan Values => MemoryMarshal.CreateReadOnlySpan(ref Unsafe.As(ref Unsafe.AsRef(in _values)), _size); + + /// + /// Sorted list of weights + /// + public readonly ReadOnlySpan Weights => MemoryMarshal.CreateReadOnlySpan(ref Unsafe.As(ref Unsafe.AsRef(in _weights)), _size); + + /// + /// The smallest weight + /// + public readonly W MinWeight => _size > 0 ? Weights[0] : W.MaxValue; + + /// + /// The largest weight + /// + public readonly W MaxWeight => _size > 0 ? Weights[_size - 1] : W.MinValue; + + /// + /// The value with the smallest weight + /// + public readonly V? MinValue => _size > 0 ? Values[0] : default; + + /// + /// The value with the largest weight + /// + public readonly V? MaxValue => _size > 0 ? Values[_size - 1] : default; + + /// + /// Returns a value and weight + /// + /// Index to return + public readonly (V Value, W Weight) this[byte index] + { + get + { + if (index < Size) + return (Values[index], Weights[index]); + throw new ArgumentOutOfRangeException(); + } + } + + /// + /// Enumerates the values and weights + /// + public readonly IEnumerable<(V Value, W Weight)> Elements + { + get + { + for (byte i = 0; i < Size; i++) + yield return this[i]; + } + } + + /// + /// Tries to add a new element - will succeed if there aren't already max elements with a smaller weight + /// + /// Value to add + /// Weight to add + /// True if values should be unique - will return false if the value already exists + /// True if the element was added + public bool TryAdd(V value, W weight, bool enforceUnique = true) + { + var values = MemoryMarshal.CreateSpan(ref Unsafe.As(ref Unsafe.AsRef(in _values)), MaxSize); + var weights = MemoryMarshal.CreateSpan(ref Unsafe.As(ref Unsafe.AsRef(in _weights)), MaxSize); + return FixedSizeSortedArrayHelper.InsertIntoAscending(enforceUnique, ref _size, MaxSize, value, weight, values, weights); + } + + /// + /// Removes an element from the array + /// + /// Index of element to remove + /// + public void RemoveAt(byte index) + { + if(index >= _size) + throw new ArgumentOutOfRangeException(); + var values = MemoryMarshal.CreateSpan(ref Unsafe.As(ref Unsafe.AsRef(in _values)), _size); + var weights = MemoryMarshal.CreateSpan(ref Unsafe.As(ref Unsafe.AsRef(in _weights)), _size); + FixedSizeSortedArrayHelper.RemoveAt(index, values, weights); + --_size; + } + } + + /// + /// Fixed size sorted array of values and weights (max <#= i #> elements) + /// that is sorted in descending order based on each weight + /// + /// Type of value to store + /// Type of weight that will be used to sort + public record struct FixedSizeSortedDescending<#= i #>Array() + where V : IComparable + where W : unmanaged, INumber, IMinMaxValue + { + /// + /// Max size of the array + /// + public const int MaxSize = <#= i #>; + + [InlineArray(MaxSize)] + internal struct ValueArray + { + public V _element0; + } + [InlineArray(MaxSize)] + internal struct WeightArray + { + public W _element0; + } + readonly ValueArray _values = new(); + readonly WeightArray _weights = new(); + byte _size = 0; + + /// + /// Current number of elements + /// + public readonly byte Size => _size; + + /// + /// Sorted list of values + /// + public readonly ReadOnlySpan Values => MemoryMarshal.CreateReadOnlySpan(ref Unsafe.As(ref Unsafe.AsRef(in _values)), _size); + + /// + /// Sorted list of weights + /// + public readonly ReadOnlySpan Weights => MemoryMarshal.CreateReadOnlySpan(ref Unsafe.As(ref Unsafe.AsRef(in _weights)), _size); + + /// + /// The smallest weight + /// + public readonly W MinWeight => _size > 0 ? Weights[_size - 1] : W.MaxValue; + + /// + /// The largest weight + /// + public readonly W MaxWeight => _size > 0 ? Weights[0] : W.MinValue; + + /// + /// The value with the smallest weight + /// + public readonly V? MinValue => _size > 0 ? Values[_size - 1] : default; + + /// + /// The value with the largest weight + /// + public readonly V? MaxValue => _size > 0 ? Values[0] : default; + + /// + /// Returns a value and weight + /// + /// Index to return + public readonly (V Value, W Weight) this[byte index] + { + get + { + if (index < Size) + return (Values[index], Weights[index]); + throw new ArgumentOutOfRangeException(); + } + } + + /// + /// Enumerates the values and weights + /// + public readonly IEnumerable<(V Value, W Weight)> Elements + { + get + { + for (byte i = 0; i < Size; i++) + yield return this[i]; + } + } + + /// + /// Tries to add a new element - will succeed if there aren't already max elements with a smaller weight + /// + /// Value to add + /// Weight to add + /// True if values should be unique - will return false if the value already exists + /// True if the element was added + public bool TryAdd(V value, W weight, bool enforceUnique = true) + { + var values = MemoryMarshal.CreateSpan(ref Unsafe.As(ref Unsafe.AsRef(in _values)), MaxSize); + var weights = MemoryMarshal.CreateSpan(ref Unsafe.As(ref Unsafe.AsRef(in _weights)), MaxSize); + return FixedSizeSortedArrayHelper.InsertIntoDescending(enforceUnique, ref _size, MaxSize, value, weight, values, weights); + } + + /// + /// Removes an element from the array + /// + /// Index of element to remove + /// + public void RemoveAt(byte index) + { + if(index >= _size) + throw new ArgumentOutOfRangeException(); + var values = MemoryMarshal.CreateSpan(ref Unsafe.As(ref Unsafe.AsRef(in _values)), _size); + var weights = MemoryMarshal.CreateSpan(ref Unsafe.As(ref Unsafe.AsRef(in _weights)), _size); + FixedSizeSortedArrayHelper.RemoveAt(index, values, weights); + --_size; + } + } + +<# } #> +} \ No newline at end of file diff --git a/BrightData/Types/FixedSizeSortedArray/FixedSizeSortedArrayHelper.cs b/BrightData/Types/FixedSizeSortedArray/FixedSizeSortedArrayHelper.cs new file mode 100644 index 00000000..6c621d83 --- /dev/null +++ b/BrightData/Types/FixedSizeSortedArray/FixedSizeSortedArrayHelper.cs @@ -0,0 +1,154 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Numerics; +using System.Text; +using System.Threading.Tasks; + +namespace BrightData.Types.FixedSizeSortedArray +{ + internal class FixedSizeSortedArrayHelper + { + public static bool InsertIntoAscending(bool enforceUnique, ref byte size, byte maxSize, V value, W weight, Span values, Span weights) + where V : IComparable + where W : unmanaged, INumber, IMinMaxValue + { + var isFull = size == maxSize; + + // check to see if it should be inserted + if (isFull && weights[size - 1] <= weight) + return false; + + // use binary search to find the insertion position + int left = 0, + right = size - 1, + insertPosition = size + ; + while (left <= right) { + var mid = left + (right - left) / 2; + if (weights[mid] > weight) { + insertPosition = mid; + right = mid - 1; + } + else { + // check for an existing weight/value + if (enforceUnique && weights[mid] == weight && values[mid].CompareTo(value) == 0) + return false; + left = mid + 1; + } + } + + if (enforceUnique) { + // check if the same element already exists in the left partition + for (var i = insertPosition - 1; i >= 0; i--) { + if (weights[i] < weight) + break; + if (values[i].CompareTo(value) == 0) + return false; + } + + // check if the same element already exists in the right partition + for (var i = insertPosition; i < size; i++) { + if (weights[i] > weight) + break; + if (values[i].CompareTo(value) == 0) + return false; + } + } + + if (insertPosition == size) { + // there is no room left + if (isFull) + return false; + } + else { + // shuffle to make room + for (var i = size - (isFull ? 2 : 1); i >= insertPosition; i--) { + values[i + 1] = values[i]; + weights[i + 1] = weights[i]; + } + } + + // insert the item + values[insertPosition] = value; + weights[insertPosition] = weight; + if (!isFull) + ++size; + return true; + } + + public static bool InsertIntoDescending(bool enforceUnique, ref byte size, byte maxSize, V value, W weight, Span values, Span weights) + where V : IComparable + where W : unmanaged, INumber, IMinMaxValue + { + var isFull = size == maxSize; + + // check to see if it should be inserted + if (isFull && weights[size - 1] >= weight) + return false; + + // use binary search to find the insertion position + int left = 0, + right = size - 1, + insertPosition = size + ; + while (left <= right) { + var mid = left + (right - left) / 2; + if (weights[mid] < weight) { + insertPosition = mid; + right = mid - 1; + } + else { + // check for an existing weight/value + if (enforceUnique && weights[mid] == weight && values[mid].CompareTo(value) == 0) + return false; + left = mid + 1; + } + } + + if (enforceUnique) { + // check if the same element already exists in the left partition + for (var i = insertPosition - 1; i >= 0; i--) { + if (weights[i] > weight) + break; + if (values[i].CompareTo(value) == 0) + return false; + } + + // check if the same element already exists in the right partition + for (var i = insertPosition; i < size; i++) { + if (weights[i] < weight) + break; + if (values[i].CompareTo(value) == 0) + return false; + } + } + + if (insertPosition == size) { + // there is no room left + if (isFull) + return false; + } + else { + // shuffle to make room + for (var i = size - (isFull ? 2 : 1); i >= insertPosition; i--) { + values[i + 1] = values[i]; + weights[i + 1] = weights[i]; + } + } + + // insert the item + values[insertPosition] = value; + weights[insertPosition] = weight; + if (!isFull) + ++size; + return true; + } + + public static void RemoveAt(byte index, Span values, Span weights) + { + values[(index+1)..].CopyTo(values[index..]); + weights[(index+1)..].CopyTo(weights[index..]); + } + } +}