### Bookstore

 Computer Math and Games in Pascal (preview) Lazarus Handbook

### Author Topic: "Flatten" linked-lists or trees in Watches of debugger  (Read 2864 times)

#### 440bx

• Hero Member
• Posts: 4478
##### Re: "Flatten" linked-lists or trees in Watches of debugger
« Reply #15 on: July 27, 2024, 01:36:17 am »
Just played with it after updating to the latest trunk.

I really like the Obj3 view.  It's a little longer than Obj4 but, it makes it really easy to visualize how the tree is organized as well as why (by identifying the field(s) it followed.)

This is really good stuff that can be extremely helpful in debugging complex tree indexes.

again, thank you for all that work, much appreciated.
(FPC v3.0.4 and Lazarus 1.8.2) or (FPC v3.2.2 and Lazarus v3.2) on Windows 7 SP1 64bit.

#### Martin_fr

• Administrator
• Hero Member
• Posts: 10240
• Debugger - SynEdit - and more
##### Re: "Flatten" linked-lists or trees in Watches of debugger
« Reply #16 on: July 29, 2024, 11:23:55 pm »
Brainstorming....

So, if you use
Code: Pascal  [Select][+][-]
1. :f_(a, Left, Right, [obj])

Then you can't do
Code: Pascal  [Select][+][-]
1. :f_(a, Left, Right, [obj])[0..999].SomeValue

Because the result of flatten is a structure with the keys d,k,v. And if you append "[0..999].V.SomeValue" to access SomeValue in V, then you loose the structure keys...

Solution is simple
Code: Pascal  [Select][+][-]
1. :f_(a, Left"add .SomeValue here", Right, [obj])
Of course you can't, because you need the object in the key "Left", so that the object can be used in the next iteration of flatten. (SomeValue may be an int or string on that object)

What is needed is, that the key has 2 parts
1) get the object (which will be used for further iteration)
2) get the display part from that object (that will be in "v" of the [obj])

So a separator is needed between the 2 parts of the key. I personally favour the ":" (as it is in var a:int;)

Code: Pascal  [Select][+][-]
1. :f_(a, Left:SomeValue, Right:SomeValue, [obj])
Which means, get the next object for the iteration from Left and Right.
But in the output show only Left.SomeValue.

So far so good. Only downside: the ":" is also used in
Code: Text  [Select][+][-]
1. a ? b : c
And the colon can start an intrinsic.

Yet, there is no case where that would make it ambiguous. It can always be clearly detected as one and only one of those.

But it is like the "case else" if you have an large nested "if then else" in the case section before.

E.g. you can have
Code: Pascal  [Select][+][-]
1. :f_(a,
2.     :_.x ? :_.Left1 : :_.Left2    :    :_.y ? :_.SomeValue1 : :_.SomeValue2,
3.     Right:SomeValue,
4.     [obj]
5. )

On the other hand I really think the colon is the most natural choice...

#### Martin_fr

• Administrator
• Hero Member
• Posts: 10240
• Debugger - SynEdit - and more
##### Re: "Flatten" linked-lists or trees in Watches of debugger
« Reply #17 on: July 31, 2024, 11:16:37 pm »
I added :obj
And mapping for each key.

See the wiki.

#### Martin_fr

• Administrator
• Hero Member
• Posts: 10240
• Debugger - SynEdit - and more
##### Re: "Flatten" linked-lists or trees in Watches of debugger
« Reply #18 on: August 02, 2024, 10:25:25 pm »
And I got the "!" working. To end the magic-mapping of a slice, and allow it to be used inside :flatten.

Now if you have a structure as below, you can do:
Code: Text  [Select][+][-]
1. :flatten(MyData, :cc(TObject(:_.Children.FList.FList^[0..:_.Children.FList.FCount-1]))!: :obj(val: :_.Value, dat: :_.Data), [array,obj4])

Mind, if you got more than one key to follow (e.g. if there was a BackupChildren that you also wanted to include), then you do not need to repeat the ": :obj(....)" part. Instead you can do "BackupChildren:1" The "1" meaning to use the same expression for display as the argument with index=1)

I am aware that the initial object does not get mapped.... yet... But, well, later.

Code: Pascal  [Select][+][-]
1. program test;
2. uses Classes;
3. type
4.   TFoo = class
5.     Value: integer;
6.     Data: boolean;
7.     constructor Create(V: integer; D: Boolean); overload;
8.   end;
9.
10.   TFooNode = class(TFoo)
11.     Children: TList;
12.     constructor Create(V: integer; D: Boolean); overload;
13.   end;
14.
15. constructor TFoo.Create(V: integer; D: Boolean);
16. begin
17.   Value := v;
18.   Data := d;
19. end;
20.
21. constructor TFooNode.Create(V: integer; D: Boolean);
22. begin
23.   inherited Create(V, D);
24.   Children := TList.Create;
25. end;
26.
27. var
28.   MyData: TFooNode;
29. begin
30.   MyData := TFooNode.Create(1,True);
31.   TFooNode(MyData).Children.Add(TFooNode.Create(11, False));
32.   TFooNode(MyData).Children.Add(TFooNode.Create(12, False));
33.   TFooNode(MyData).Children.Add(TFooNode.Create(13, True));
34.   TFooNode(MyData).Children.Add(TFooNode.Create(14, False));
35.
36.   TFooNode(MyData.Children[0]).Children.Add(TFooNode.Create(111, False));
37.   TFooNode(MyData.Children[0]).Children.Add(TFooNode.Create(112, True));
38.   TFooNode(MyData.Children[0]).Children.Add(TFooNode.Create(113, False));
39.
40.   TFooNode(MyData.Children[1]).Children.Add(TFooNode.Create(121, False));
41.   TFooNode(MyData.Children[1]).Children.Add(TFooNode.Create(122, False));
42.   TFooNode(MyData.Children[1]).Children.Add(TFoo.Create(123, False));
43.   TFooNode(MyData.Children[1]).Children.Add(TFoo.Create(124, False));
44.
45.   TFooNode(TFooNode(MyData.Children[1]).Children[1]).Children.Add(TFooNode.Create(1221, False));
46.   TFooNode(TFooNode(MyData.Children[1]).Children[1]).Children.Add(TFooNode.Create(1221, True));
47.
48.   TFooNode(MyData.Children[3]).Children.Add(TFooNode.Create(141, True));
49.   MyData:=MyData; // break here
50. end.