diff --git a/src/flatcollections-array/FlatArray.Tests/FlatArray.Tests.csproj b/src/flatcollections-array/FlatArray.Tests/FlatArray.Tests.csproj index ef0f4e57..20fd0460 100644 --- a/src/flatcollections-array/FlatArray.Tests/FlatArray.Tests.csproj +++ b/src/flatcollections-array/FlatArray.Tests/FlatArray.Tests.csproj @@ -14,14 +14,14 @@ - + - - + + runtime; build; native; contentfiles; analyzers; buildtransitive all - + runtime; build; native; contentfiles; analyzers; buildtransitive all diff --git a/src/flatcollections-array/FlatArray.Tests/Internal.Helper/FlatArray/FlatArray.Verify.cs b/src/flatcollections-array/FlatArray.Tests/Internal.Helper/FlatArray/FlatArray.Verify.cs index 023fcdd3..4baebeb5 100644 --- a/src/flatcollections-array/FlatArray.Tests/Internal.Helper/FlatArray/FlatArray.Verify.cs +++ b/src/flatcollections-array/FlatArray.Tests/Internal.Helper/FlatArray/FlatArray.Verify.cs @@ -22,4 +22,22 @@ internal static void VerifyInnerState_TheSameAssert(this FlatArray actual, var actualItems = actual.GetFieldValue("items"); Assert.Same(expectedItems, actualItems); } + + internal static void VerifyTruncatedState(this FlatArray actual, params T[] expectedItems) + { + var actualLength = actual.GetStructFieldValue("length"); + Assert.StrictEqual(expectedItems.Length, actualLength); + + var actualItems = actual.GetFieldValue("items"); + if (actualItems is null || actualItems.Length == actualLength) + { + Assert.Equal(expectedItems, actualItems); + return; + } + + var truncatedItems = new T[actualLength]; + Array.Copy(actualItems, truncatedItems, actualLength); + + Assert.Equal(expectedItems, truncatedItems); + } } \ No newline at end of file diff --git a/src/flatcollections-array/FlatArray.Tests/Tests.FlatArray.T/Functional/Concat.Array.cs b/src/flatcollections-array/FlatArray.Tests/Tests.FlatArray.T/Functional/Concat.Array.cs new file mode 100644 index 00000000..ea97defb --- /dev/null +++ b/src/flatcollections-array/FlatArray.Tests/Tests.FlatArray.T/Functional/Concat.Array.cs @@ -0,0 +1,111 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using PrimeFuncPack.UnitTest; +using Xunit; +using static PrimeFuncPack.UnitTest.TestData; + +namespace PrimeFuncPack.Core.Tests; + +partial class FlatArrayTest +{ + [Fact] + public static void ConcatWithArray_SourceIsEmptyAndOtherIsNull_ExpectEmpty() + { + var source = default(FlatArray); + var other = (decimal?[]?)null; + + var actual = source.Concat(other); + + actual.VerifyInnerState(default, default); + } + + [Fact] + public static void ConcatWithArray_SourceAndOtherAreEmpty_ExpectEmpty() + { + var source = default(FlatArray); + var other = Array.Empty(); + + var actual = source.Concat(other); + + actual.VerifyInnerState(default, default); + } + + [Fact] + public static void ConcatWithArray_SourceIsEmptyAndOtherIsNotEmpty_ExpectOther() + { + var source = default(FlatArray); + var other = new[] { MinusFifteenIdNullNameRecord, PlusFifteenIdLowerSomeStringNameRecord }; + + var actual = source.Concat(other); + var expectedItems = new[] { MinusFifteenIdNullNameRecord, PlusFifteenIdLowerSomeStringNameRecord }; + + actual.VerifyTruncatedState(expectedItems); + } + + [Fact] + public static void ConcatWithArray_OtherIsNullAndSourceIsNotEmpty_ExpectSource() + { + var source = new[] { AnotherString, UpperSomeString, WhiteSpaceString, null }.InitializeFlatArray(2); + var other = (string?[]?)null; + + var actual = source.Concat(other); + var expectedItems = new[] { AnotherString, UpperSomeString }; + + actual.VerifyTruncatedState(expectedItems); + } + + [Fact] + public static void ConcatWithArray_OtherIsEmptyAndSourceIsNotEmpty_ExpectSource() + { + var source = new RecordStruct?[] + { + SomeTextRecordStruct, + AnotherTextRecordStruct, + null, + UpperAnotherTextRecordStruct + } + .InitializeFlatArray(3); + + var other = Array.Empty(); + + var actual = source.Concat(other); + + var expectedItems = new RecordStruct?[] + { + SomeTextRecordStruct, + AnotherTextRecordStruct, + null + }; + + actual.VerifyTruncatedState(expectedItems); + } + + [Fact] + public static void ConcatWithArray_SourceAndOtherAreNotEmpty_ExpectMergedArray() + { + var source = new int?[] + { + MinusFifteen, + Zero, + null, + int.MaxValue + } + .InitializeFlatArray(3); + + var actual = source.Concat(PlusFifteen, null, One, int.MinValue); + + var expectedItems = new int?[] + { + MinusFifteen, + Zero, + null, + PlusFifteen, + null, + One, + int.MinValue + }; + + actual.VerifyTruncatedState(expectedItems); + } +} \ No newline at end of file diff --git a/src/flatcollections-array/FlatArray.Tests/Tests.FlatArray.T/Functional/Concat.cs b/src/flatcollections-array/FlatArray.Tests/Tests.FlatArray.T/Functional/Concat.cs new file mode 100644 index 00000000..efbe26d8 --- /dev/null +++ b/src/flatcollections-array/FlatArray.Tests/Tests.FlatArray.T/Functional/Concat.cs @@ -0,0 +1,79 @@ +using System; +using PrimeFuncPack.UnitTest; +using Xunit; +using static PrimeFuncPack.UnitTest.TestData; + +namespace PrimeFuncPack.Core.Tests; + +partial class FlatArrayTest +{ + [Fact] + public static void Concat_SourceAndOtherAreEmpty_ExpectEmpty() + { + var source = default(FlatArray); + var other = default(FlatArray); + + var actual = source.Concat(other); + + actual.VerifyInnerState(default, default); + } + + [Fact] + public static void Concat_SourceIsEmptyAndOtherIsNotEmpty_ExpectOther() + { + var source = default(FlatArray); + var other = new int?[] { null, PlusFifteen, Zero, One }.InitializeFlatArray(3); + + var actual = source.Concat(other); + var expectedItems = new int?[] { null, PlusFifteen, Zero }; + + actual.VerifyTruncatedState(expectedItems); + } + + [Fact] + public static void Concat_OtherIsEmptyAndSourceIsNotEmpty_ExpectSource() + { + var source = new[] { SomeString, null, AnotherString }.InitializeFlatArray(2); + var other = default(FlatArray); + + var actual = source.Concat(other); + var expectedItems = new[] { SomeString, null }; + + actual.VerifyTruncatedState(expectedItems); + } + + [Fact] + public static void Concat_SourceAndOtherAreNotEmpty_ExpectMergedArray() + { + var source = new[] + { + null, + MinusFifteenIdNullNameRecord, + ZeroIdNullNameRecord + } + .InitializeFlatArray(2); + + var other = new[] + { + PlusFifteenIdLowerSomeStringNameRecord, + MinusFifteenIdSomeStringNameRecord, + PlusFifteenIdSomeStringNameRecord, + MinusFifteenIdNullNameRecord, + null + } + .InitializeFlatArray(3); + + var actual = source.Concat(other); + + var expectedItems = new[] + { + null, + MinusFifteenIdNullNameRecord, + PlusFifteenIdLowerSomeStringNameRecord, + MinusFifteenIdSomeStringNameRecord, + PlusFifteenIdSomeStringNameRecord + }; + + actual.VerifyTruncatedState(expectedItems); + } +} \ No newline at end of file diff --git a/src/flatcollections-array/FlatArray.Tests/Tests.FlatArray.T/Functional/Filter.Index.cs b/src/flatcollections-array/FlatArray.Tests/Tests.FlatArray.T/Functional/Filter.Index.cs new file mode 100644 index 00000000..4dcd52aa --- /dev/null +++ b/src/flatcollections-array/FlatArray.Tests/Tests.FlatArray.T/Functional/Filter.Index.cs @@ -0,0 +1,84 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using PrimeFuncPack.UnitTest; +using Xunit; +using static PrimeFuncPack.UnitTest.TestData; + +namespace PrimeFuncPack.Core.Tests; + +partial class FlatArrayTest +{ + [Theory] + [InlineData(true)] + [InlineData(false)] + public static void FilterWithIndex_PredicateIsNull_ExpectArgumentNullException( + bool isSourceDefault) + { + var source = isSourceDefault ? default : new[] { MinusFifteenIdRefType }.InitializeFlatArray(); + Func predicate = null!; + + var ex = Assert.Throws(Test); + Assert.Equal("predicate", ex.ParamName); + + void Test() + => + _ = source.Filter(predicate); + } + + [Fact] + public static void FilterWithIndex_SourceIsEmpty_ExpectDefault() + { + var source = default(FlatArray); + + var actual = source.Filter(Predicate); + + actual.VerifyInnerState(default, default); + + static bool Predicate(StructType? item, int _) + => + true; + } + + [Fact] + public static void FilterWithIndex_SourceIsNotEmptyAndAllPredicatesReturnFalse_ExpectDefault() + { + var source = new decimal?[] { decimal.One, null, decimal.MaxValue }.InitializeFlatArray(); + + var actual = source.Filter(Predicate); + + actual.VerifyInnerState(default, default); + + static bool Predicate(decimal? item, int _) + => + false; + } + + [Fact] + public static void FilterWithIndex_SourceIsNotEmptyAndNotAllPredicatesReturnFalse_ExpectFilteredValues() + { + var mapper = new Dictionary + { + { EmptyString, true }, + { SomeString, false }, + { UpperAnotherString, true }, + { WhiteSpaceString, true }, + { AnotherString, false }, + { TabString, true } + }; + + var sourceItems = new[] { EmptyString, SomeString, UpperAnotherString, WhiteSpaceString, AnotherString }; + var source = mapper.Keys.ToArray().InitializeFlatArray(sourceItems.Length); + + var actual = source.Filter(Predicate); + var expectedItems = new[] { EmptyString, UpperAnotherString, WhiteSpaceString }; + + actual.VerifyTruncatedState(expectedItems); + + bool Predicate(string item, int index) + { + Assert.Equal(sourceItems[index], item); + return mapper[item]; + } + } +} \ No newline at end of file diff --git a/src/flatcollections-array/FlatArray.Tests/Tests.FlatArray.T/Functional/Filter.cs b/src/flatcollections-array/FlatArray.Tests/Tests.FlatArray.T/Functional/Filter.cs new file mode 100644 index 00000000..a98dfe5b --- /dev/null +++ b/src/flatcollections-array/FlatArray.Tests/Tests.FlatArray.T/Functional/Filter.cs @@ -0,0 +1,80 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using PrimeFuncPack.UnitTest; +using Xunit; +using static PrimeFuncPack.UnitTest.TestData; + +namespace PrimeFuncPack.Core.Tests; + +partial class FlatArrayTest +{ + [Theory] + [InlineData(true)] + [InlineData(false)] + public static void Filter_PredicateIsNull_ExpectArgumentNullException( + bool isSourceDefault) + { + var source = isSourceDefault ? default : new[] { SomeString, LowerSomeString }.InitializeFlatArray(); + Func predicate = null!; + + var ex = Assert.Throws(Test); + Assert.Equal("predicate", ex.ParamName); + + void Test() + => + _ = source.Filter(predicate); + } + + [Fact] + public static void Filter_SourceIsEmpty_ExpectDefault() + { + var source = default(FlatArray); + + var actual = source.Filter(Predicate); + + actual.VerifyInnerState(default, default); + + static bool Predicate(RecordType _) + => + true; + } + + [Fact] + public static void Filter_SourceIsNotEmptyAndAllPredicatesReturnFalse_ExpectDefault() + { + var source = new[] { MinusFifteenIdRefType, ZeroIdRefType }.InitializeFlatArray(); + + var actual = source.Filter(Predicate); + + actual.VerifyInnerState(default, default); + + static bool Predicate(RefType _) + => + false; + } + + [Fact] + public static void Filter_SourceIsNotEmptyAndNotAllPredicatesReturnFalse_ExpectFilteredValues() + { + var mapper = new Dictionary + { + { MinusFifteen, false }, + { Zero, true }, + { MinusOne, true }, + { One, false }, + { PlusFifteen, true } + }; + + var source = mapper.Keys.ToArray().InitializeFlatArray(4); + + var actual = source.Filter(Predicate); + var expectedItems = new[] { Zero, MinusOne }; + + actual.VerifyTruncatedState(expectedItems); + + bool Predicate(int item) + => + mapper[item]; + } +} \ No newline at end of file diff --git a/src/flatcollections-array/FlatArray.Tests/Tests.FlatArray.T/Functional/FlatMap.Index.cs b/src/flatcollections-array/FlatArray.Tests/Tests.FlatArray.T/Functional/FlatMap.Index.cs new file mode 100644 index 00000000..7de4422a --- /dev/null +++ b/src/flatcollections-array/FlatArray.Tests/Tests.FlatArray.T/Functional/FlatMap.Index.cs @@ -0,0 +1,83 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using PrimeFuncPack.UnitTest; +using Xunit; +using static PrimeFuncPack.UnitTest.TestData; + +namespace PrimeFuncPack.Core.Tests; + +partial class FlatArrayTest +{ + [Theory] + [InlineData(true)] + [InlineData(false)] + public static void FlatMapWithIndex_MapArgumentIsNull_ExpectArgumentNullException( + bool isSourceDefault) + { + var source = isSourceDefault ? default : new[] { long.MinValue, long.MaxValue }.InitializeFlatArray(); + Func> map = null!; + + var ex = Assert.Throws(Test); + Assert.Equal("map", ex.ParamName); + + void Test() + => + _ = source.FlatMap(map); + } + + [Fact] + public static void FlatMapWithIndex_SourceIsDefault_ExpectDefault() + { + var source = default(FlatArray); + + var actual = source.FlatMap(Map); + + actual.VerifyInnerState(default, default); + + static FlatArray Map(StructType _, int index) + => + new(null, SomeTextRecordStruct, AnotherTextRecordStruct); + } + + [Fact] + public static void FlatMapWithIndex_SourceIsNotDefaultAndAllMapResultAreDefault_ExpectDefault() + { + var source = new[] { EmptyString, SomeString, WhiteSpaceString }.InitializeFlatArray(); + + var actual = source.FlatMap(Map); + + actual.VerifyInnerState(default, default); + + static FlatArray Map(string sourceValue, int index) + => + default; + } + + [Fact] + public static void FlatMapWithIndex_SourceIsNotDefault_ExpectMappedValues() + { + var mapper = new Dictionary> + { + [SomeString] = default, + [AnotherString] = new decimal?[] { decimal.MinusOne, null, decimal.MaxValue }.InitializeFlatArray(2), + [WhiteSpaceString] = new decimal?[] { null }.InitializeFlatArray(), + [UpperSomeString] = new decimal?[] { decimal.One }.InitializeFlatArray(), + [LowerSomeString] = new decimal?[] { decimal.MinusOne }.InitializeFlatArray() + }; + + var sourceItems = new[] { SomeString, AnotherString, WhiteSpaceString, UpperSomeString }; + var source = mapper.Keys.ToArray().InitializeFlatArray(sourceItems.Length); + + var actual = source.FlatMap(Map); + var expectedItems = new decimal?[] { decimal.MinusOne, null, null, decimal.One }; + + actual.VerifyTruncatedState(expectedItems); + + FlatArray Map(string sourceValue, int index) + { + Assert.Equal(sourceItems[index], sourceValue); + return mapper[sourceValue]; + } + } +} \ No newline at end of file diff --git a/src/flatcollections-array/FlatArray.Tests/Tests.FlatArray.T/Functional/FlatMap.cs b/src/flatcollections-array/FlatArray.Tests/Tests.FlatArray.T/Functional/FlatMap.cs new file mode 100644 index 00000000..135f227b --- /dev/null +++ b/src/flatcollections-array/FlatArray.Tests/Tests.FlatArray.T/Functional/FlatMap.cs @@ -0,0 +1,79 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using PrimeFuncPack.UnitTest; +using Xunit; +using static PrimeFuncPack.UnitTest.TestData; + +namespace PrimeFuncPack.Core.Tests; + +partial class FlatArrayTest +{ + [Theory] + [InlineData(true)] + [InlineData(false)] + public static void FlatMap_MapArgumentIsNull_ExpectArgumentNullException( + bool isSourceDefault) + { + var source = isSourceDefault ? default : new[] { MinusFifteenIdRefType, ZeroIdRefType }.InitializeFlatArray(); + Func> map = null!; + + var ex = Assert.Throws(Test); + Assert.Equal("map", ex.ParamName); + + void Test() + => + _ = source.FlatMap(map); + } + + [Fact] + public static void FlatMap_SourceIsDefault_ExpectDefault() + { + var source = default(FlatArray); + + var actual = source.FlatMap(Map); + + actual.VerifyInnerState(default, default); + + static FlatArray Map(RecordStruct? _) + => + new(SomeString, AnotherString); + } + + [Fact] + public static void FlatMap_SourceIsNotDefaultAndAllMapResultAreDefault_ExpectDefault() + { + var source = new[] { SomeTextStructType, LowerSomeTextStructType }.InitializeFlatArray(); + + var actual = source.FlatMap(Map); + + actual.VerifyInnerState(default, default); + + static FlatArray Map(StructType sourceValue) + => + default; + } + + [Fact] + public static void FlatMap_SourceIsNotDefault_ExpectMappedValues() + { + var mapper = new Dictionary> + { + [MinusFifteen] = new RecordType?[] { MinusFifteenIdSomeStringNameRecord }.InitializeFlatArray(), + [One] = default, + [int.MaxValue] = new RecordType?[] { PlusFifteenIdSomeStringNameRecord, null, ZeroIdNullNameRecord }.InitializeFlatArray(2), + [PlusFifteen] = new RecordType?[] { MinusFifteenIdNullNameRecord }.InitializeFlatArray() + }; + + var source = mapper.Keys.ToArray().InitializeFlatArray(3); + + var actual = source.FlatMap(Map); + var expectedItems = new RecordType?[] { MinusFifteenIdSomeStringNameRecord, PlusFifteenIdSomeStringNameRecord, null }; + + actual.VerifyTruncatedState(expectedItems); + + FlatArray Map(int sourceValue) + => + mapper[sourceValue]; + } +} \ No newline at end of file diff --git a/src/flatcollections-array/FlatArray.Tests/Tests.FlatArray.T/Functional/Map.Index.cs b/src/flatcollections-array/FlatArray.Tests/Tests.FlatArray.T/Functional/Map.Index.cs new file mode 100644 index 00000000..e2c6431c --- /dev/null +++ b/src/flatcollections-array/FlatArray.Tests/Tests.FlatArray.T/Functional/Map.Index.cs @@ -0,0 +1,67 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using PrimeFuncPack.UnitTest; +using Xunit; +using static PrimeFuncPack.UnitTest.TestData; + +namespace PrimeFuncPack.Core.Tests; + +partial class FlatArrayTest +{ + [Theory] + [InlineData(true)] + [InlineData(false)] + public static void MapWithIndex_MapArgumentIsNull_ExpectArgumentNullException( + bool isSourceDefault) + { + var source = isSourceDefault ? default : new RefType?[] { PlusFifteenIdRefType, MinusFifteenIdRefType }.InitializeFlatArray(); + Func map = null!; + + var ex = Assert.Throws(Test); + Assert.Equal("map", ex.ParamName); + + void Test() + => + _ = source.Map(map); + } + + [Fact] + public static void MapWithIndex_SourceIsDefault_ExpectDefault() + { + var source = default(FlatArray); + + var actual = source.Map(Map); + + actual.VerifyInnerState(default, default); + + static RecordType? Map(string _, int index) + => + ZeroIdNullNameRecord; + } + + [Fact] + public static void MapWithIndex_SourceIsNotDefault_ExpectMappedValues() + { + var mapper = new Dictionary + { + [MinusFifteenIdRefType] = SomeString, + [PlusFifteenIdRefType] = null, + [ZeroIdRefType] = AnotherString + }; + + var sourceItems = new[] { MinusFifteenIdRefType, PlusFifteenIdRefType }; + var source = mapper.Keys.ToArray().InitializeFlatArray(sourceItems.Length); + + var actual = source.Map(Map); + var expectedItems = new[] { SomeString, null }; + + actual.VerifyTruncatedState(expectedItems); + + string? Map(RefType sourceValue, int index) + { + Assert.Equal(sourceItems[index], sourceValue); + return mapper[sourceValue]; + } + } +} \ No newline at end of file diff --git a/src/flatcollections-array/FlatArray.Tests/Tests.FlatArray.T/Functional/Map.cs b/src/flatcollections-array/FlatArray.Tests/Tests.FlatArray.T/Functional/Map.cs new file mode 100644 index 00000000..337b8869 --- /dev/null +++ b/src/flatcollections-array/FlatArray.Tests/Tests.FlatArray.T/Functional/Map.cs @@ -0,0 +1,64 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using PrimeFuncPack.UnitTest; +using Xunit; +using static PrimeFuncPack.UnitTest.TestData; + +namespace PrimeFuncPack.Core.Tests; + +partial class FlatArrayTest +{ + [Theory] + [InlineData(true)] + [InlineData(false)] + public static void Map_MapArgumentIsNull_ExpectArgumentNullException( + bool isSourceDefault) + { + var source = isSourceDefault ? default : new[] { PlusFifteen, Zero, MinusOne }.InitializeFlatArray(); + Func map = null!; + + var ex = Assert.Throws(Test); + Assert.Equal("map", ex.ParamName); + + void Test() + => + _ = source.Map(map); + } + + [Fact] + public static void Map_SourceIsDefault_ExpectDefault() + { + var source = default(FlatArray); + + var actual = source.Map(Map); + + actual.VerifyInnerState(default, default); + + static RefType Map(RecordStruct _) + => + MinusFifteenIdRefType; + } + + [Fact] + public static void Map_SourceIsNotDefault_ExpectMappedValues() + { + var mapper = new Dictionary + { + [SomeString] = PlusFifteenIdLowerSomeStringNameRecord, + [AnotherString] = ZeroIdNullNameRecord, + [MixedWhiteSpacesString] = MinusFifteenIdSomeStringNameRecord + }; + + var source = mapper.Keys.ToArray().InitializeFlatArray(mapper.Keys.Count - 1); + + var actual = source.Map(Map); + var expectedItems = new[] { PlusFifteenIdLowerSomeStringNameRecord, ZeroIdNullNameRecord }; + + actual.VerifyTruncatedState(expectedItems); + + RecordType Map(string sourceValue) + => + mapper[sourceValue]; + } +} \ No newline at end of file diff --git a/src/flatcollections-array/FlatArray/FlatArray.T/FlatArray.Functional.Concat.cs b/src/flatcollections-array/FlatArray/FlatArray.T/FlatArray.Functional.Concat.cs new file mode 100644 index 00000000..b4b85120 --- /dev/null +++ b/src/flatcollections-array/FlatArray/FlatArray.T/FlatArray.Functional.Concat.cs @@ -0,0 +1,38 @@ +using System.Diagnostics.CodeAnalysis; + +namespace System; + +partial struct FlatArray +{ + public FlatArray Concat(FlatArray other) + { + if (other.length == default) + { + return this; + } + + if (length == default) + { + return other; + } + + var resultItems = InnerArrayHelper.Concat(items!, length, other.items!, other.length); + return new(resultItems, default); + } + + public FlatArray Concat([AllowNull] params T[] other) + { + if (other is null || other.Length == default) + { + return this; + } + + if (length == default) + { + return new(InnerArrayHelper.Clone(other), default); + } + + var resultItems = InnerArrayHelper.Concat(items!, length, other, other.Length); + return new(resultItems, default); + } +} \ No newline at end of file diff --git a/src/flatcollections-array/FlatArray/FlatArray.T/FlatArray.Functional.Filter.cs b/src/flatcollections-array/FlatArray/FlatArray.T/FlatArray.Functional.Filter.cs new file mode 100644 index 00000000..cd45639b --- /dev/null +++ b/src/flatcollections-array/FlatArray/FlatArray.T/FlatArray.Functional.Filter.cs @@ -0,0 +1,80 @@ +namespace System; + +partial struct FlatArray +{ + public FlatArray Filter(Func predicate) + { + _ = predicate ?? throw new ArgumentNullException(nameof(predicate)); + + if (length == default) + { + return default; + } + + var initialCapacity = length < InnerAllocHelper.DefaultPositiveCapacity ? length : InnerAllocHelper.DefaultPositiveCapacity; + + var resultItems = new T[initialCapacity]; + var resultLength = 0; + + InternalForEach( + item => + { + if (predicate.Invoke(item) is false) + { + return; + } + + if (resultLength == resultItems.Length) + { + InnerBufferHelper.EnlargeBuffer(ref resultItems); + } + + resultItems[resultLength++] = item; + }); + + if (resultLength == default) + { + return default; + } + + return new(resultLength, resultItems); + } + + public FlatArray Filter(Func predicate) + { + _ = predicate ?? throw new ArgumentNullException(nameof(predicate)); + + if (length == default) + { + return default; + } + + var initialCapacity = length < InnerAllocHelper.DefaultPositiveCapacity ? length : InnerAllocHelper.DefaultPositiveCapacity; + + var resultItems = new T[initialCapacity]; + var resultLength = 0; + + InternalForEach( + (i, item) => + { + if (predicate.Invoke(item, i) is false) + { + return; + } + + if (resultLength == resultItems.Length) + { + InnerBufferHelper.EnlargeBuffer(ref resultItems); + } + + resultItems[resultLength++] = item; + }); + + if (resultLength == default) + { + return default; + } + + return new(resultLength, resultItems); + } +} \ No newline at end of file diff --git a/src/flatcollections-array/FlatArray/FlatArray.T/FlatArray.Functional.FlatMap.cs b/src/flatcollections-array/FlatArray/FlatArray.T/FlatArray.Functional.FlatMap.cs new file mode 100644 index 00000000..b4c0e63e --- /dev/null +++ b/src/flatcollections-array/FlatArray/FlatArray.T/FlatArray.Functional.FlatMap.cs @@ -0,0 +1,60 @@ +using System.Collections.Generic; + +namespace System; + +partial struct FlatArray +{ + public FlatArray FlatMap(Func> map) + { + _ = map ?? throw new ArgumentNullException(nameof(map)); + + if (length == default) + { + return default; + } + + var resultList = new List(); + + InternalForEach( + item => + { + var resultArray = map.Invoke(item); + + if (resultArray.length == default) + { + return; + } + + resultList.AddRange(new ArraySegment(resultArray.items!, 0, resultArray.length)); + }); + + return FlatArray.InnerFactory.FromList(resultList); + } + + public FlatArray FlatMap(Func> map) + { + _ = map ?? throw new ArgumentNullException(nameof(map)); + + if (length == default) + { + return default; + } + + var resultList = new List(); + + InternalForEach( + (i, item) => + { + var resultArray = map.Invoke(item, i); + + if (resultArray.length == default) + { + return; + } + + resultList.AddRange(new ArraySegment(resultArray.items!, 0, resultArray.length)); + }); + + return FlatArray.InnerFactory.FromList(resultList); + } +} \ No newline at end of file diff --git a/src/flatcollections-array/FlatArray/FlatArray.T/FlatArray.Functional.Map.cs b/src/flatcollections-array/FlatArray/FlatArray.T/FlatArray.Functional.Map.cs new file mode 100644 index 00000000..578c526e --- /dev/null +++ b/src/flatcollections-array/FlatArray/FlatArray.T/FlatArray.Functional.Map.cs @@ -0,0 +1,38 @@ +namespace System; + +partial struct FlatArray +{ + public FlatArray Map(Func map) + { + _ = map ?? throw new ArgumentNullException(nameof(map)); + + if (length == default) + { + return default; + } + + var resultItems = new TResult[length]; + + InternalForEach( + (i, item) => resultItems[i] = map.Invoke(item)); + + return new(resultItems, default); + } + + public FlatArray Map(Func map) + { + _ = map ?? throw new ArgumentNullException(nameof(map)); + + if (length == default) + { + return default; + } + + var resultItems = new TResult[length]; + + InternalForEach( + (i, item) => resultItems[i] = map.Invoke(item, i)); + + return new(resultItems, default); + } +} \ No newline at end of file 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 f5512109..13737abc 100644 --- a/src/flatcollections-array/FlatArray/FlatArray.T/InnerArrayHelper/FlatArray.InnerArrayHelper.cs +++ b/src/flatcollections-array/FlatArray/FlatArray.T/InnerArrayHelper/FlatArray.InnerArrayHelper.cs @@ -25,6 +25,19 @@ internal static T[] Copy(T[] source, int length) return dest; } + // 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) + { + Debug.Assert(length1 >= 0 && length1 <= array1.Length); + Debug.Assert(length2 >= 0 && length2 <= array2.Length); + + var result = new T[length1 + length2]; + Array.Copy(array1, result, length1); + Array.Copy(array2, 0, result, length1, length2); + return result; + } + // The caller MUST ensure the new length is GREATER than the source length [MethodImpl(MethodImplOptions.AggressiveInlining)] internal static void ExtendUnchecked(ref T[] array, int newLength) diff --git a/src/flatcollections-array/FlatArray/FlatArray.csproj b/src/flatcollections-array/FlatArray/FlatArray.csproj index e245e4fc..d082becb 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.1.0 + 1.2.0-preview.1 diff --git a/src/flatcollections/FlatCollections/FlatCollections.csproj b/src/flatcollections/FlatCollections/FlatCollections.csproj index 906c012b..c43b46ea 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.1.0 + 1.2.0-preview.1 @@ -32,7 +32,7 @@ - +