@@ -185,6 +185,8 @@ TEnumerableBase<T> = class abstract(TEnumerableBase)
185185 function Min (const comparer: IComparer<T>): T; overload;
186186 function Min (const comparer: TComparison<T>): T; overload;
187187
188+ function Memoize : IEnumerable<T>;
189+
188190 function Ordered : IEnumerable<T>; overload;
189191 function Ordered (const comparer: IComparer<T>): IEnumerable<T>; overload;
190192 function Ordered (const comparer: TComparison<T>): IEnumerable<T>; overload;
@@ -260,7 +262,7 @@ TCollectionWrapper = class(TEnumerableWrapper, ICollection)
260262
261263 TIteratorKind = (
262264 Partition, &Array ,
263- Concat, Ordered, Reversed, Shuffled,
265+ Concat, Memoize, Ordered, Reversed, Shuffled,
264266 SkipWhile, SkipWhileIndex,
265267 TakeWhile, TakeWhileIndex,
266268 Where, WhereIndex, Select);
@@ -292,6 +294,7 @@ TIteratorBlock = record
292294
293295 function GetEnumerator : Boolean;
294296 function GetEnumeratorAndSkip : Boolean;
297+ function GetEnumeratorMemoize : Boolean;
295298
296299 function _Release : Integer; stdcall;
297300 function MoveNext : Boolean;
@@ -309,6 +312,15 @@ TIteratorBase = record
309312 function GetCountFast : Integer;
310313 end ;
311314
315+ TMemoizeIterator<T> = record
316+ // only used via pointer internally
317+ // field layout has to match with TIteratorBase
318+ Source: IEnumerable;
319+ Enumerator: IEnumerator<T>;
320+ Items: TArray<T>;
321+ Index, Count: Integer;
322+ end ;
323+
312324 TIteratorBase<T> = class abstract (TEnumerableBase<T>)
313325 private
314326 function HasLimit : Boolean; inline;
@@ -361,6 +373,7 @@ TIteratorBlock<T> = record
361373 function GetCurrent : T;
362374
363375 function MoveNextConcat : Boolean;
376+ function MoveNextMemoize : Boolean;
364377 function MoveNextOrdered : Boolean;
365378 function MoveNextReversed : Boolean;
366379 function MoveNextSkipWhile : Boolean;
@@ -1505,6 +1518,16 @@ function TEnumerableBase<T>.Min(const comparer: TComparison<T>): T;
15051518 Result := IEnumerable<T>(this).Min(IComparer<T>(PPointer(@comparer)^));
15061519end ;
15071520
1521+ function TEnumerableBase <T>.Memoize: IEnumerable<T>;
1522+ begin
1523+ if (GetInterfaceEntry(ICollectionOfTGuid) <> nil )
1524+ or (GetInterfaceEntry(IReadOnlyCollectionOfTGuid) <> nil ) then
1525+ Result := IEnumerable<T>(this)
1526+ else
1527+ Result := TEnumerableIterator<T>.Create(IEnumerable<T>(this),
1528+ 0 , 0 , nil , TIteratorKind.Memoize);
1529+ end ;
1530+
15081531function TEnumerableBase <T>.Ordered: IEnumerable<T>;
15091532begin
15101533 Result := TEnumerableIterator<T>.Create(IEnumerable<T>(this),
@@ -1693,30 +1716,28 @@ function TEnumerableBase<T>.SkipWhile(
16931716end ;
16941717
16951718function TEnumerableBase <T>.Sum: T;
1696- var
1697- enumerator: IEnumerator<T>;
1698- item: T;
16991719begin
1700- Result := Default(T);
1701- enumerator := IEnumerable<T>(this).GetEnumerator;
1702- while enumerator.MoveNext do
1703- begin
1704- { $IFDEF RSP31615}
1705- if IsManagedType(T) then
1706- IEnumeratorInternal(enumerator).GetCurrent(item)
1707- else
1720+ if TypeInfo(T) = TypeInfo(Integer) then
1721+ PInteger(@Result)^ := TEnumerable.Sum(IEnumerable<Integer>(this))
1722+ else if TypeInfo(T) = TypeInfo(Int64) then
1723+ PInt64(@Result)^ := TEnumerable.Sum(IEnumerable<Int64>(this))
1724+ else if TypeInfo(T) = TypeInfo(NativeInt) then
1725+ { $IFDEF CPU32BITS}
1726+ PInteger(@Result)^ := TEnumerable.Sum(IEnumerable<Integer>(this))
1727+ { $ELSE}
1728+ PInt64(@Result)^ := TEnumerable.Sum(IEnumerable<Int64>(this))
17081729 { $ENDIF}
1709- item := enumerator.Current;
1710- case TType.Kind<T> of
1711- tkInteger: PInteger(@Result)^ := PInteger(@Result)^ + PInteger(@item)^;
1712- tkInt64: PInt64 (@Result)^ := PInt64(@Result)^ + PInt64(@item)^;
1713- tkFloat:
1714- case GetTypeData(TypeInfo(T)).FloatType of
1715- ftSingle: PSingle(@Result)^ := PSingle(@Result)^ + PSingle(@item)^;
1716- ftDouble: PDouble(@Result)^ := PDouble(@Result)^ + PDouble(@item)^;
1717- end ;
1718- end ;
1719- end ;
1730+ else if TypeInfo(T) = TypeInfo(System.Single) then
1731+ PSingle(@Result)^ := TEnumerable.Sum(IEnumerable<System.Single>(this))
1732+ else if TypeInfo(T) = TypeInfo(Double) then
1733+ PDouble (@Result)^ := TEnumerable.Sum(IEnumerable<Double>(this))
1734+ else if TypeInfo(T) = TypeInfo(Currency) then
1735+ PCurrency(@Result)^ := TEnumerable.Sum(IEnumerable<Currency>(this))
1736+ else
1737+ // if T is not of any of the above types this way of calling Sum is not supported
1738+ // consider using TEnumerable.Sum with a selector function to turn the values
1739+ // to any of the supported types for calculating the sum
1740+ RaiseHelper.NotSupported ;
17201741end ;
17211742
17221743function TEnumerableBase <T>.Take(count: Integer): IEnumerable<T>;
@@ -3040,6 +3061,21 @@ function TIteratorBlock.GetEnumeratorAndSkip: Boolean;
30403061 end ;
30413062end ;
30423063
3064+ function TIteratorBlock.GetEnumeratorMemoize : Boolean;
3065+ begin
3066+ if PIteratorBase(Predicate).fCount = 0 then
3067+ begin
3068+ { $IFDEF MSWINDOWS}
3069+ IEnumerableInternal(Source).GetEnumerator(IEnumerator(PIteratorBase(Predicate).fPredicate));
3070+ { $ELSE}
3071+ IEnumerator(PIteratorBase(Predicate).fPredicate) := Source.GetEnumerator;
3072+ { $ENDIF}
3073+ PIteratorBase(Predicate).fCount := PIteratorBase(Predicate).fCount or not CountMask;
3074+ end ;
3075+ DoMoveNext := Methods.MoveNext;
3076+ Result := DoMoveNext(@Self);
3077+ end ;
3078+
30433079function TIteratorBlock.MoveNextEmpty : Boolean;
30443080begin
30453081 Result := False;
@@ -3072,6 +3108,8 @@ class function TIteratorBlock<T>.Create(const iterator: TIteratorBase<T>): IEnum
30723108 Count := iterator.fCount;
30733109 Kind := iterator.fKind;
30743110 Methods.Finalize := @TIteratorBlock<T>.Finalize;
3111+ if Kind = Memoize then
3112+ Pointer(Predicate) := @iterator.fSource;
30753113 end ;
30763114 rec.InitMethods;
30773115 rec.InitVtable;
@@ -3118,6 +3156,16 @@ procedure TIteratorBlock<T>.InitMethods;
31183156 Methods.MoveNext := @TIteratorBlock<T>.MoveNextConcat;
31193157 DoMoveNext := @TIteratorBlock.GetEnumerator;
31203158 end ;
3159+ TIteratorKind.Memoize:
3160+ begin
3161+ if Count = 0 then
3162+ begin
3163+ Methods.MoveNext := @TIteratorBlock<T>.MoveNextMemoize;
3164+ DoMoveNext := @TIteratorBlock.GetEnumeratorMemoize;
3165+ end
3166+ else
3167+ DoMoveNext := @TIteratorBlock<T>.MoveNextMemoize;
3168+ end ;
31213169 TIteratorKind.Ordered:
31223170 begin
31233171 Methods.MoveNext := @TIteratorBlock<T>.MoveNextOrdered;
@@ -3179,7 +3227,10 @@ function TIteratorBlock<T>.Finalize: Boolean;
31793227begin
31803228 Enumerator := nil ;
31813229 Source := nil ;
3182- Predicate := nil ;
3230+ if Kind <> Memoize then
3231+ Predicate := nil
3232+ else
3233+ Pointer(Predicate) := nil ;
31833234 Items := nil ;
31843235{ $IFDEF DELPHIXE7_UP}
31853236 if IsManagedType(T) then
@@ -3227,7 +3278,7 @@ function TIteratorBlock<T>.MoveNextConcat: Boolean;
32273278 { $IFDEF MSWINDOWS}
32283279 IEnumerableInternal(Predicate).GetEnumerator(IEnumerator(Enumerator));
32293280 { $ELSE}
3230- Enumerator := IEnumerable(Predicate).GetEnumerator;
3281+ Enumerator := IEnumerable<T> (Predicate).GetEnumerator;
32313282 { $ENDIF}
32323283 Predicate := nil ;
32333284 until False;
@@ -3282,6 +3333,44 @@ function TIteratorBlock<T>.MoveNextIndexed: Boolean;
32823333 end ;
32833334end ;
32843335
3336+ function TIteratorBlock <T>.MoveNextMemoize: Boolean;
3337+ var
3338+ iterator: ^TMemoizeIterator<T>;
3339+ count, capacity: NativeInt;
3340+ begin
3341+ iterator := Pointer(Predicate);
3342+ count := iterator.Count and CountMask;
3343+ if Index >= count then
3344+ begin
3345+ if iterator.Enumerator = nil then
3346+ Exit(False);
3347+
3348+ if not iterator.Enumerator.MoveNext then
3349+ begin
3350+ iterator.Enumerator := nil ;
3351+ Exit(False);
3352+ end ;
3353+
3354+ capacity := DynArrayLength(iterator.Items);
3355+ if count >= capacity then
3356+ begin
3357+ capacity := GrowCapacity(capacity);
3358+ SetLength(iterator.Items, capacity);
3359+ end ;
3360+ { $IF defined(DELPHIXE7_UP) and defined(MSWINDOWS)}
3361+ if IsManagedType(T) then
3362+ IEnumeratorInternal(iterator.Enumerator).GetCurrent(iterator.Items[count])
3363+ else
3364+ { $IFEND}
3365+ iterator.Items[count] := iterator.Enumerator.Current;
3366+ Inc(iterator.Count);
3367+ end ;
3368+
3369+ Current := iterator.Items[Index];
3370+ Inc(Index);
3371+ Result := True;
3372+ end ;
3373+
32853374function TIteratorBlock <T>.MoveNextOrdered: Boolean;
32863375begin
32873376 if Index < Count then
@@ -3416,12 +3505,10 @@ function TIteratorBlock<T>.MoveNextWhereIndex: Boolean;
34163505function TIteratorBlock <T>.ToArray: Boolean;
34173506begin
34183507 Items := Source.ToArray;
3419- Count := Length (Items);
3508+ Count := DynArrayLength (Items);
34203509 case Kind of
34213510 TIteratorKind.Ordered:
34223511 TArray.Sort<T>(Items, IComparer<T>(Predicate));
3423- TIteratorKind.Reversed:
3424- Count := Length(Items);
34253512 TIteratorKind.Shuffled:
34263513 TArray.Shuffle<T>(Items, DynArrayHigh(Items));
34273514 end ;
@@ -3624,7 +3711,7 @@ function TIteratorBase<T>.ToArray: TArray<T>;
36243711 TIteratorKind.Array :
36253712 begin
36263713 Result := fItems;
3627- SetLength(Result, Length (Result));
3714+ SetLength(Result, DynArrayLength (Result));
36283715 Exit;
36293716 end ;
36303717 TIteratorKind.Ordered:
@@ -3810,7 +3897,7 @@ procedure TArrayIterator<T>.CopyTo(var values: TArray<T>; index: Integer);
38103897var
38113898 count: Integer;
38123899begin
3813- count := Length (fItems);
3900+ count := DynArrayLength (fItems);
38143901 if count > 0 then
38153902 if TType.IsManaged<T> then
38163903 MoveManaged(@fItems[0 ], @values[index], TypeInfo(T), count)
0 commit comments