### Bookstore

 Computer Math and Games in Pascal (preview) Lazarus Handbook

### Author Topic: [SOLVED]How to convert an Integer Array to a Byte Array use the same memory?  (Read 9068 times)

#### tomitomy

• Full Member
• Posts: 234
##### [SOLVED]How to convert an Integer Array to a Byte Array use the same memory?
« on: October 09, 2017, 06:36:45 am »

Code: Pascal  [Select][+][-]
1. function GetIntFromBytes(index: integer; bytes: TBytes): integer;
2. begin
3.   Result := PInteger(@bytes[index * Sizeof(integer)])^;
4. end;
5.
6. procedure SetIntToBytes(index: integer; bytes: TBytes; data: integer);
7. begin
8.   PInteger(@bytes[index * Sizeof(integer)])^ := data;
9. end;
10.
11. function CountIntsInBytes(bytes: TBytes): integer;
12. begin
13.   Result := Length(bytes) div Sizeof(integer);
14. end;
15.
16. function InsertIntIntoBytes(data: integer; refData: integer; bytes: TBytes;
17.   before: boolean = True): TBytes;
18. var
19.   i, j: integer;
20. begin
21.   // Get insert point
22.   for i := 0 to CountIntsInBytes(bytes) - 1 do
23.     if GetIntFromBytes(i, bytes) = refData then
24.       Break;
25.   // Resize TBytes
26.   SetLength(bytes, (CountIntsInBytes(bytes) + 1) * Sizeof(integer));
27.   // Move data
28.   if not before then
29.     i := i + 1;
30.   for j := CountIntsInBytes(bytes) - 1 downto i + 1 do
31.     SetIntToBytes(j, bytes, GetIntFromBytes(j - 1, bytes));
32.   // Insert data
33.   SetIntToBytes(i, bytes, data);
34.   Result := bytes;
35. end;
36.
37. procedure Test;
38. var
39.   i: integer;
40.   bytes: TBytes;
41. begin
42.   bytes := InsertIntIntoBytes(1, 0, bytes);
43.   bytes := InsertIntIntoBytes(2, 1, bytes);
44.   bytes := InsertIntIntoBytes(3, 1, bytes);
45.   bytes := InsertIntIntoBytes(4, 1, bytes, False);
46.   bytes := InsertIntIntoBytes(5, 1, bytes, False);
47.   for i := 0 to CountIntsInBytes(bytes) - 1 do
48.     ShowMessage(IntToStr(GetIntFromBytes(i, bytes)));
49. end;

------------------------------------------------------------

Can I speak Chinese here? My English is poor.

I want to put an integer array into a database, but the database only accept TBytes, how to convert an integer array into a byte array?

In order to improve read and write speed, I do not want to allocate new memory, but direct use the momory of integer array, which can be achieved?

My current practice is to read and write integers directly in TBytes, but this code is not clear, it is difficult to read, is there a better way?

Here's my practice:

Code: Pascal  [Select][+][-]
1. function GetIntFromBytes(index: integer; bytes: TBytes): integer;
2. begin
3.   Result := PInteger(@bytes[index * Sizeof(integer)])^;
4. end;
5.
6. procedure SetIntToBytes(index: integer; bytes: TBytes; data: integer);
7. begin
8.   PInteger(@bytes[index * Sizeof(integer)])^ := data;
9. end;
10.
11. function CountIntsInBytes(bytes: TBytes): integer;
12. begin
13.   Result := Length(bytes) div Sizeof(integer);
14. end;
15.
16. function InsertIntIntoBytes(data: integer; refData: integer; bytes: TBytes;
17.   before: boolean = True): TBytes;
18. var
19.   i, j: integer;
20. begin
21.   // Get insert point
22.   for i := 0 to CountIntsInBytes(bytes) - 1 do
23.     if GetIntFromBytes(i, bytes) = refData then
24.       Break;
25.   // Resize TBytes
26.   SetLength(bytes, (CountIntsInBytes(bytes) + 1) * Sizeof(integer));
27.   // Move data
28.   if not before then
29.     i := i + 1;
30.   for j := CountIntsInBytes(bytes) - 1 downto i + 1 do
31.     SetIntToBytes(j, bytes, GetIntFromBytes(j - 1, bytes));
32.   // Insert data
33.   SetIntToBytes(i, bytes, data);
34.   Result := bytes;
35. end;
36.
37. procedure Test;
38. var
39.   i: integer;
40.   bytes: TBytes;
41. begin
42.   bytes := InsertIntIntoBytes(1, 0, bytes);
43.   bytes := InsertIntIntoBytes(2, 1, bytes);
44.   bytes := InsertIntIntoBytes(3, 1, bytes);
45.   bytes := InsertIntIntoBytes(4, 1, bytes, False);
46.   bytes := InsertIntIntoBytes(5, 1, bytes, False);
47.   for i := 0 to CountIntsInBytes(bytes) - 1 do
48.     ShowMessage(IntToStr(GetIntFromBytes(i, bytes)));
49. end;
« Last Edit: October 12, 2017, 12:30:13 pm by tomitomy »

#### taazz

• Hero Member
• Posts: 5365
##### Re: How to convert an integer array to a byte array use the same memory?
« Reply #1 on: October 09, 2017, 08:11:47 am »
tbytes is a dynamic array that means that the length and size of the array are managed internally with hidden fields it is impossible to cast one dynamic array to an other and have the rtl function properly, it might be easier to extend the database component to support a pbyte and a length parameter instead of a tbytes.
Good judgement is the result of experience … Experience is the result of bad judgement.

OS : Windows 7 64 bit
Laz: Lazarus 1.4.4 FPC 2.6.4 i386-win32-win32/win64

• Hero Member
• Posts: 10716
##### Re: How to convert an integer array to a byte array use the same memory?
« Reply #2 on: October 09, 2017, 09:25:16 am »
As long as the size of the integer is known (2,4,8? bytes) Simply cast it or use absolute.
example:
Code: Pascal  [Select][+][-]
1. program program1;
2. var
3.   a:array[0..9] of integer = (0,1,2,3,4,5,6,7,8,9);
4.   b:array[0..9*SizeOf(Integer)] of byte absolute a;
5.   c:byte;
6. begin
7.   for c in b do writeln(c);// should write some extra zeros depending on int size and compiler mode...
8. end.
9.

- A standard compile will write one extra zero (integer =16 bit = 2 bytes in TP or default mode)
- Mode Delphi or ObjFPC will write 3 extra zero's (integer = 32 bit = 4 )
« Last Edit: October 09, 2017, 11:22:44 am by Thaddy »

#### tomitomy

• Full Member
• Posts: 234
##### Re: How to convert an integer array to a byte array use the same memory?
« Reply #3 on: October 09, 2017, 11:26:25 am »
tbytes is a dynamic array that means that the length and size of the array are managed internally with hidden fields it is impossible to cast one dynamic array to an other and have the rtl function properly, it might be easier to extend the database component to support a pbyte and a length parameter instead of a tbytes.

I do not know how to implement, is there a sample code?

• Hero Member
• Posts: 10716
##### Re: How to convert an integer array to a byte array use the same memory?
« Reply #4 on: October 09, 2017, 11:33:20 am »
tbytes is a dynamic array that means that the length and size of the array are managed internally with hidden fields it is impossible to cast one dynamic array to an other and have the rtl function properly, it might be easier to extend the database component to support a pbyte and a length parameter instead of a tbytes.

I do not know how to implement, is there a sample code?
Yes, but for your purpose you should not use TBytes. See my example for sharing an integer and a byte array in the exact same memory.
That can not be guaranteed with a dynamic array (they can be relocated...).

Usually I use absolute if array size is known.

@Taazz plz read subject! A better way is maybe a variant record with an array of integer and an array of byte.... He needs the same memory, w/o copy.
Code: Pascal  [Select][+][-]
1. program program1;
2. {\$mode fpc}
3. var
4.   overlay: packed record
5.   case boolean of
6.     false:(a:array[0..9] of integer);
7.     true :(b:array[0..9*SizeOf(Integer)] of byte);
8.   end;
9. begin
10. overlay.a[0]:=1;
11. writeln(overlay.b[0],#9,overlay.b[1]);
12.
13. overlay.a[0]:=256;
14. writeln(overlay.b[0],#9,overlay.b[1]);
15.
16. end.

Same can be done with pointers, of course, but that is an excercise.
« Last Edit: October 09, 2017, 11:57:52 am by Thaddy »

#### tomitomy

• Full Member
• Posts: 234
##### Re: How to convert an integer array to a byte array use the same memory?
« Reply #5 on: October 09, 2017, 12:00:03 pm »
tbytes is a dynamic array that means that the length and size of the array are managed internally with hidden fields it is impossible to cast one dynamic array to an other and have the rtl function properly, it might be easier to extend the database component to support a pbyte and a length parameter instead of a tbytes.

I do not know how to implement, is there a sample code?
Yes, but for your purpose you should not use TBytes. See my example for sharing an integer and a byte array in the exact same memory.
That can not be guaranteed with a dynamic array (they can be relocated...).

@Taazz plz read subject! A better way is maybe a variant record with an array of integer and an array of byte.... He needs the same memory, w/o copy.

But my integer array is a dynamic array, I need to dynamically add and delete elements, and I want write it to a SQLite database, if I don't use TBytes, I don't know how to write it to the database.
« Last Edit: October 09, 2017, 12:03:38 pm by tomitomy »

#### taazz

• Hero Member
• Posts: 5365
##### Re: How to convert an integer array to a byte array use the same memory?
« Reply #6 on: October 09, 2017, 12:02:04 pm »
tbytes is a dynamic array that means that the length and size of the array are managed internally with hidden fields it is impossible to cast one dynamic array to an other and have the rtl function properly, it might be easier to extend the database component to support a pbyte and a length parameter instead of a tbytes.

I do not know how to implement, is there a sample code?
I need to see the code that uses the TBytes in order to provide a sample.
Good judgement is the result of experience … Experience is the result of bad judgement.

OS : Windows 7 64 bit
Laz: Lazarus 1.4.4 FPC 2.6.4 i386-win32-win32/win64

#### tomitomy

• Full Member
• Posts: 234
##### Re: How to convert an integer array to a byte array use the same memory?
« Reply #7 on: October 09, 2017, 12:51:20 pm »
tbytes is a dynamic array that means that the length and size of the array are managed internally with hidden fields it is impossible to cast one dynamic array to an other and have the rtl function properly, it might be easier to extend the database component to support a pbyte and a length parameter instead of a tbytes.

I do not know how to implement, is there a sample code?
I need to see the code that uses the TBytes in order to provide a sample.

this is my code (Simplified):

Code: Pascal  [Select][+][-]
1. unit Unit1;
2.
3. {\$mode objfpc}{\$H+}
4.
5. interface
6.
7. uses
8.   Classes, SysUtils, FileUtil, Forms, Controls, Graphics, Dialogs, sqlite3conn, sqldb;
9.
10. type
11.   TTestDB = class(TObject)
12.     SQLConn: TSQLite3Connection;
13.     SQLQuery: TSQLQuery;
14.     SQLTran: TSQLTransaction;
15.   private
16.     procedure CreateTable;
17.   public
18.     constructor Create;
19.     destructor Destroy; override;
20.
21.     function OpenDB(FileName: string): boolean;
22.     procedure CloseDB(Save: boolean = True);
23.
24.     function GetData(ID: integer): TBytes;
25.     procedure SetData(ID: integer; Data: TBytes);
26.
27.     function NewRecord(Data: TBytes): integer;
28.   end;
29.
30.   { TForm1 }
31.
32.   TForm1 = class(TForm)
33.     procedure FormCreate(Sender: TObject);
34.   end;
35.
36. var
37.   Form1: TForm1;
38.
39. implementation
40.
41. {\$R *.lfm}
42.
43. procedure Test;
44. var
45.   FileName: string;
46.   bytes: TBytes;
47.   TestDB: TTestDB;
48.   i: integer;
49. begin
50.   FileName := ExtractFilePath(Application.ExeName);
51.   FileName := ConcatPaths([FileName, 'test.db']);
52.   DeleteFile(FileName);
53.   TestDB := TTestDB.Create;
54.   TestDB.OpenDB(FileName);
55.   SetLength(bytes, 5 * sizeof(integer));
56.   for i := 0 to 4 do
57.     PInteger(@bytes[i * Sizeof(integer)])^ := i + 1;
58.   // Write
59.   TestDB.NewRecord(bytes);
61.   bytes := TestDB.GetData(1);
62.   for i := 0 to 4 do
63.   begin
64.     ShowMessage(IntToStr(PInteger(@bytes[i * Sizeof(integer)])^));
65.   end;
66. end;
67.
68. procedure TForm1.FormCreate(Sender: TObject);
69. begin
70.   Test;
71. end;
72.
73. constructor TTestDB.Create;
74. var
75.   LibFile: string;
76.   AppPath: string;
77. begin
78.   inherited Create;
79.   SQLConn := TSQLite3Connection.Create(nil);
80.   SQLTran := TSQLTransaction.Create(nil);
81.   SQLQuery := TSQLQuery.Create(nil);
82.
83.   SQLConn.Transaction := SQLTran;
84.   SQLTran.DataBase := SQLConn;
85.   SQLQuery.DataBase := SQLConn;
86.
87.   AppPath := ExtractFilePath(Application.ExeName);
88. {\$ifdef MSWINDOWS}
89.   LibFile := ConcatPaths([AppPath, 'lib', 'sqlite3.dll']);
90. {\$else}
91.   LibFile := ConcatPaths([AppPath, 'lib', 'libsqlite3.so']);
92. {\$endif}
93.   if FileExists(LibFile) then
94.     SQLiteLibraryName := LibFile;
95. end;
96.
97. destructor TTestDB.Destroy;
98. begin
99.   FreeAndNil(SQLQuery);
100.   FreeAndNil(SQLTran);
101.   FreeAndNil(SQLConn);
102.   inherited Destroy;
103. end;
104.
105. procedure TTestDB.CreateTable;
106. begin
107.   SQLConn.ExecuteDirect('Create Table "main"("data" Blob);');
108. end;
109.
110. function TTestDB.OpenDB(FileName: string): boolean;
111. begin
112.   SQLConn.DatabaseName := FileName;
113.   SQLConn.Open;
114.   SQLTran.Active := True;
115.   CreateTable;
116. end;
117.
118. procedure TTestDB.CloseDB(Save: boolean = True);
119. begin
120.   if SQLTran.Active then
121.     if Save then
122.       SQLTran.Commit
123.     else
124.       SQLTran.Rollback;
125.   SQLConn.Close(True);
126. end;
127.
128. function TTestDB.NewRecord(Data: TBytes): integer;
129. begin
130.   SQLQuery.SQL.Text :=
131.     'Insert Into main (data) Values (:data)';
132.   SQLQuery.Params.ParamByName('data').AsBytes := Data;
133.   SQLQuery.ExecSQL;
134.   SQLQuery.SQL.Text := 'Select last_insert_rowid() From main';
135.   SQLQuery.Open;
136.   Result := SQLQuery.Fields[0].AsInteger;
137.   SQLQuery.Close;
138. end;
139.
140. function TTestDB.GetData(ID: integer): TBytes;
141. begin
142.   SQLQuery.SQL.Text := 'Select data From main where rowid=:rowid';
143.   SQLQuery.Params.ParamByName('rowid').AsInteger := ID;
144.   SQLQuery.Open;
145.   Result := SQLQuery.Fields[0].AsBytes;
146.   SQLQuery.Close;
147. end;
148.
149. procedure TTestDB.SetData(ID: integer; Data: TBytes);
150. begin
151.   SQLQuery.SQL.Text := 'Update main Set data=:data Where rowid=:rowid';
152.   SQLQuery.Params.ParamByName('data').AsBytes := Data;
153.   SQLQuery.Params.ParamByName('rowid').AsInteger := ID;
154.   SQLQuery.ExecSQL;
155. end;
156.
157. end.

#### taazz

• Hero Member
• Posts: 5365
##### Re: How to convert an integer array to a byte array use the same memory?
« Reply #8 on: October 09, 2017, 10:12:39 pm »
tbytes is a dynamic array that means that the length and size of the array are managed internally with hidden fields it is impossible to cast one dynamic array to an other and have the rtl function properly, it might be easier to extend the database component to support a pbyte and a length parameter instead of a tbytes.

I do not know how to implement, is there a sample code?
I need to see the code that uses the TBytes in order to provide a sample.

this is my code (Simplified):

Code: Pascal  [Select][+][-]
1. unit Unit1;
2.
3. {\$mode objfpc}{\$H+}
4.
5. interface
6.
7. uses
8.   Classes, SysUtils, FileUtil, Forms, Controls, Graphics, Dialogs, sqlite3conn, sqldb;
9.
10. type
11.   TTestDB = class(TObject)
12.     SQLConn: TSQLite3Connection;
13.     SQLQuery: TSQLQuery;
14.     SQLTran: TSQLTransaction;
15.   private
16.     procedure CreateTable;
17.   public
18.     constructor Create;
19.     destructor Destroy; override;
20.
21.     function OpenDB(FileName: string): boolean;
22.     procedure CloseDB(Save: boolean = True);
23.
24.     function GetData(ID: integer): TBytes;
25.     procedure SetData(ID: integer; Data: TBytes);
26.
27.     function NewRecord(Data: TBytes): integer;
28.   end;
29.
30.   { TForm1 }
31.
32.   TForm1 = class(TForm)
33.     procedure FormCreate(Sender: TObject);
34.   end;
35.
36. var
37.   Form1: TForm1;
38.
39. implementation
40.
41. {\$R *.lfm}
42.
43. procedure Test;
44. var
45.   FileName: string;
46.   bytes: TBytes;
47.   TestDB: TTestDB;
48.   i: integer;
49. begin
50.   FileName := ExtractFilePath(Application.ExeName);
51.   FileName := ConcatPaths([FileName, 'test.db']);
52.   DeleteFile(FileName);
53.   TestDB := TTestDB.Create;
54.   TestDB.OpenDB(FileName);
55.   SetLength(bytes, 5 * sizeof(integer));
56.   for i := 0 to 4 do
57.     PInteger(@bytes[i * Sizeof(integer)])^ := i + 1;
58.   // Write
59.   TestDB.NewRecord(bytes);
61.   bytes := TestDB.GetData(1);
62.   for i := 0 to 4 do
63.   begin
64.     ShowMessage(IntToStr(PInteger(@bytes[i * Sizeof(integer)])^));
65.   end;
66. end;
67.
68. procedure TForm1.FormCreate(Sender: TObject);
69. begin
70.   Test;
71. end;
72.
73. constructor TTestDB.Create;
74. var
75.   LibFile: string;
76.   AppPath: string;
77. begin
78.   inherited Create;
79.   SQLConn := TSQLite3Connection.Create(nil);
80.   SQLTran := TSQLTransaction.Create(nil);
81.   SQLQuery := TSQLQuery.Create(nil);
82.
83.   SQLConn.Transaction := SQLTran;
84.   SQLTran.DataBase := SQLConn;
85.   SQLQuery.DataBase := SQLConn;
86.
87.   AppPath := ExtractFilePath(Application.ExeName);
88. {\$ifdef MSWINDOWS}
89.   LibFile := ConcatPaths([AppPath, 'lib', 'sqlite3.dll']);
90. {\$else}
91.   LibFile := ConcatPaths([AppPath, 'lib', 'libsqlite3.so']);
92. {\$endif}
93.   if FileExists(LibFile) then
94.     SQLiteLibraryName := LibFile;
95. end;
96.
97. destructor TTestDB.Destroy;
98. begin
99.   FreeAndNil(SQLQuery);
100.   FreeAndNil(SQLTran);
101.   FreeAndNil(SQLConn);
102.   inherited Destroy;
103. end;
104.
105. procedure TTestDB.CreateTable;
106. begin
107.   SQLConn.ExecuteDirect('Create Table "main"("data" Blob);');
108. end;
109.
110. function TTestDB.OpenDB(FileName: string): boolean;
111. begin
112.   SQLConn.DatabaseName := FileName;
113.   SQLConn.Open;
114.   SQLTran.Active := True;
115.   CreateTable;
116. end;
117.
118. procedure TTestDB.CloseDB(Save: boolean = True);
119. begin
120.   if SQLTran.Active then
121.     if Save then
122.       SQLTran.Commit
123.     else
124.       SQLTran.Rollback;
125.   SQLConn.Close(True);
126. end;
127.
128. function TTestDB.NewRecord(Data: TBytes): integer;
129. begin
130.   SQLQuery.SQL.Text :=
131.     'Insert Into main (data) Values (:data)';
132.   SQLQuery.Params.ParamByName('data').AsBytes := Data;
133.   SQLQuery.ExecSQL;
134.   SQLQuery.SQL.Text := 'Select last_insert_rowid() From main';
135.   SQLQuery.Open;
136.   Result := SQLQuery.Fields[0].AsInteger;
137.   SQLQuery.Close;
138. end;
139.
140. function TTestDB.GetData(ID: integer): TBytes;
141. begin
142.   SQLQuery.SQL.Text := 'Select data From main where rowid=:rowid';
143.   SQLQuery.Params.ParamByName('rowid').AsInteger := ID;
144.   SQLQuery.Open;
145.   Result := SQLQuery.Fields[0].AsBytes;
146.   SQLQuery.Close;
147. end;
148.
149. procedure TTestDB.SetData(ID: integer; Data: TBytes);
150. begin
151.   SQLQuery.SQL.Text := 'Update main Set data=:data Where rowid=:rowid';
152.   SQLQuery.Params.ParamByName('data').AsBytes := Data;
153.   SQLQuery.Params.ParamByName('rowid').AsInteger := ID;
154.   SQLQuery.ExecSQL;
155. end;
156.
157. end.
The only thing you can do is to convert your data to TBytes or to a string and pass that to the parameter. I would recomend converting it to a string, for the correct procedure of doing so see the method TParam.GetAsString in the db unit, because this is done for your data internally when you execute it, this way you avoid a 3 way convertion.
Good judgement is the result of experience … Experience is the result of bad judgement.

OS : Windows 7 64 bit
Laz: Lazarus 1.4.4 FPC 2.6.4 i386-win32-win32/win64

#### tomitomy

• Full Member
• Posts: 234
##### Re: How to convert an integer array to a byte array use the same memory?
« Reply #9 on: October 10, 2017, 07:34:52 am »

I don't want allocate new memory, so i don't want to convert my data to another type, I just want to use the same memory of my data.

now, with your help, I have two ways to meet my needs, the one is only use 'absolute', another is change the hidden field which stone the length of the array.

method 1 (only use 'absolute'):

Code: Pascal  [Select][+][-]
1. type
2.   TInts = array of integer;
3.
4. procedure Test;
5. var
6.   FileName: string;
7.   TestDB: TTestDB;
8.   i: integer;
9.   bytes: TBytes;
10.   ints: TInts absolute bytes;
11.   HighInt: integer;
12. begin
13.   FileName := ExtractFilePath(Application.ExeName);
14.   FileName := ConcatPaths([FileName, 'test.db']);
15.   DeleteFile(FileName);
16.   TestDB := TTestDB.Create;
17.   TestDB.OpenDB(FileName);
18.
19.   // Initialize Ints
20.   HighInt := 4;
21.   // don't use SetLength(ints, HighInt +1)
22.   // Bytes are larger in length than ints, they are use the same length field.
23.   SetLength(bytes, (HighInt + 1) * sizeof(integer));
24.   for i := Low(Ints) to HighInt do
25.     Ints[i] := i + 1;
26.   // Write Ints
27.   TestDB.NewRecord(bytes);
28.   // Clear Ints
29.   SetLength(Ints,0);
31.   bytes := TestDB.GetData(1);
32.   for i := Low(Ints) to HighInt do
33.   begin
34.     ShowMessage(IntToStr(Ints[i]));
35.   end;
36. end;

method 2 (change the hidden field):

Code: Pascal  [Select][+][-]
1. type
2.   TInts = array of integer;
3.
4. function IntsToBytes(ints: TInts):TBytes;
5. var
6.   bytes: TBytes absolute ints;
7.   p: PQword;
8. begin
9.   // Get hidden field address
10.   p := @ints[0];
11.   Dec(p);
12.   // Change hidden field
13.   p^ := Length(Ints) * Sizeof(integer) - 1;
14.   Result := bytes;
15. end;
16.
17. function BytesToInts(bytes: TBytes):TInts;
18. var
19.   ints: TInts absolute bytes;
20.   p: PQword;
21. begin
22.   // Get hidden field address
23.   p := @ints[0];
24.   Dec(p);
25.   // Change hidden field
26.   p^ := Length(bytes) div Sizeof(integer) - 1;
27.   Result := ints;
28. end;
29.
30. procedure Test;
31. var
32.   FileName: string;
33.   TestDB: TTestDB;
34.   i: integer;
35.   ints: TInts;
36. begin
37.   FileName := ExtractFilePath(Application.ExeName);
38.   FileName := ConcatPaths([FileName, 'test.db']);
39.   DeleteFile(FileName);
40.   TestDB := TTestDB.Create;
41.   TestDB.OpenDB(FileName);
42.
43.   // Initialize Ints
44.   SetLength(ints, 5);
45.   for i := Low(Ints) to High(ints) do
46.     Ints[i] := i + 1;
47.   // Write Ints
48.   TestDB.NewRecord(IntsToBytes(Ints));
49.   // Clear Ints
50.   SetLength(Ints,0);
52.   Ints := BytesToInts(TestDB.GetData(1));
53.   for i := Low(Ints) to High(ints) do
54.   begin
55.     ShowMessage(IntToStr(Ints[i]));
56.   end;
57. end;

I don't know if the second method is correct, but it can work properly.
« Last Edit: October 10, 2017, 07:38:11 am by tomitomy »

#### ASerge

• Hero Member
• Posts: 1758
##### Re: How to convert an integer array to a byte array use the same memory?
« Reply #10 on: October 11, 2017, 12:05:18 am »
I don't know if the second method is correct, but it can work properly.
A little safer with the test:
Code: Pascal  [Select][+][-]
1. {\$APPTYPE CONSOLE}
2. {\$MODE OBJFPC}
3. program project1;
4.
5. uses SysUtils;
6.
7. function GetArrHigh(P: Pointer): PDynArrayIndex; inline;
8. begin
9.   Result := P - SizeOf(IntPtr);  // See TDynArray in dynarr.inc
10. end;
11.
12. function IntsToBytes(const Ints: TBoundArray): TBytes;
13. begin
14.   if Assigned(Ints) then
15.     GetArrHigh(@Ints[0])^ := Length(Ints) * SizeOf(Ints[0]) - 1;
16.   Result := TBytes(Ints);
17. end;
18.
19. function BytesToInts(const Bytes: TBytes): TBoundArray;
20. begin
21.   if Assigned(Bytes) then
22.     GetArrHigh(@Bytes[0])^ := Length(Bytes) div SizeOf(TBoundArray[0]) - 1;
23.   Result := TBoundArray(Bytes);
24. end;
25.
26. procedure PrintInts(const Ints: TBoundArray);
27. var
28.   i: Integer;
29. begin
30.   Write(Format('Ints  %p: ', [@Ints[0]]));
31.   for i := Low(Ints) to High(Ints) do
32.     Write(Ints[i], ' ');
33.   Writeln;
34. end;
35.
36. procedure PrintBytes(const Bytes: TBytes);
37. var
38.   i: Integer;
39. begin
40.   Write(Format('Bytes %p: ', [@Bytes[0]]));
41.   for i := Low(Bytes) to High(Bytes) do
42.     Write(Bytes[i], ' ');
43.   Writeln;
44. end;
45.
46. procedure Test;
47. var
48.   Ints: TBoundArray;
49.   Bytes: TBytes;
50.   i: Integer;
51. begin
52.   SetLength(Ints, 5);
53.   for i := Low(Ints) to High(ints) do
54.     Ints[i] := i + 1;
55.   PrintInts(Ints);
56.   Bytes := IntsToBytes(Ints);
57.   //Ints := nil;
58.   PrintBytes(Bytes);
59.   Ints := BytesToInts(Bytes);
60.   //Bytes := nil;
61.   PrintInts(Ints);
62. end;
63.
64. begin
65.   Test;