Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Can I convert a buffer + size to TBytes?

Tags:

delphi

Given a buffer and its size in bytes, is there a way to convert this to TBytes without copying it?

Example:

procedure HandleBuffer(_Buffer: PByte; _BufSize: integer);
var
  Arr: TBytes;
  i: Integer;
begin
  // some clever code here to get contents of the buffer into the Array
  for i := 0 to Length(Arr)-1 do begin
    HandleByte(Arr[i]);
  end;
end;

I could of course copy the data:

procedure HandleBuffer(_Buffer: PByte; _BufSize: integer);
var
  Arr: TBytes;
  i: Integer;
begin
  // this works but is very inefficient
  SetLength(Arr, _BufSize);
  Move(PByte(_Buffer)^, Arr[0], _BufSize);
  //
  for i := 0 to Length(Arr)-1 do begin
    HandleByte(Arr[i]);
  end;
end;

But for a large buffer (about a hundred megabytes) this would mean I have double the memory requirement and also spend a lot of time unnecessarily copying data.

I am aware that I could simply use a PByte to process each byte in the buffer, I'm only interested in a solution to use a TBytes instead.

I think it's not possible, but I have been wrong before.

like image 753
dummzeuch Avatar asked Oct 14 '20 12:10

dummzeuch


1 Answers

No, this is not possible (without unreasonable hacks).

The problem is that TBytes = TArray<Byte> = array of Byte is a dynamic array and the heap object for a non-empty dynamic array has a header containing the array's reference count and length.

A function that accepts a TBytes parameter, when given a plain pointer to an array of bytes, might (rightfully) attempt to read the (non-existing) header, and then you are in serious trouble.

Also, dynamic arrays are managed types (as indicated by the reference count I mentioned), so you might have problems with that as well.


However, in your particular example code, you don't actually use the dynamic array nature of the data at all, so you can work directly with the buffer:

procedure HandleBuffer(_Buffer: PByte; _BufSize: integer);
var
  i: Integer;
begin
  for i := 0 to _BufSize - 1 do
    HandleByte(_Buffer[i]);
end;
like image 186
Andreas Rejbrand Avatar answered Nov 13 '22 08:11

Andreas Rejbrand