tag:blogger.com,1999:blog-29331675.post486804943944617586..comments2024-03-05T17:37:00.995+01:00Comments on The Delphi Geek: Fun with enumerators, part 3 - parameterized enumeratorsgabr42http://www.blogger.com/profile/06903558857617342477noreply@blogger.comBlogger11125tag:blogger.com,1999:blog-29331675.post-21410090366589867322016-09-19T08:25:25.264+02:002016-09-19T08:25:25.264+02:00As suggested I made a enumerator that returns the ...As suggested I made a enumerator that returns the specified class from a collection that supports :-<br /><br /> for page in mBook.Filter< cPage > do begin<br /> for picture in page.Filter< cPhotoItem > do begin<br /><br />implemented :-<br /><br />cObjNode = class // base class for tree objects<br /> .... <br /> private<br /> oMakeEnum : TObject; // cMakeEnumMyList< T >;<br /> function FindMatch< T : class >( index : integer ) : integer;<br /> type // see http://www.thedelphigeek.com/2007/03/fun-with-enumerators-part-3.html Primož Gabrijelčič<br /><br /> cEnumNode< T : class > = class<br /> constructor Create( owner: cObjNode );<br /> private<br /> mOwner : cObjNode;<br /> mIndex : integer;<br /> public<br /> function GetCurrent() : T; // [ index ]<br /> function MoveNext: boolean; // Inc( index ) if index<br /> property Current : T read GetCurrent;<br /> end;<br /><br /> cMakeEnumNode< T : class > = class // as required by 'for in'<br /> constructor Create( owner : cObjNode );<br /> private<br /> mOwner : cObjNode;<br /> public<br /> function GetEnumerator: cEnumNode< T >;<br /> end;<br /><br /> public<br /> function Filter< T : class >() : cObjNode.cMakeEnumNode< T >;<br /> end;<br /><br /><br />...<br /><br />function cObjNode.Filter< T >() : cObjNode.cMakeEnumNode< T >;<br /><br /> begin<br /> oMakeEnum.Free; // free the previous one<br /> result := cMakeEnumNode< T >.Create( self );<br /> oMakeEnum := result;<br /> end;<br /><br /><br />function cObjNode.FindMatch< T >( index : integer ) : integer; // filter logic<br /><br /> begin<br /> result := ChildCount; // default to over the end<br /> while index < ChildCount do begin<br /> if oChildren[ index ] is T then begin<br /> result := index;<br /> break;<br /> end;<br /> Inc( index );<br /> end;<br /> end;<br /><br /><br />constructor cObjNode.cEnumNode< T >.Create( owner: cObjNode );<br /><br /> begin<br /> mOwner := owner;<br /> mIndex := -1;<br /> end;<br /><br /><br />function cObjNode.cEnumNode< T >.GetCurrent() : T;<br /><br /> begin<br /> if mIndex < mOwner.ChildCount then result := mOwner[ mIndex ] as T<br /> else result := nil;<br /> end;<br /><br /><br />function cObjNode.cEnumNode< T >.MoveNext: boolean;<br /><br /> begin<br /> mIndex := mOwner.FindMatch< T >( mIndex + 1 );<br /> result := mIndex < mOwner.ChildCount;<br /> end;<br /><br /><br />constructor cObjNode.cMakeEnumNode< T >.Create( owner : cObjNode );<br /><br /> begin<br /> mOwner := owner;<br /> end;<br /><br /><br />function cObjNode.cMakeEnumNode< T >.GetEnumerator: cEnumNode< T >;<br /><br /> begin<br /> result := cObjNode.cEnumNode< T >.Create( mOwner );<br /> end;<br /><br /><br /><br />GThttp://alphasoft1.com.aunoreply@blogger.comtag:blogger.com,1999:blog-29331675.post-67272342037906269252012-12-07T15:02:54.805+01:002012-12-07T15:02:54.805+01:00Is the implementation of the TCSLEnumEveryNth cons...Is the implementation of the TCSLEnumEveryNth constructor missing the "inherited Create;"? Or is it not needed in this case...Erwin Westerhttp://www.erwinwester.nlnoreply@blogger.comtag:blogger.com,1999:blog-29331675.post-86433004337975717792012-06-14T10:39:06.593+02:002012-06-14T10:39:06.593+02:00I don´t see why with this code it shouldn't be...I don´t see why with this code it shouldn't be possible to have two enumerators (with different Skip factors) on the same string list at one time. The index counter is inside the enumerator and that is instantiated for every single for..in loop, meaning another counter for each loop. Where would be the problem?Anonymousnoreply@blogger.comtag:blogger.com,1999:blog-29331675.post-7918644162285463142007-10-17T23:41:00.000+02:002007-10-17T23:41:00.000+02:00To run multiple enumerators on one structure, you ...To run multiple enumerators on one structure, you have to use enumerator factory and interfaces. See parts 4, 5, and 6 for more information.<BR/><BR/>As for the thread-safety - threading is hard. My enumerator code doesn't try at all to be multithread-aware.gabr42https://www.blogger.com/profile/06903558857617342477noreply@blogger.comtag:blogger.com,1999:blog-29331675.post-44465629542634795922007-10-17T23:14:00.000+02:002007-10-17T23:14:00.000+02:00This is a nice example, except that it isn't threa...This is a nice example, except that it isn't thread-safe. In fact, worse than that, it isn't even possible to have two enumerators (with different Skip factors) on the same string list at one time, even on a single thread (a for in loop nested within another for in loop).Anonymousnoreply@blogger.comtag:blogger.com,1999:blog-29331675.post-24122062911845445332007-03-08T17:46:00.000+01:002007-03-08T17:46:00.000+01:00Of course :)With plenty of dire warnings.Of course :)<BR/><BR/>With plenty of dire warnings.gabr42https://www.blogger.com/profile/06903558857617342477noreply@blogger.comtag:blogger.com,1999:blog-29331675.post-15248419366043907502007-03-08T17:34:00.000+01:002007-03-08T17:34:00.000+01:00I've always been an advocate of the school that sa...<I>I've always been an advocate of the school that says "write more code when preparing an infrastructure so you can write less code when using this infrastructure"</I><BR/><BR/>Yeah, but in my version, the 'infrastructure' amounts to less code and the 'use' of it amounts to about the same... Anyhow, I'll be looking out now for part 5. You're going to be creating a class helper, I assume...Chrishttps://www.blogger.com/profile/17560741389745871142noreply@blogger.comtag:blogger.com,1999:blog-29331675.post-50756520650244217702007-03-08T12:42:00.000+01:002007-03-08T12:42:00.000+01:00This is all fully documented (I even quoted Delphi...This is all fully documented (I even quoted Delphi help in Part 1) and will continue to work in future Delphis.gabr42https://www.blogger.com/profile/06903558857617342477noreply@blogger.comtag:blogger.com,1999:blog-29331675.post-21561711836381927302007-03-08T12:06:00.000+01:002007-03-08T12:06:00.000+01:00Very nice stuff, one question I have is will this ...Very nice stuff, one question I have is will this work with BDS 2007, 8.. or is this an undocumented feature?<BR/><BR/>thanks again<BR/>Dave N.Anonymousnoreply@blogger.comtag:blogger.com,1999:blog-29331675.post-22780646375757659682007-03-07T23:47:00.000+01:002007-03-07T23:47:00.000+01:00Sure, but that way you cannot use the for..in :)I'...Sure, but that way you cannot use the for..in :)<BR/><BR/>I've always been an advocate of the school that says "write more code when preparing an infrastructure so you can write less code when using this infrastructure"gabr42https://www.blogger.com/profile/06903558857617342477noreply@blogger.comtag:blogger.com,1999:blog-29331675.post-77897048467033863832007-03-07T22:27:00.000+01:002007-03-07T22:27:00.000+01:00This is interesting stuff, and don't get me wrong,...This is interesting stuff, and don't get me wrong, I'll certainly be looking out for the next installment. But... you need more lines to hook into the compiler's for/in syntax than if you didn't bother! Cf.:<BR/><BR/>ICSLEnum = interface<BR/> function FindNext(out S: string): Boolean;<BR/>end;<BR/><BR/>TCStringList = class(TStringList)<BR/>public<BR/> function CreateEnumerator(Skip: Integer): ICSLEnum;<BR/>end;<BR/><BR/>TCSLEnum = class(TInterfacedObject, ICSLEnum)<BR/>private<BR/> FListIndex: Integer;<BR/> FOwner: TCStringList;<BR/> FSkip: Integer;<BR/>protected<BR/> function FindNext(out S: string): Boolean;<BR/>public<BR/> constructor Create(Owner: TCStringList;<BR/> Skip: Integer);<BR/>end;<BR/><BR/>constructor TCSLEnum.Create(Owner: TCStringList; skip: integer);<BR/>begin<BR/> FOwner := Owner;<BR/> FSkip := Skip;<BR/>end;<BR/><BR/>function TCSLEnum.FindNext(out S: string): Boolean;<BR/>begin<BR/> Result := (FListIndex < FOwner.Count);<BR/> if not Result then Exit;<BR/> S := FOwner[FListIndex];<BR/> Inc(FListIndex, FSkip);<BR/>end;<BR/><BR/>function TCStringList.CreateEnumerator(Skip: Integer): ICSLEnumEveryNth;<BR/>begin<BR/> Result := TCSLEnum.Create(Self, Skip);<BR/>end;<BR/><BR/>with FslTest.CreateEnumerator(3) do<BR/> while FindNext(s) do ln := ln + s;<BR/><BR/>I've shortened the class names so it looks better in the comment box. Anyhow, note there's no factory class needed, which keeps the overall line count down. Also, what replaces the actual for/in construct takes the same number of lines (i.e., 2) that your original did.Chrishttps://www.blogger.com/profile/17560741389745871142noreply@blogger.com