diff --git a/src/flatcollections-array/FlatArray/FlatArray.T.Builder/FlatArray.Builder.AddRange.Array.cs b/src/flatcollections-array/FlatArray/FlatArray.T.Builder/FlatArray.Builder.AddRange.Array.cs index 83252633..6c24af61 100644 --- a/src/flatcollections-array/FlatArray/FlatArray.T.Builder/FlatArray.Builder.AddRange.Array.cs +++ b/src/flatcollections-array/FlatArray/FlatArray.T.Builder/FlatArray.Builder.AddRange.Array.cs @@ -25,7 +25,7 @@ internal Builder AddRange([AllowNull] T[] items, int length) { var itemsLength = items?.Length ?? default; - if (InnerAllocHelper.IsWithin(length, itemsLength) is not true) + if (InnerAllocHelper.IsWithinLength(length, itemsLength) is not true) { throw InnerExceptionFactory.StartSegmentIsNotWithinArray(nameof(length), length, itemsLength); } diff --git a/src/flatcollections-array/FlatArray/FlatArray.T.Builder/FlatArray.Builder.AddRange.FlatArray.cs b/src/flatcollections-array/FlatArray/FlatArray.T.Builder/FlatArray.Builder.AddRange.FlatArray.cs index d850a53f..71d5f076 100644 --- a/src/flatcollections-array/FlatArray/FlatArray.T.Builder/FlatArray.Builder.AddRange.FlatArray.cs +++ b/src/flatcollections-array/FlatArray/FlatArray.T.Builder/FlatArray.Builder.AddRange.FlatArray.cs @@ -31,7 +31,7 @@ internal Builder AddRange(FlatArray? items, int length) private Builder InnerAddRangeChecked( FlatArray items, int length, [CallerArgumentExpression(nameof(length))] string lengthParamName = "") { - if (InnerAllocHelper.IsWithin(length, items.length) is not true) + if (InnerAllocHelper.IsWithinLength(length, items.length) is not true) { throw InnerExceptionFactory.StartSegmentIsNotWithinArray(lengthParamName, length, items.length); } diff --git a/src/flatcollections-array/FlatArray/FlatArray.T.Builder/FlatArray.Builder.AddRange.ImmutableArray.cs b/src/flatcollections-array/FlatArray/FlatArray.T.Builder/FlatArray.Builder.AddRange.ImmutableArray.cs index 155393e3..0d3c2e77 100644 --- a/src/flatcollections-array/FlatArray/FlatArray.T.Builder/FlatArray.Builder.AddRange.ImmutableArray.cs +++ b/src/flatcollections-array/FlatArray/FlatArray.T.Builder/FlatArray.Builder.AddRange.ImmutableArray.cs @@ -35,7 +35,7 @@ private Builder InnerAddRangeChecked( { var itemsLength = items.IsDefault ? default : items.Length; - if (InnerAllocHelper.IsWithin(length, itemsLength) is not true) + if (InnerAllocHelper.IsWithinLength(length, itemsLength) is not true) { throw InnerExceptionFactory.StartSegmentIsNotWithinArray(lengthParamName, length, itemsLength); } diff --git a/src/flatcollections-array/FlatArray/FlatArray.T.Builder/FlatArray.Builder.AddRange.List.cs b/src/flatcollections-array/FlatArray/FlatArray.T.Builder/FlatArray.Builder.AddRange.List.cs new file mode 100644 index 00000000..1de73b7c --- /dev/null +++ b/src/flatcollections-array/FlatArray/FlatArray.T.Builder/FlatArray.Builder.AddRange.List.cs @@ -0,0 +1,54 @@ +using System.Collections.Generic; +using System.Diagnostics; +using System.Diagnostics.CodeAnalysis; +using System.Runtime.CompilerServices; + +namespace System; + +partial struct FlatArray +{ + partial class Builder + { + // TODO: Add the tests and make public + internal Builder AddRange([AllowNull] List items) + { + if (items is null || items.Count == default) + { + return this; + } + + InnerAddRange(items, items.Count); + return this; + } + + // TODO: Add the tests and make public + internal Builder AddRange([AllowNull] List items, int length) + { + var itemsLength = items?.Count ?? default; + + if (InnerAllocHelper.IsWithinLength(length, itemsLength) is not true) + { + throw InnerExceptionFactory.StartSegmentIsNotWithinArray(nameof(length), length, itemsLength); + } + + if (items is null || items.Count == default) + { + return this; + } + + InnerAddRange(items, length); + return this; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private void InnerAddRange(List items, int length) + { + Debug.Assert(items.Count != default); + Debug.Assert(length > 0 && length <= items.Count); + + InnerBufferHelperEx.EnsureBufferCapacity(ref this.items, this.length, length); + items.CopyTo(0, this.items, this.length, length); + this.length += length; + } + } +} diff --git a/src/flatcollections-array/FlatArray/FlatArray.T.Builder/FlatArray.Builder.Capacity.cs b/src/flatcollections-array/FlatArray/FlatArray.T.Builder/FlatArray.Builder.Capacity.cs index 25145c5f..7ef67e57 100644 --- a/src/flatcollections-array/FlatArray/FlatArray.T.Builder/FlatArray.Builder.Capacity.cs +++ b/src/flatcollections-array/FlatArray/FlatArray.T.Builder/FlatArray.Builder.Capacity.cs @@ -11,7 +11,7 @@ internal int Capacity set { - if (InnerAllocHelper.IsWithin(length, value) is not true) + if (value >= length is not true) { throw InnerBuilderExceptionFactory.CapacityOutOfRange_MustBeGreaterThanOrEqualToLength(value, length); } diff --git a/src/flatcollections-array/FlatArray/FlatArray.T.Builder/InnerBufferHelper/FlatArray.Builder.InnerBufferHelperEx.cs b/src/flatcollections-array/FlatArray/FlatArray.T.Builder/InnerBufferHelper/FlatArray.Builder.InnerBufferHelperEx.cs index 9dd43814..8270fb5c 100644 --- a/src/flatcollections-array/FlatArray/FlatArray.T.Builder/InnerBufferHelper/FlatArray.Builder.InnerBufferHelperEx.cs +++ b/src/flatcollections-array/FlatArray/FlatArray.T.Builder/InnerBufferHelper/FlatArray.Builder.InnerBufferHelperEx.cs @@ -9,7 +9,6 @@ partial class Builder { private static class InnerBufferHelperEx { - // The caller MUST ensure the length and the length increase are GREATER than zero [MethodImpl(MethodImplOptions.AggressiveInlining)] internal static void EnsureBufferCapacity( ref T[] array, @@ -20,8 +19,8 @@ internal static void EnsureBufferCapacity( Debug.Assert(lengthIncrease >= 0); int newLength = unchecked(length + lengthIncrease); - int doubleLength = length << 1; // unchecked(length * 2); - int newCapacity = unchecked((uint)newLength) > unchecked((uint)doubleLength) + int doubleLength = InnerAllocHelper.DoubleUnchecked(length); + int newCapacity = InnerAllocHelper.IsWithinCapacityUnchecked(doubleLength, newLength) ? newLength : doubleLength; diff --git a/src/flatcollections-array/FlatArray/FlatArray.T/FlatArray.Factory.Explicit.From.Array.cs b/src/flatcollections-array/FlatArray/FlatArray.T/FlatArray.Factory.Explicit.From.Array.cs index 34a2920d..b27be4cd 100644 --- a/src/flatcollections-array/FlatArray/FlatArray.T/FlatArray.Factory.Explicit.From.Array.cs +++ b/src/flatcollections-array/FlatArray/FlatArray.T/FlatArray.Factory.Explicit.From.Array.cs @@ -17,7 +17,7 @@ internal static FlatArray InternalFromArrayChecked([AllowNull] T[] source, in { var sourceLength = source?.Length ?? default; - if (InnerAllocHelper.IsSegmentWithin(start, length, sourceLength) is not true) + if (InnerAllocHelper.IsSegmentWithinLength(start, length, sourceLength) is not true) { throw InnerExceptionFactory.SegmentIsNotWithinArray(start, length, sourceLength); } diff --git a/src/flatcollections-array/FlatArray/FlatArray.T/FlatArray.Factory.Explicit.From.FlatArray.cs b/src/flatcollections-array/FlatArray/FlatArray.T/FlatArray.Factory.Explicit.From.FlatArray.cs index 9e3b16a1..2aabe9c9 100644 --- a/src/flatcollections-array/FlatArray/FlatArray.T/FlatArray.Factory.Explicit.From.FlatArray.cs +++ b/src/flatcollections-array/FlatArray/FlatArray.T/FlatArray.Factory.Explicit.From.FlatArray.cs @@ -22,7 +22,7 @@ internal static FlatArray From(FlatArray? source, int start, int length) internal static FlatArray InternalFromFlatArrayChecked(FlatArray source, int start, int length) { - if (InnerAllocHelper.IsSegmentWithin(start, length, source.length) is not true) + if (InnerAllocHelper.IsSegmentWithinLength(start, length, source.length) is not true) { throw InnerExceptionFactory.SegmentIsNotWithinArray(start, length, source.length); } diff --git a/src/flatcollections-array/FlatArray/FlatArray.T/FlatArray.Factory.Explicit.From.ImmutableArray.cs b/src/flatcollections-array/FlatArray/FlatArray.T/FlatArray.Factory.Explicit.From.ImmutableArray.cs index 0e4a2b2e..edfa7d78 100644 --- a/src/flatcollections-array/FlatArray/FlatArray.T/FlatArray.Factory.Explicit.From.ImmutableArray.cs +++ b/src/flatcollections-array/FlatArray/FlatArray.T/FlatArray.Factory.Explicit.From.ImmutableArray.cs @@ -26,7 +26,7 @@ internal static FlatArray InternalFromImmutableArrayChecked(ImmutableArray { var sourceLength = source.IsDefault ? default : source.Length; - if (InnerAllocHelper.IsSegmentWithin(start, length, sourceLength) is not true) + if (InnerAllocHelper.IsSegmentWithinLength(start, length, sourceLength) is not true) { throw InnerExceptionFactory.SegmentIsNotWithinArray(start, length, sourceLength); } diff --git a/src/flatcollections-array/FlatArray/FlatArray.T/FlatArray.Factory.Explicit.From.List.cs b/src/flatcollections-array/FlatArray/FlatArray.T/FlatArray.Factory.Explicit.From.List.cs index 9c19d19b..4907e36b 100644 --- a/src/flatcollections-array/FlatArray/FlatArray.T/FlatArray.Factory.Explicit.From.List.cs +++ b/src/flatcollections-array/FlatArray/FlatArray.T/FlatArray.Factory.Explicit.From.List.cs @@ -18,7 +18,7 @@ internal static FlatArray InternalFromListChecked([AllowNull] List source, { var sourceLength = source?.Count ?? default; - if (InnerAllocHelper.IsSegmentWithin(start, length, sourceLength) is not true) + if (InnerAllocHelper.IsSegmentWithinLength(start, length, sourceLength) is not true) { throw InnerExceptionFactory.SegmentIsNotWithinArray(start, length, sourceLength); } diff --git a/src/flatcollections-array/FlatArray/FlatArray.T/InnerAllocHelper/FlatArray.InnerAllocHelper.cs b/src/flatcollections-array/FlatArray/FlatArray.T/InnerAllocHelper/FlatArray.InnerAllocHelper.cs index b4491b95..0870ff05 100644 --- a/src/flatcollections-array/FlatArray/FlatArray.T/InnerAllocHelper/FlatArray.InnerAllocHelper.cs +++ b/src/flatcollections-array/FlatArray/FlatArray.T/InnerAllocHelper/FlatArray.InnerAllocHelper.cs @@ -9,7 +9,6 @@ private static class InnerAllocHelper { internal const int DefaultPositiveCapacity = 4; - // The caller MUST ensure the length is GREATER than or EQUAL to zero [MethodImpl(MethodImplOptions.AggressiveInlining)] internal static bool IsIndexInRange(int index, int length) { @@ -19,56 +18,75 @@ internal static bool IsIndexInRange(int index, int length) } [MethodImpl(MethodImplOptions.AggressiveInlining)] - internal static bool IsWithin(int value, int threshold) - => - unchecked((uint)value) <= unchecked((uint)threshold); + internal static bool IsWithinLength(int value, int length) + { + Debug.Assert(value >= 0); + Debug.Assert(length >= 0); + + return InnerIsWithinUnchecked(value, length); + } [MethodImpl(MethodImplOptions.AggressiveInlining)] - internal static bool IsSegmentWithin(int start, int length, int threshold) + internal static bool IsSegmentWithinLength(int segmentStart, int segmentLength, int length) + { + Debug.Assert(segmentStart >= 0); + Debug.Assert(segmentLength >= 0); + Debug.Assert(length >= 0); + + return (ulong)unchecked((uint)segmentStart) + unchecked((uint)segmentLength) <= unchecked((uint)length); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + internal static bool IsWithinCapacityUnchecked(int value, int capacity) => - (ulong)unchecked((uint)start) + unchecked((uint)length) <= unchecked((uint)threshold); + InnerIsWithinUnchecked(value, capacity); [MethodImpl(MethodImplOptions.AggressiveInlining)] internal static int EnsurePositiveCapacity(int capacity) - => - capacity > 0 ? capacity : DefaultPositiveCapacity; + { + Debug.Assert(capacity >= 0); + + return capacity > 0 ? capacity : DefaultPositiveCapacity; + } - // The caller MUST ensure the capacity is GREATER than or EQUAL to zero internal static int EnsureCapacityWithinDefaultPositive(int capacity) { Debug.Assert(capacity >= 0); - return IsWithin(capacity, DefaultPositiveCapacity) ? capacity : DefaultPositiveCapacity; + return InnerIsWithinUnchecked(capacity, DefaultPositiveCapacity) ? capacity : DefaultPositiveCapacity; } - // The caller MUST ensure the capacity is GREATER than zero and LESS than the max capacity [MethodImpl(MethodImplOptions.AggressiveInlining)] internal static int EnlargeCapacity(int capacity, int maxCapacity) { Debug.Assert(capacity > 0 && capacity < maxCapacity); - int newCapacity = InnerDoubleUnchecked(capacity); - return IsWithin(newCapacity, maxCapacity) ? newCapacity : maxCapacity; + int newCapacity = DoubleUnchecked(capacity); + return InnerIsWithinUnchecked(newCapacity, maxCapacity) ? newCapacity : maxCapacity; } - // The caller MUST ensure the length is GREATER than zero and LESS than or EQUAL to the capacity [MethodImpl(MethodImplOptions.AggressiveInlining)] internal static bool IsHugeCapacity(int length, int capacity) { Debug.Assert(length > 0 && length <= capacity); - if (IsWithin(capacity, DefaultPositiveCapacity)) + if (InnerIsWithinUnchecked(capacity, DefaultPositiveCapacity)) { return false; } - int doubleLength = InnerDoubleUnchecked(length); - return IsWithin(doubleLength, capacity); + int doubleLength = DoubleUnchecked(length); + return InnerIsWithinUnchecked(doubleLength, capacity); } [MethodImpl(MethodImplOptions.AggressiveInlining)] - private static int InnerDoubleUnchecked(int value) + internal static int DoubleUnchecked(int value) => value << 1; // unchecked(value * 2); + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static bool InnerIsWithinUnchecked(int value, int threshold) + => + unchecked((uint)value) <= unchecked((uint)threshold); } } diff --git a/src/flatcollections-array/FlatArray/FlatArray.T/InnerArrayHelper/FlatArray.InnerArrayHelper.cs b/src/flatcollections-array/FlatArray/FlatArray.T/InnerArrayHelper/FlatArray.InnerArrayHelper.cs index 8262094e..acceed9e 100644 --- a/src/flatcollections-array/FlatArray/FlatArray.T/InnerArrayHelper/FlatArray.InnerArrayHelper.cs +++ b/src/flatcollections-array/FlatArray/FlatArray.T/InnerArrayHelper/FlatArray.InnerArrayHelper.cs @@ -12,7 +12,6 @@ internal static T[] Copy(T[] array) => new ReadOnlySpan(array).ToArray(); - // The caller MUST ensure the length is within the array length [MethodImpl(MethodImplOptions.AggressiveInlining)] internal static T[] Copy(T[] array, int length) { @@ -24,11 +23,10 @@ internal static T[] Copy(T[] array, int length) return sourceSpan.ToArray(); } - // The caller MUST ensure the segment is within the array [MethodImpl(MethodImplOptions.AggressiveInlining)] internal static T[] CopySegment(T[] array, int start, int length) { - Debug.Assert(InnerAllocHelper.IsSegmentWithin(start, length, array.Length)); + Debug.Assert(InnerAllocHelper.IsSegmentWithinLength(start, length, array.Length)); var sourceSpan = start == default && length == array.Length ? new ReadOnlySpan(array) @@ -36,7 +34,6 @@ internal static T[] CopySegment(T[] array, int start, int length) return sourceSpan.ToArray(); } - // The caller MUST ensure the lengths are within the arrays actual lengths [MethodImpl(MethodImplOptions.AggressiveInlining)] internal static T[] Concat(T[] array1, int length1, T[] array2, int length2) { diff --git a/src/flatcollections-array/FlatArray/FlatArray.T/InnerFactory/FlatArray.InnerFactory.FromArray.cs b/src/flatcollections-array/FlatArray/FlatArray.T/InnerFactory/FlatArray.InnerFactory.FromArray.cs index 633583a3..bc450f5a 100644 --- a/src/flatcollections-array/FlatArray/FlatArray.T/InnerFactory/FlatArray.InnerFactory.FromArray.cs +++ b/src/flatcollections-array/FlatArray/FlatArray.T/InnerFactory/FlatArray.InnerFactory.FromArray.cs @@ -15,7 +15,7 @@ internal static FlatArray FromArray(T[] source) [MethodImpl(MethodImplOptions.AggressiveInlining)] internal static FlatArray FromArray(T[] source, int start, int length) { - Debug.Assert(InnerAllocHelper.IsSegmentWithin(start, length, source.Length)); + Debug.Assert(InnerAllocHelper.IsSegmentWithinLength(start, length, source.Length)); return length == default ? default : new(InnerArrayHelper.CopySegment(source, start, length), default); } diff --git a/src/flatcollections-array/FlatArray/FlatArray.T/InnerFactory/FlatArray.InnerFactory.FromFlatArray.cs b/src/flatcollections-array/FlatArray/FlatArray.T/InnerFactory/FlatArray.InnerFactory.FromFlatArray.cs index d5ae367b..b0bbf75e 100644 --- a/src/flatcollections-array/FlatArray/FlatArray.T/InnerFactory/FlatArray.InnerFactory.FromFlatArray.cs +++ b/src/flatcollections-array/FlatArray/FlatArray.T/InnerFactory/FlatArray.InnerFactory.FromFlatArray.cs @@ -15,7 +15,7 @@ internal static FlatArray FromFlatArray(FlatArray source) [MethodImpl(MethodImplOptions.AggressiveInlining)] internal static FlatArray FromFlatArray(FlatArray source, int start, int length) { - Debug.Assert(InnerAllocHelper.IsSegmentWithin(start, length, source.length)); + Debug.Assert(InnerAllocHelper.IsSegmentWithinLength(start, length, source.length)); return length == default ? default : new(InnerArrayHelper.CopySegment(source.items!, start, length), default); } diff --git a/src/flatcollections-array/FlatArray/FlatArray.T/InnerFactory/FlatArray.InnerFactory.FromImmutableArray.cs b/src/flatcollections-array/FlatArray/FlatArray.T/InnerFactory/FlatArray.InnerFactory.FromImmutableArray.cs index 857cddaf..955f11c1 100644 --- a/src/flatcollections-array/FlatArray/FlatArray.T/InnerFactory/FlatArray.InnerFactory.FromImmutableArray.cs +++ b/src/flatcollections-array/FlatArray/FlatArray.T/InnerFactory/FlatArray.InnerFactory.FromImmutableArray.cs @@ -25,9 +25,9 @@ internal static FlatArray FromImmutableArray(ImmutableArray source) [MethodImpl(MethodImplOptions.AggressiveInlining)] internal static FlatArray FromImmutableArray(ImmutableArray source, int start, int length) { - Debug.Assert(InnerAllocHelper.IsSegmentWithin(start, length, source.IsDefault ? default : source.Length)); + Debug.Assert(InnerAllocHelper.IsSegmentWithinLength(start, length, source.IsDefault ? default : source.Length)); - if (source.IsDefaultOrEmpty) + if (length == default) { return default; } diff --git a/src/flatcollections-array/FlatArray/FlatArray.T/InnerFactory/FlatArray.InnerFactory.FromList.cs b/src/flatcollections-array/FlatArray/FlatArray.T/InnerFactory/FlatArray.InnerFactory.FromList.cs index 2c7be8c5..de809d1c 100644 --- a/src/flatcollections-array/FlatArray/FlatArray.T/InnerFactory/FlatArray.InnerFactory.FromList.cs +++ b/src/flatcollections-array/FlatArray/FlatArray.T/InnerFactory/FlatArray.InnerFactory.FromList.cs @@ -26,7 +26,7 @@ internal static FlatArray FromList(List source) [MethodImpl(MethodImplOptions.AggressiveInlining)] internal static FlatArray FromList(List source, int start, int length) { - Debug.Assert(InnerAllocHelper.IsSegmentWithin(start, length, source.Count)); + Debug.Assert(InnerAllocHelper.IsSegmentWithinLength(start, length, source.Count)); if (length == default) { diff --git a/src/flatcollections-array/FlatArray/FlatArray.csproj b/src/flatcollections-array/FlatArray/FlatArray.csproj index f64598cb..2d413fd8 100644 --- a/src/flatcollections-array/FlatArray/FlatArray.csproj +++ b/src/flatcollections-array/FlatArray/FlatArray.csproj @@ -17,7 +17,7 @@ PrimeFuncPack Core.FlatArray is a core library for .NET consisting of immutable FlatArray targeted for use in functional programming. System PrimeFuncPack.Core.FlatArray - 1.2.0-rc.1 + 1.2.0-rc.2 diff --git a/src/flatcollections/FlatCollections/FlatCollections.csproj b/src/flatcollections/FlatCollections/FlatCollections.csproj index fca6db0d..18208b03 100644 --- a/src/flatcollections/FlatCollections/FlatCollections.csproj +++ b/src/flatcollections/FlatCollections/FlatCollections.csproj @@ -17,7 +17,7 @@ PrimeFuncPack Core.FlatCollections is a set of immutable Flat collections for .NET designed for developing business applications based on functional programming. System PrimeFuncPack.Core.FlatCollections - 1.2.0-rc.1 + 1.2.0-rc.2 @@ -32,7 +32,7 @@ - +