Jump to content

A.M. Hoornweg

  • Content Count

  • Joined

  • Last visited

Community Reputation

5 Neutral

Recent Profile Visitors

The recent visitors block is disabled and is not being shown to other users.

  1. You're right, that's what it's called nowadays (and it is a much clearer description). Any idea in what OS version Microsoft renamed it?
  2. I rarely ever use repeat either. Because a repeat loop always iterates at least once. The example of the original poster will throw a GPF if the initial node is the root node. I do use exit() , but if it is inside a try/finally block, I always write a remark behind it that it will jump to the next "finally" statement.
  3. I dislike abstract classes because they still force you to inherit from a common base class instead of leaving you full freedom of implementation.
  4. I think that the problem with inheritance is mainly that the descendant object may expose unwanted methods of the ancestor. For example: A "List" is a sequence of stuff and one can insert, delete and read from any valid position (which also makes sorting possible). Retrieval does not necessarily imply removal. A "Stack" is a list with severe constraints, lacking random access and enforcing LIFO behaviour. Most implementations also enforce that retrieval is removal (as in PUSH/POP). A "Queue" is similar, only it enforces FIFO. The problem is the word "constraint". Inheriting from a class in Delphi can extend it, but AFAIK it isn't possible to *hide* methods of an ancestor class, or is it? It is tempting and dead easy to inherit a tStack or tQueue from a tList, but in that case one would expose unwanted methods like Insert(), Delete() and Sort().
  5. Nobody said that Subscriber.OnNotify() needs to be blocking. In my case the subscriber base class is generic and I've implemented the asynchronicity in the derived classes. The current subscribers simply queue the information and perform a Postmessage() for asynchronous processing in the main VCL thread. The only limitation of the publisher is that it is single threaded by design, so calls to subscribe/unsubscribe & Publish must be done in one thread.
  6. I'm using this in a publisher/subscriber/event pattern. The event, the subscriber and the publisher classes are all implemented as generics; my idea was to make the code 100% re-usable for multiple purposes. By using generics I can "fill in the details" at implementation time. Anyway; the Publisher publishes the Event to all Subscribers, but of course a subscriber may decide to unsubscribe() during this notification, thus causing the element to be deleted from the list that was being enumerated during the Publish(). But since this is happening synchronously (single-threaded) and just for one subscriber at a time, it should be 100% safe to simply iterate the list backward and allow it to happen. And if during the Publish() a new subscriber gets appended to the end of the list, he'll simply miss the notification, which is also perfectly correct behavior (a subscriber shouldn't receive a notification that predates his subscription). So I think that a backward enumerator will do perfectly for my purpose.
  7. Hi Stefan, these were just my first trials with generic lists having enumerators, I'm totally unexperienced with that matter .... I have now separated the enumerator from the list by writing a generic class factory for it. No more inheritance needed. It now works like this: Type intList=tList<integer>; Reversed: ReverseList<integer>; // class factory, class function "enum" returns an interface Var ints:intlist; i:integer; begin ints:=intList.create; ints.add(1); ints.add(2); FOR i IN Reversed.Enum(ints) Do begin ... end; ints.free; end; The reason why I'm experimenting with backward iterators is that it is intended for a list in which elements may get deleted during the enumeration. For .. in is simply much more legible than For .. downto IMHO and also less error-prone . // Interface Part: TYPE iListEnumFactory < T >= INTERFACE FUNCTION GetEnumerator: TEnumerator<T>; END; tListEnumReversed<T> = CLASS(TEnumerator<T>) PROTECTED fowner: tlist<T>; fListIndex: integer; FUNCTION DoGetCurrent: T; OVERRIDE; FUNCTION DoMoveNext: Boolean; OVERRIDE; PUBLIC CONSTRUCTOR Create(owner: tlist<T>); END; // also works fine for tObjectlist<T> ReverseList <T>= CLASS(tinterfacedobject, iListEnumFactory<T>) PROTECTED fowner: tlist<T>; PUBLIC CONSTRUCTOR Create(aOwner: tlist<T>); FUNCTION GetEnumerator: TEnumerator<T>; CLASS FUNCTION Enum(aOwner: tlist<T>): iListEnumFactory<T>; END; IMPLEMENTATION CONSTRUCTOR tListEnumReversed<T>.Create(owner: tlist<T>); BEGIN INHERITED Create; fowner := owner; fListIndex := owner.count; END; FUNCTION tListEnumReversed<T>.DoGetCurrent: T; BEGIN result := fowner[fListIndex]; END; FUNCTION tListEnumReversed<T>.DoMoveNext: Boolean; BEGIN result := fListIndex > 0; IF result THEN Dec(fListIndex); END; CONSTRUCTOR ReverseList<T>.Create(aOwner: tlist<T>); BEGIN INHERITED Create; fowner := aOwner; END; CLASS FUNCTION ReverseList<T>.Enum(aOwner: tlist<T>): iListEnumFactory<T>; BEGIN result := Create(aOwner); END; FUNCTION ReverseList<T>.GetEnumerator: TEnumerator<T>; BEGIN result := tListEnumReversed<T>.Create(fowner); END; end.
  8. AHHH, that makes sense! Thanks for pointing this out!
  9. Hello all, I'm stumbling on an unexpected generics-related problem here (Delphi XE). I'm trying to implement a backward-running enumerator for a generic tList<T>. I believe I did everything correctly but still the enumerator runs forward unless I make a modification that really shouldn't be necessary. TYPE tListEnumReversed<T> = CLASS(tEnumerator<T>) PROTECTED fowner: tlist<T>; fListIndex: integer; FUNCTION DoGetCurrent: T; OVERRIDE; FUNCTION DoMoveNext: Boolean; OVERRIDE; PUBLIC CONSTRUCTOR Create(owner: tlist<T>); END; tListReversed<T> = CLASS(tlist<T>) PROTECTED FUNCTION DoGetEnumerator: tEnumerator<T>; OVERRIDE; END; CONSTRUCTOR tListEnumReversed<T>.Create(owner: tlist<T>); BEGIN fowner := owner; fListIndex := owner.count; END; FUNCTION tListEnumReversed<T>.DoGetCurrent: T; BEGIN Result := fowner[fListIndex]; END; FUNCTION tListEnumReversed<T>.DoMoveNext: Boolean; BEGIN Result := fListIndex > 0; IF Result THEN Dec(fListIndex); END; FUNCTION tListReversed<T>.DoGetEnumerator: tEnumerator<T>; BEGIN Result := tListEnumReversed<T>.Create(Self); END; This is the code I used for testing: ... Var t:tListReversed<Integer>; i:integer; begin t:=tListReversed<Integer>.Create; t.Add(1); t.Add(2); t.Add(3); For i in T do memo1.lines.add(inttostr(i)) t.free; end; The weird thing is, the code runs correctly if I make the following change.... And I have literally no idea why that is the case! As far as I can see, the base class tEnumerable<T> already has a method GetEnumerator which should call my overridden virtual Method DoGetEnumerator. What am I missing here ??? tListReversed<T> = CLASS(tlist<T>) PROTECTED FUNCTION DoGetEnumerator: tEnumerator<T>; OVERRIDE; PUBLIC FUNCTION GetEnumerator: TEnumerator<T>; END; ... function tListReversed<T>.GetEnumerator: TEnumerator<T>; begin result:=DoGetEnumerator; end;
  10. Hello all, I'm currently using Turbopower Lockbox 2 for AES encryption and I'd like to move on to something that's newer & active. The caveat is that I need to stay compatible with existing encrypted binary files. Lockbox2 converts a password into a 128 bit hash (a 16 byte array called tKey128) using a proprietary algorithm. Subsequently, its AES cipher uses this hash for encrypting or decrypting the data. I have the old Lockbox2 password hashes ready-made. Is it possible to use them in a newer library (such as lockbox 3) to decode files that were previously AES encoded using Lockbox 2?
  11. I use a freeware tool called "agent ransack" which is brilliant for quickly finding strings in whole directory trees. It also has a regular expressions option and it is lightning fast. What's especially nice about Agent Ransack is that you can drag&drop the search results onto an editor like Notepad++ and then perform a bulk search&replace inside all opened files.
  12. That's cool! I really need to take a closer look at these event functions. Thanks for teaching me something new!
  13. I use Finalbuilder too, but as far as I can see you can't parametrize the Delphi version in the compile action. Do you create a separate compile action for each Delphi version?
  14. Never mind, I've found an easier way to find it out. Look at this page : http://docwiki.embarcadero.com/Libraries/Rio/en/Help_of_Previous_Versions This page lets me browse the help file wiki for older Delphi versions (starting with 2010). I simply navigated to the unit of interest for a specific Delphi version, such as this one: http://docwiki.embarcadero.com/Libraries/XE7/en/System.AnsiStrings ... and by simply replacing the "XE7" in the link for older versions, I was able to ascertain that function "searchbuf" first appeared in the Ansistrings unit in Delphi XE4. Problem solved!
  15. Hello all, Our company uses several Delphi versions and I want my code to compile without warnings on all these versions. When I compile one of my units with Delphi Rio, the compiler emits a warning that "sysutils.searchbuf" is deprecated and has moved to the "ansistrings" unit. No problem, but how do I find out in which Delphi version this transition was made? I'd like to write an appropriate {$IF compilerversion} around my code block to suppress the warning and keep it functional across all Delphi versions. Kind regards, Arthur