@@ -37,7 +37,13 @@ namespace DryIoc.ImTools
37
37
using System . Runtime . CompilerServices ; // For [MethodImpl(AggressiveInlining)]
38
38
39
39
/// <summary>General purpose Match operator</summary>
40
- public delegate bool Match < S , T , R > ( ref S state , ref T it , out R result ) ;
40
+ public delegate bool MatchOp < S , T , R > ( ref S state , ref T it , out R result ) ;
41
+
42
+ /// <summary>General purpose Is operator</summary>
43
+ public delegate bool IsOp < S , T > ( ref S state , ref T it ) ;
44
+
45
+ /// <summary>General purpose Map operator</summary>
46
+ public delegate R MapOp < S , T , R > ( ref S state , ref T it ) ;
41
47
42
48
/// <summary>Helpers for functional composition</summary>
43
49
public static class Fun
@@ -662,6 +668,17 @@ private static R[] Copy<S, T, R>(this T[] source, S state, int sourcePos, int co
662
668
return results ;
663
669
}
664
670
671
+ private static R [ ] Copy < S , T , R > ( this T [ ] source , ref S state , int sourcePos , int count , MapOp < S , T , R > map )
672
+ {
673
+ var results = new R [ count ] ;
674
+ if ( count == 1 )
675
+ results [ 0 ] = map ( ref state , ref source [ sourcePos ] ) ;
676
+ else
677
+ for ( int i = 0 , j = sourcePos ; i < count ; ++ i , ++ j )
678
+ results [ i ] = map ( ref state , ref source [ j ] ) ;
679
+ return results ;
680
+ }
681
+
665
682
private static R [ ] Copy < A , B , T , R > ( this T [ ] source , A a , B b , int sourcePos , int count , Func < A , B , T , R > map )
666
683
{
667
684
var results = new R [ count ] ;
@@ -709,6 +726,18 @@ private static R[] AppendTo<S, T, R>(this T[] source, S state, R[] results, int
709
726
return results ;
710
727
}
711
728
729
+ private static R [ ] AppendTo < S , T , R > ( this T [ ] source , ref S state , R [ ] results , int sourcePos , int count , MapOp < S , T , R > map )
730
+ {
731
+ var oldResultsCount = results . Length ;
732
+ Array . Resize ( ref results , oldResultsCount + count ) ;
733
+ if ( count == 1 )
734
+ results [ oldResultsCount ] = map ( ref state , ref source [ sourcePos ] ) ;
735
+ else
736
+ for ( int i = oldResultsCount , j = sourcePos ; i < results . Length ; ++ i , ++ j )
737
+ results [ i ] = map ( ref state , ref source [ j ] ) ;
738
+ return results ;
739
+ }
740
+
712
741
private static R [ ] AppendTo < A , B , T , R > ( this T [ ] source , A a , B b , R [ ] results , int sourcePos , int count , Func < A , B , T , R > map )
713
742
{
714
743
var oldResultsCount = results . Length ;
@@ -993,6 +1022,71 @@ public static R[] Match<S, T, R>(this T[] source, S state, Func<S, T, bool> cond
993
1022
return matches ?? ( matchStart == 0 ? source . Copy ( state , 0 , source . Length , map ) : Empty < R > ( ) ) ;
994
1023
}
995
1024
1025
+ /// <summary>Match with the additional state to use in <paramref name="condition"/> and <paramref name="map"/>
1026
+ /// to minimize the allocations in <paramref name="condition"/> lambda closure </summary>
1027
+ public static R [ ] Match < S , T , R > ( this T [ ] source , ref S state , IsOp < S , T > condition , MapOp < S , T , R > map )
1028
+ {
1029
+ if ( source == null )
1030
+ return null ;
1031
+ if ( source . Length == 0 )
1032
+ return Empty < R > ( ) ;
1033
+
1034
+ if ( source . Length == 1 )
1035
+ {
1036
+ var item = source [ 0 ] ;
1037
+ return condition ( ref state , ref item ) ? new [ ] { map ( ref state , ref item ) } : Empty < R > ( ) ;
1038
+ }
1039
+
1040
+ if ( source . Length == 2 )
1041
+ {
1042
+ var c0 = condition ( ref state , ref source [ 0 ] ) ;
1043
+ var c1 = condition ( ref state , ref source [ 1 ] ) ;
1044
+ return c0 & c1 ? new [ ] { map ( ref state , ref source [ 0 ] ) , map ( ref state , ref source [ 1 ] ) }
1045
+ : c0 ? new [ ] { map ( ref state , ref source [ 0 ] ) }
1046
+ : c1 ? new [ ] { map ( ref state , ref source [ 1 ] ) }
1047
+ : Empty < R > ( ) ;
1048
+ }
1049
+
1050
+ if ( source . Length == 3 )
1051
+ {
1052
+ var c0 = condition ( ref state , ref source [ 0 ] ) ;
1053
+ var c1 = condition ( ref state , ref source [ 1 ] ) ;
1054
+ var c2 = condition ( ref state , ref source [ 2 ] ) ;
1055
+ return c0 & c1 & c2 ? new [ ] { map ( ref state , ref source [ 0 ] ) , map ( ref state , ref source [ 1 ] ) , map ( ref state , ref source [ 2 ] ) }
1056
+ : c0 ? ( c1 ? new [ ] { map ( ref state , ref source [ 0 ] ) , map ( ref state , ref source [ 1 ] ) }
1057
+ : c2 ? new [ ] { map ( ref state , ref source [ 0 ] ) , map ( ref state , ref source [ 2 ] ) }
1058
+ : new [ ] { map ( ref state , ref source [ 0 ] ) } )
1059
+ : c1 ? ( c2 ? new [ ] { map ( ref state , ref source [ 1 ] ) , map ( ref state , ref source [ 2 ] ) }
1060
+ : new [ ] { map ( ref state , ref source [ 1 ] ) } )
1061
+ : c2 ? new [ ] { map ( ref state , ref source [ 2 ] ) }
1062
+ : Empty < R > ( ) ;
1063
+ }
1064
+
1065
+ var matchStart = 0 ;
1066
+ R [ ] matches = null ;
1067
+ var matchFound = false ;
1068
+
1069
+ var i = 0 ;
1070
+ for ( ; i < source . Length ; ++ i )
1071
+ if ( ! ( matchFound = condition ( ref state , ref source [ i ] ) ) )
1072
+ {
1073
+ // for accumulated matched items
1074
+ if ( i != 0 && i > matchStart )
1075
+ matches = matches == null
1076
+ ? source . Copy ( ref state , matchStart , i - matchStart , map )
1077
+ : source . AppendTo ( ref state , matches , matchStart , i - matchStart , map ) ;
1078
+ matchStart = i + 1 ; // guess the next match start will be after the non-matched item
1079
+ }
1080
+
1081
+ // when last match was found but not all items are matched (hence matchStart != 0)
1082
+ if ( matchFound && matchStart != 0 )
1083
+ return matches == null
1084
+ ? source . Copy ( ref state , matchStart , i - matchStart , map )
1085
+ : source . AppendTo ( ref state , matches , matchStart , i - matchStart , map ) ;
1086
+
1087
+ return matches ?? ( matchStart == 0 ? source . Copy ( ref state , 0 , source . Length , map ) : Empty < R > ( ) ) ;
1088
+ }
1089
+
996
1090
/// <summary>Match with the additional state to use in <paramref name="condition"/> and <paramref name="map"/>
997
1091
/// to minimize the allocations in <paramref name="condition"/> lambda closure </summary>
998
1092
public static R [ ] Match < A , B , T , R > ( this T [ ] source , A a , B b , Func < A , B , T , bool > condition , Func < A , B , T , R > map )
@@ -1091,6 +1185,28 @@ public static R[] Map<T, S, R>(this T[] source, S state, Func<S, T, R> map)
1091
1185
return results ;
1092
1186
}
1093
1187
1188
+ /// Map with additional state to use in <paramref name="map"/> to minimize allocations in <paramref name="map"/> lambda closure
1189
+ public static R [ ] Map < T , S , R > ( this T [ ] source , ref S state , MapOp < S , T , R > map )
1190
+ {
1191
+ if ( source == null )
1192
+ return null ;
1193
+
1194
+ var sourceCount = source . Length ;
1195
+ if ( sourceCount == 0 )
1196
+ return Empty < R > ( ) ;
1197
+
1198
+ if ( sourceCount == 1 )
1199
+ return new [ ] { map ( ref state , ref source [ 0 ] ) } ;
1200
+
1201
+ if ( sourceCount == 2 )
1202
+ return new [ ] { map ( ref state , ref source [ 0 ] ) , map ( ref state , ref source [ 1 ] ) } ;
1203
+
1204
+ var results = new R [ sourceCount ] ;
1205
+ for ( var i = 0 ; i < source . Length ; i ++ )
1206
+ results [ i ] = map ( ref state , ref source [ i ] ) ;
1207
+ return results ;
1208
+ }
1209
+
1094
1210
/// Map with additional two states to use in <paramref name="map"/> to minimize allocations in <paramref name="map"/> lambda closure
1095
1211
public static R [ ] Map < T , A , B , R > ( this T [ ] source , A a , B b , Func < A , B , T , R > map )
1096
1212
{
0 commit comments