Recent

Author Topic: Copying records with dynamic arrays  (Read 4568 times)

Zvoni

  • Hero Member
  • *****
  • Posts: 2896
Re: Copying records with dynamic arrays
« Reply #30 on: January 27, 2025, 03:48:31 pm »
Another potential Approach to "map 1D-Array to 2D-Array" is the "Div/Mod"-Approach
From your first post i see you have an 80x25 "Grid" (80 rows and 25 columns), meaning 2000 "cells"
If you now declare an Array[0..1999] of your "Content" you can Div/Mod the position.
Of course, this only works for zero-based arrays (Yes, it can work on 1-based arrays, but do you really want the hassle?)

e.g. Index 162
162 Div 80 = 2 --> meaning you are in Row 3 ("Row 0" being the first row)
162 Mod 25 = 12 --> meaning you are in Column 13 ("Column 0" being the first column)

Index 400
400 Div 80 = 5 --> Row 6
400 Mod 25 = 0 --> Column 1
« Last Edit: January 27, 2025, 03:50:20 pm by Zvoni »
One System to rule them all, One Code to find them,
One IDE to bring them all, and to the Framework bind them,
in the Land of Redmond, where the Windows lie
---------------------------------------------------------------------
Code is like a joke: If you have to explain it, it's bad

cdbc

  • Hero Member
  • *****
  • Posts: 1946
    • http://www.cdbc.dk
Re: Copying records with dynamic arrays
« Reply #31 on: January 27, 2025, 04:02:36 pm »
Hi
@Zvoni:
Quote
e.g. Index 162
162 Div 80 = 2 --> meaning you are in Row 3 ("Row 0" being the first row)
162 Mod 25 = 12 --> meaning you are in Column 13 ("Column 0" being the first column)
Shouldn't that be:
Quote
e.g. Index 162
162 Div 80 = 2 --> meaning you are in Row 3 ("Row 0" being the first row)
(162 Mod 80) + 1 = 3 --> meaning you are in Column 4 ("Column 0" being the first column)
...or is my math completely wrong, I mean your example will result in 172
Regards benny
« Last Edit: January 27, 2025, 04:05:11 pm by cdbc »
If it ain't broke, don't fix it ;)
PCLinuxOS(rolling release) 64bit -> KDE5 -> FPC 3.2.2 -> Lazarus 3.6 up until Jan 2024 from then on it's both above &: KDE5/QT5 -> FPC 3.3.1 -> Lazarus 4.99

TRon

  • Hero Member
  • *****
  • Posts: 4139
Re: Copying records with dynamic arrays
« Reply #32 on: January 27, 2025, 04:10:51 pm »
I think you may have misunderstood me there. I haven't implemented the single-dimension approach yet. I was talking about the difference after converting WindowList[] to dynamic.
I must have then (I thought the part I quoted from you was meant as a reaction to alpine's suggestion to switch from 2D to 1D arrays which requires some calculation). If my reaction is misplaced then I apologize.

Quote
Don't get me wrong. I am very much open to suggestions! But, I'll be the first to admit that I'm a relative newbie in coding. I'm basically trying to pick up where I left off in high school, some quarter century ago. A lot of these concepts are just a bit beyond my skill level. I don't even understand what an 'array property' means.
Ah, ok. Thank you for the background information. It is not required to share but I honestly thought your FPC skills were not that of a complete newbie. Always difficult to judge from the other side of the screen  :)

In that case, do what you are most comfortable with. In the end you have to work with it, not us. You need to have a fair understanding of how your own code works before being able to advance/improve on what you've learned..

Quote
Do you think you could provide an example?
Sure, if only to show what could be possible (it is not an ideal example because it could have been a better fit for your current implementation).

fwiw : Please don't let yourself being suckered in into something you do not fully grasp or feel comfortable with as that would probably make things worse for your current and future progress.

Code: Pascal  [Select][+][-]
  1. program test;
  2.  
  3. {$mode objfpc}{$h+}
  4. {$modeswitch advancedrecords}
  5.  
  6. uses
  7.   types, sysutils;
  8.  
  9. type
  10.   TContentType = record
  11.    private
  12.     function  GetItem(x:integer; y: integer): char;
  13.     procedure SetItem(x: integer; y: integer; c: char);
  14.    public
  15.     size : TSize;
  16.     data : packed array of AnsiChar;
  17.     property Items[x: integer; y: integer]: char read GetItem write SetItem; default;
  18.     procedure SetSize(w,h: integer);
  19.   end;
  20.  
  21. procedure TContentType.SetSize(w,h: integer);
  22. begin
  23.   // sample does not account for resizing.
  24.   size.Width  := w;
  25.   size.Height := h;
  26.   SetLength(Self.data, size.Width*size.Height);
  27. end;
  28.  
  29. function  TContentType.GetItem(x: integer; y: integer): char;
  30. begin
  31.   result := self.data[y*size.width + x];
  32. end;
  33.  
  34. procedure TContentType.SetItem(x: integer; y: integer; c: char);
  35. begin
  36.   self.data[y*size.width + x] := c;
  37. end;
  38.  
  39. var
  40.   Content: TContentType;
  41.   Width  : integer = 10;
  42.   Height : integer = 8;
  43.   cx,cy  : integer;
  44.   ch     : Char = ' ';
  45. begin
  46.   // only do this when width * heigh <= 127
  47.   Content.SetSize(Width, Height);
  48.  
  49.   // fill content
  50.   for cy := 0 to pred(height) do
  51.     for cx := 0 to pred(width) do
  52.     begin
  53.       Content[cx, cy] := ch;
  54.       inc(ch);
  55.     end;
  56.  
  57.   // display buffer
  58.   for ch in Content.Data
  59.     do write(ch);
  60.   writeln;
  61. end.
  62.  

Something like that (that is if I did not make any stupid mistakes).
Today is tomorrow's yesterday.

alpine

  • Hero Member
  • *****
  • Posts: 1372
Re: Copying records with dynamic arrays
« Reply #33 on: January 27, 2025, 04:25:29 pm »
@TRon
With such a fine example, you could also include an additional  'ZeroBased: Boolean' property for lavishness.   :D
"I'm sorry Dave, I'm afraid I can't do that."
—HAL 9000

TRon

  • Hero Member
  • *****
  • Posts: 4139
Re: Copying records with dynamic arrays
« Reply #34 on: January 27, 2025, 04:47:02 pm »
Thank you alpine, nothing really fancy though. I couldn't get it done with only a type-helper (without cheating).

Better would perhaps be to also include the colour and while at it make the whole window type an advanced record. or object/class.

But, I can understand in case someone is more familiar with only using procedural code.

And indeed everything is possible including the zerobased option and/or overloading the high and low functions in order to stay as close to the original code from TS as possible.
Today is tomorrow's yesterday.

alpine

  • Hero Member
  • *****
  • Posts: 1372
Re: Copying records with dynamic arrays
« Reply #35 on: January 27, 2025, 05:29:05 pm »
Thank you alpine, nothing really fancy though. I couldn't get it done with only a type-helper (without cheating).
Don't get me wrong, I think it's really good, but it might be too much for a newbie. It would be helpful first to grasp the basic idea of ​​linearization (and the memory layout for the compound types in general).
"I'm sorry Dave, I'm afraid I can't do that."
—HAL 9000

TRon

  • Hero Member
  • *****
  • Posts: 4139
Re: Copying records with dynamic arrays
« Reply #36 on: January 27, 2025, 05:32:48 pm »
No problem alpine, my mistake. You're right in that it would be better to let that sink in first.
Today is tomorrow's yesterday.

Zvoni

  • Hero Member
  • *****
  • Posts: 2896
Re: Copying records with dynamic arrays
« Reply #37 on: January 28, 2025, 07:59:33 am »
Hi
@Zvoni:
Quote
e.g. Index 162
162 Div 80 = 2 --> meaning you are in Row 3 ("Row 0" being the first row)
162 Mod 25 = 12 --> meaning you are in Column 13 ("Column 0" being the first column)
Shouldn't that be:
Quote
e.g. Index 162
162 Div 80 = 2 --> meaning you are in Row 3 ("Row 0" being the first row)
(162 Mod 80) + 1 = 3 --> meaning you are in Column 4 ("Column 0" being the first column)
...or is my math completely wrong, I mean your example will result in 172
Regards benny

OOOOOPPPSSS!!
You're right. My bad.
I blame being winter and all that.....

80 Rows, 25 columns has to be of course
162 Div 25 for rows
162 Mod 25 for columns

If it's the other way round, well then....
One System to rule them all, One Code to find them,
One IDE to bring them all, and to the Framework bind them,
in the Land of Redmond, where the Windows lie
---------------------------------------------------------------------
Code is like a joke: If you have to explain it, it's bad

McDoob

  • New Member
  • *
  • Posts: 29
Re: Copying records with dynamic arrays
« Reply #38 on: January 28, 2025, 05:44:23 pm »
Quote
Don't get me wrong. I am very much open to suggestions! But, I'll be the first to admit that I'm a relative newbie in coding. I'm basically trying to pick up where I left off in high school, some quarter century ago. A lot of these concepts are just a bit beyond my skill level. I don't even understand what an 'array property' means.
Ah, ok. Thank you for the background information. It is not required to share but I honestly thought your FPC skills were not that of a complete newbie. Always difficult to judge from the other side of the screen  :)

Hey. To be clear, I said 'relative' newbie, not 'complete'!  XD
Certainly, my knowledge of Pascal is substantially lower than yours and the others who've contributed to this thread, but I'm not exactly at 'Hello World' level. If I were, I doubt I would be working on code such as we're discussing.
Quote
In that case, do what you are most comfortable with. In the end you have to work with it, not us. You need to have a fair understanding of how your own code works before being able to advance/improve on what you've learned..
I've been advancing my understanding quite a bit over the past couple of days. I expect, by next weekend, to have converted all of my arrays to dynamic (there's still a couple in my menu subsystems).
Quote
Quote
Do you think you could provide an example?
Sure, if only to show what could be possible (it is not an ideal example because it could have been a better fit for your current implementation).

fwiw : Please don't let yourself being suckered in into something you do not fully grasp or feel comfortable with as that would probably make things worse for your current and future progress.

Code: Pascal  [Select][+][-]
  1. program test;
  2.  
  3. {$mode objfpc}{$h+}
  4. {$modeswitch advancedrecords}
  5.  
  6. uses
  7.   types, sysutils;
  8.  
  9. type
  10.   TContentType = record
  11.    private
  12.     function  GetItem(x:integer; y: integer): char;
  13.     procedure SetItem(x: integer; y: integer; c: char);
  14.    public
  15.     size : TSize;
  16.     data : packed array of AnsiChar;
  17.     property Items[x: integer; y: integer]: char read GetItem write SetItem; default;
  18.     procedure SetSize(w,h: integer);
  19.   end;
  20.  
  21. procedure TContentType.SetSize(w,h: integer);
  22. begin
  23.   // sample does not account for resizing.
  24.   size.Width  := w;
  25.   size.Height := h;
  26.   SetLength(Self.data, size.Width*size.Height);
  27. end;
  28.  
  29. function  TContentType.GetItem(x: integer; y: integer): char;
  30. begin
  31.   result := self.data[y*size.width + x];
  32. end;
  33.  
  34. procedure TContentType.SetItem(x: integer; y: integer; c: char);
  35. begin
  36.   self.data[y*size.width + x] := c;
  37. end;
  38.  
  39. var
  40.   Content: TContentType;
  41.   Width  : integer = 10;
  42.   Height : integer = 8;
  43.   cx,cy  : integer;
  44.   ch     : Char = ' ';
  45. begin
  46.   // only do this when width * heigh <= 127
  47.   Content.SetSize(Width, Height);
  48.  
  49.   // fill content
  50.   for cy := 0 to pred(height) do
  51.     for cx := 0 to pred(width) do
  52.     begin
  53.       Content[cx, cy] := ch;
  54.       inc(ch);
  55.     end;
  56.  
  57.   // display buffer
  58.   for ch in Content.Data
  59.     do write(ch);
  60.   writeln;
  61. end.
  62.  

Something like that (that is if I did not make any stupid mistakes).

Oof. That's going to take a few reads before I can wrap my head around it. There's a lot of stuff in there I'm not familiar with. It's a bit of a surprise to me that one can have funcs/procs within a type declaration. I'll start working on that in the next revision; right now I'm trying to concentrate on converting all of my arrays to dynamic with the code I currently have.

Also, I have two copies of the code I'm working on; one that works and can be used in anything else, and one that I can mess around with and possibly break while I learn how to implement the suggestions I'm getting from everyone. I certainly wouldn't just copy-paste something directly into the working copy without trying to figure it out in the test copy. I am at least pretending to maintain good coding practices.  8)

I really appreciate all the help and suggestions everyone is giving me!
-McDoob

EDIT: What's the difference between a 'packed' array and a regular one? And why must Width*Height be less than 128?
« Last Edit: January 28, 2025, 06:00:30 pm by McDoob »

McDoob

  • New Member
  • *
  • Posts: 29
Re: Copying records with dynamic arrays
« Reply #39 on: January 28, 2025, 05:46:46 pm »
Hi
@Zvoni:
Quote
e.g. Index 162
162 Div 80 = 2 --> meaning you are in Row 3 ("Row 0" being the first row)
162 Mod 25 = 12 --> meaning you are in Column 13 ("Column 0" being the first column)
Shouldn't that be:
Quote
e.g. Index 162
162 Div 80 = 2 --> meaning you are in Row 3 ("Row 0" being the first row)
(162 Mod 80) + 1 = 3 --> meaning you are in Column 4 ("Column 0" being the first column)
...or is my math completely wrong, I mean your example will result in 172
Regards benny

OOOOOPPPSSS!!
You're right. My bad.
I blame being winter and all that.....

80 Rows, 25 columns has to be of course
162 Div 25 for rows
162 Mod 25 for columns

If it's the other way round, well then....

Heh, this is exactly the kind of mistake I could see myself making! It's the main reason I'm leery of converting to 1D arrays.
-McD

TRon

  • Hero Member
  • *****
  • Posts: 4139
Re: Copying records with dynamic arrays
« Reply #40 on: January 28, 2025, 07:27:12 pm »
Hey. To be clear, I said 'relative' newbie, not 'complete'!  XD
lol

On a more serious note it is always a guess how far along someone actually is being a newbie as it tends to vary a lot. That and the type of coder you actually are.

Quote
Oof. That's going to take a few reads before I can wrap my head around it. There's a lot of stuff in there I'm not familiar with.
I understand. It is a lot to take in in case not being familiar with it. Don't worry about it too much.

Just for reference: Advanced records aka Extended records and record operators

In case you are familiar with OOP (old style objects, modern objects/classes) then things are a lot easier to grasp as some of the features you are able to find back in advanced records.

Quote
I am at least pretending to maintain good coding practices.  8)
Indeed. Very good of you to do so. It is how I myself approach things as well. At least it prevents my (working) code from turning into a (not working and/or garbled) mess.

From that I also know that taking smaller steps is sometimes requires to wrap your head around some concepts. You would have to figure out for yourself in what time-frame/pace you would like to advance. Too quick will often lead to pitfalls simply because of lacking experience/knowledge and too slow will eventually be able to put you to sleep (which also and often is prone to errors).

In case of questions just ask (as you did).

Quote
EDIT: What's the difference between a 'packed' array and a regular one? And why must Width*Height be less than 128?
Regarding the former:
It is (bad ?) habit of mine. For the theory behind it see arrays for the definition and for how packed actually works see Structured types.

In short it tries to make sure that the data in memory is aligned without any gaps.

Regarding the latter:
The data stored at the location(s) with those dimensions is a character. The stored character starts at space and is increased for each iteration.

Because it is an ASCII character, as soon as the character is increased over 128 times it will not be a valid ASCII character anymore and will eventually output garbage on the terminal.

It is a (deliberate programmed/flawed) limitation of the example.

One of the reasons to do so is that I wanted to proof that once the data is stored inside a single array that the data stored in memory is a continuous stream of data. That way it is for example possible to write out a single line of text in one go, instead of outputting that text one character at a time.

Hopefully that is able to clear up a few things, if not then just let know.
Today is tomorrow's yesterday.

McDoob

  • New Member
  • *
  • Posts: 29
Re: Copying records with dynamic arrays
« Reply #41 on: January 28, 2025, 08:01:28 pm »
Oof. That's going to take a few reads before I can wrap my head around it. There's a lot of stuff in there I'm not familiar with.
I understand. It is a lot to take in in case not being familiar with it. Don't worry about it too much.

Just for reference: Advanced records aka Extended records and record operators

In case you are familiar with OOP (old style objects, modern objects/classes) then things are a lot easier to grasp as some of the features you are able to find back in advanced records.
That's one of my limits. OOP wasn't covered at all back in high school. I will have to work on changing that.
Quote
Quote
I am at least pretending to maintain good coding practices.  8)
Indeed. Very good of you to do so. It is how I myself approach things as well. At least it prevents my (working) code from turning into a (not working and/or garbled) mess.

From that I also know that taking smaller steps is sometimes requires to wrap your head around some concepts. You would have to figure out for yourself in what time-frame/pace you would like to advance. Too quick will often lead to pitfalls simply because of lacking experience/knowledge and too slow will eventually be able to put you to sleep (which also and often is prone to errors).

In case of questions just ask (as you did).
You'd be surprised (or maybe you wouldn't) how many times I screwed up a working project before I got into the habit of making copies. I don't really have a deadline, or specific pace I need to work at. This is all just a hobby at this point. It actually started as a mental exercise to help me get to sleep at night, as I'm a horrible insomniac sometimes.
Quote
Quote
EDIT: What's the difference between a 'packed' array and a regular one? And why must Width*Height be less than 128?
Regarding the former:
It is (bad ?) habit of mine. For the theory behind it see arrays for the definition and for how packed actually works see Structured types.

In short it tries to make sure that the data in memory is aligned without any gaps.

Regarding the latter:
The data stored at the location(s) with those dimensions is a character. The stored character starts at space and is increased for each iteration.

Because it is an ASCII character, as soon as the character is increased over 128 times it will not be a valid ASCII character anymore and will eventually output garbage on the terminal.

It is a (deliberate programmed/flawed) limitation of the example.

One of the reasons to do so is that I wanted to proof that once the data is stored inside a single array that the data stored in memory is a continuous stream of data. That way it is for example possible to write out a single line of text in one go, instead of outputting that text one character at a time.

Hopefully that is able to clear up a few things, if not then just let know.
Thanks for elaborating. I'll have a look at the articles you linked. I had thought there was some problem with the implementation that would prevent me from using a full-size window, with ~2000 elements in Content. Good to know that...once I figure out the rest...I can change it to remove that limit.

I'm actually taking a day off today, to give my mind a chance to digest all this new stuff. It might help me come up with something new at bedtime.
-McDoob

Zvoni

  • Hero Member
  • *****
  • Posts: 2896
Re: Copying records with dynamic arrays
« Reply #42 on: January 29, 2025, 08:15:32 am »
Heh, this is exactly the kind of mistake I could see myself making! It's the main reason I'm leery of converting to 1D arrays.
-McD
There is also a different way to map a 1D to 2D-Array, but AFAIK that only works for Arrays, which members have a clearly defined memory-allocation (have no better word for it-->Ordinals?), like Integer, Byte, Word, Dword etc.

Run the following
Code: Pascal  [Select][+][-]
  1. program Project1;
  2. Uses SysUtils;
  3. Var
  4.   i,j,x:Integer;
  5.   a1:Array[0..99] Of Integer;
  6.   a2:Array[0..9,0..9] Of Integer;
  7.  
  8. begin
  9.   For x:=0  To 99 Do a1[x]:=x;
  10.   Move(a1,a2,Length(a1)*SizeOf(Integer));
  11.   For i:=0 To 9 Do
  12.     Begin
  13.       For j:=0 To 9 Do Write(a2[i,j].ToString+' ');
  14.       Writeln;
  15.     end;
  16.   Readln;
  17. end.

Result
Code: [Select]
0 1 2 3 4 5 6 7 8 9
10 11 12 13 14 15 16 17 18 19
20 21 22 23 24 25 26 27 28 29
30 31 32 33 34 35 36 37 38 39
40 41 42 43 44 45 46 47 48 49
50 51 52 53 54 55 56 57 58 59
60 61 62 63 64 65 66 67 68 69
70 71 72 73 74 75 76 77 78 79
80 81 82 83 84 85 86 87 88 89
90 91 92 93 94 95 96 97 98 99

Line 10 just copies the whole memory-block of the 1D-Array into the Memory-Location of the 2D-Array
No need to run through loops or Div/Mod the position

Note: This only works for NON-dynamic-Arrays (or partially NON-dynamic)

a2:array of array Of Integer---> Doesn't work
a2:Array Of array[0..9] Of Integer --> Works

For partial dynamic Array
Code: Pascal  [Select][+][-]
  1. program Project1;
  2. Var
  3.   i,j,x:Integer;
  4.   a1:Array Of Integer;
  5. //  a1:Array[0..99] Of Integer;
  6.   a2:Array Of Array[0..9] Of Integer;
  7. //  a2:Array[0..9,0..9] Of Integer;
  8.  
  9. begin
  10.   SetLength(a1,100);
  11.   SetLength(a2,10);
  12.   For x:=0  To 99 Do a1[x]:=x;
  13.   Move(a1,a2,Length(a1)*SizeOf(Integer));
  14.   For i:=low(a2[0]) To High(a2[0]) Do
  15.     Begin
  16.       For j:=low(a2[0]) To High(a2[0]) Do Write(a2[i,j],' ');
  17.       Writeln;
  18.     end;
  19.   Readln;
  20. end.
« Last Edit: January 29, 2025, 08:37:01 am by Zvoni »
One System to rule them all, One Code to find them,
One IDE to bring them all, and to the Framework bind them,
in the Land of Redmond, where the Windows lie
---------------------------------------------------------------------
Code is like a joke: If you have to explain it, it's bad

TRon

  • Hero Member
  • *****
  • Posts: 4139
Re: Copying records with dynamic arrays
« Reply #43 on: January 29, 2025, 08:50:56 am »
Line 10 just copies the whole memory-block of the 1D-Array into the Memory-Location of the 2D-Array
No need to run through loops or Div/Mod the position
Nice !

Let's try apply some trickery.

Code: Pascal  [Select][+][-]
  1. var
  2.   a1:Array[0..99] Of Integer;
  3.   a2:Array[0..9,0..9] Of Integer absolute a1;
  4.  

.. and move move out of the window  ;D
« Last Edit: January 29, 2025, 08:52:54 am by TRon »
Today is tomorrow's yesterday.

alpine

  • Hero Member
  • *****
  • Posts: 1372
Re: Copying records with dynamic arrays
« Reply #44 on: January 29, 2025, 10:59:58 am »
There is also a different way to map a 1D to 2D-Array, but AFAIK that only works for Arrays, which members have a clearly defined memory-allocation (have no better word for it-->Ordinals?), like Integer, Byte, Word, Dword etc.
Not applicable since you should fix the 'member' size (screen width) at compile time. This is the only way to have contiguous layout instead of some "woven basket" of intertwined references.
Backward translation from linear to rectangular space (DivMod) isn't needed, it was given for completeness. The contents can be cleared simply with
Code: Pascal  [Select][+][-]
  1. FillChar(Content.data, Length(Content.data), ' ');
"I'm sorry Dave, I'm afraid I can't do that."
—HAL 9000

 

TinyPortal © 2005-2018