it's using a quite standard double-linked list and the implementor found easier to GetMem() for a whole record.
Any idea, thoughts?fcl-stl is not exactly the best implementation -its interface is! -. It tries to mimic a C++ style standard template library..
1. I think OO implementation of standard double-linked list is more readable, extendable and customizable.A TList or a TList<T> are underneath linked lists, just like in C.
2. There must be other reasons (memory, performance,...)No. The only reasons are OOP in the first place: A linked list isn't. It's a list of pointers, a.k.a. memory locations.
3. Using records in classes in wrong place and way breaks OO spirit and design.You do not understand the encapsulation part of object orientation.
fcl-stl is not exactly the best implementation -its interface is! -. It tries to mimic a C++ style standard template library..
FPC/Lazarus has at least two standard libraries that are - implementation wise - much better:
- fgl
- rtl-generics.
OO spirit and designOO is just one tool. Tools are specific to their use cases, and you have to know when to switch tools. There is no silver bullet (https://en.wikipedia.org/wiki/No_Silver_Bullet).
OK. My question is not from the user side, but from learner and programmer. I try to understand pros and cons of gset implementation.well, one "pro" to this is by by placing all of my variables in a record, I can use a call to fillchar(my,sizeof(my),0) => "fill memory with 0" in my Clear() procedure. My warning anyone using this trick is you can only have simple variables in your record. Strings, classes, and even arrays defined within the record should not be cleared in this manor so I keep them outside the record.
A TList or a TList<T> are underneath linked lists, just like in C.
Reading fcl-stl gset implementation on GitHub I found that gset class contains pointer to the record. Why usage of records in the class? Why just not standard class fields?It seems that you misunderstand what is happening here. Node is not a field, it's a type. It would logically be equal to declare Node outside of TSet<,>. This way TSet<,> can contain multiple Node entries by using a linked list which is much less expensive than doing a linked list for the whole class. And the FSize is simply there to keep track of the amount of items without the need to iterate the whole linked list.
generic TSet<T, TCompare>=class public type PNode=^Node; Node=record Data:T; Left,Right:PNode; Parent:PNode; Color:boolean; end; TIterator=specialize TSetIterator<T, Node>; var private FBase:PNode; FSize:SizeUInt;
BTW FSize is outside the record!
Thanks.
It seems that you misunderstand what is happening here. Node is not a field, it's a type. It would logically be equal to declare Node outside of TSet<,>. This way TSet<,> can contain multiple Node entries by using a linked list which is much less expensive than doing a linked list for the whole class. And the FSize is simply there to keep track of the amount of items without the need to iterate the whole linked list.Ok. Thanks. I got it. I am writing implementation of similar data structure without records. Node is instance of class in my code and all operations are class methods. This approach has overheads, but works good and fast. Gset instance holds only pointer to the root node. But my question remains.
OK. My question is not from the user side, but from learner and programmer. I try to understand pros and cons of gset implementation.well, one "pro" to this is by by placing all of my variables in a record, I can use a call to fillchar(my,sizeof(my),0) => "fill memory with 0" in my Clear() procedure. My warning anyone using this trick is you can only have simple variables in your record. Strings, classes, and even arrays defined within the record should not be cleared in this manor so I keep them outside the record.
This approach has overheads, but works good and fast. Gset instance holds only pointer to the root node. But my question remains.
When it's for yourself it may not matter (much) but when writing general code that may be used by thousands of programmers for thousands of different applications it matters quite a lot.That's right. Assume for different reasons we want augment, extend Node in gset class. Can we do this? Can we subclass gset class and add other fields to the inner record. If yes , how?
thank you for this tidbit. if I read this correctly, that thread says you are using fillchar on strings? from what I understand, a string may be broken across 2 areas of memory and is likely to live outside it's record's memory block. I can see how it may work on a string at startup or if it's fixed size but have you tried it on one that has changed 10 to 20 times with different lengths? (your code in the other thread look like you used setlength() to fix it's size and thus it's location)OK. My question is not from the user side, but from learner and programmer. I try to understand pros and cons of gset implementation.well, one "pro" to this is by by placing all of my variables in a record, I can use a call to fillchar(my,sizeof(my),0) => "fill memory with 0" in my Clear() procedure. My warning anyone using this trick is you can only have simple variables in your record. Strings, classes, and even arrays defined within the record should not be cleared in this manor so I keep them outside the record.
@mas steindorff:
Look at this thread "Weird Memory Leak!! (https://forum.lazarus.freepascal.org/index.php/topic,16527.msg90059.html#msg90059)". Martin_fr suggested to use this code:And now I can't live without that code (by the way this month was the birthday of such a great procedure, now it has 7 years and 20 days old :D )
procedure FillerByte(out x; count: SizeInt; value: byte); begin FillByte(x, count, value); end;
... but have you tried it on one that has changed 10 to 20 times with different lengths? ...
(your code in the other thread look like you used setlength() to fix it's size and thus it's location)
thank you for this tidbit. if I read this correctly, that thread says you are using fillchar on strings? from what I understand, a string may be broken across 2 areas of memory and is likely to live outside it's record's memory block. I can see how it may work on a string at startup or if it's fixed size but have you tried it on one that has changed 10 to 20 times with different lengths? (your code in the other thread look like you used setlength() to fix it's size and thus it's location)