How to quickly convert an array of numeric characters to an integer?

Situation: An integer stored as hex in an array of bytes (TBytes). Convert this number to enter an integer with fewer copies, if possible, without copying.

here is an example:

array = ($35, $36, $37);

This is '5', '6', '7' in ansi. How to convert it to 567 (= $ 273) with less problems?

I did this by copying twice. Is it possible to do faster? How?

+3
source share
4 answers

You can use the LookUp table instead of HexToInt ...

This procedure only works with AnsiChars, and of course, error checking is not provided!

var
  Table        :array[byte]of byte;

procedure InitLookupTable;
var
  n:            integer;
begin
  for n := 0 to Length(Table) do
    case n of
      ord('0')..ord('9'): Table[n] := n - ord('0');
      ord('A')..ord('F'): Table[n] := n - ord('A') + 10;
      ord('a')..ord('f'): Table[n] := n - ord('a') + 10;
    else Table[n] := 0;
    end;
end;

function HexToInt(var hex: TBytes): integer;
var
  n:            integer;
begin
  result := 0;
  for n := 0 to Length(hex) -1 do
    result := result shl 4 + Table[ord(hex[n])];
end;
+1
source
function BytesToInt(const bytes: TBytes): integer;
var
  i: integer;
begin
  result := 0;
  for i := 0 to high(bytes) do
    result := (result shl 4) + HexToInt(bytes[i]);
end;

PA, , , . HexToInt ​​ , .

0

You can do

function CharArrToInteger(const Arr: TBytes): integer;
var
  s: AnsiString;
begin
  SetLength(s, length(Arr));
  Move(Arr[0], s[1], length(s));
  result := StrToInt(s);
end;

procedure TForm1.FormCreate(Sender: TObject);
var
  a: TBytes;
begin
  a := TBytes.Create($35, $36, $37);
  Caption := IntToStr(CharArrToInteger(a));
end;

If you know that the string ends with zero, that is, if the ending character in the array is 0, you can simply do

function CharArrToInteger(const Arr: TBytes): integer;
begin
  result := StrToInt(PAnsiChar(@Arr[0]));
end;

procedure TForm1.FormCreate(Sender: TObject);
var
  a: TBytes;
begin
  a := TBytes.Create($35, $36, $37, 0);
  Caption := IntToStr(CharArrToInteger(a));
end;

The most natural approach, however, is to use an array of characters instead of an array of bytes! Then the compiler can do some tricks for you:

procedure TForm1.FormCreate(Sender: TObject);
var
  a: TCharArray;
begin
  a := TCharArray.Create(#$35, #$36, #$37);
  Caption := IntToStr(StrToInt(string(a)));
end;
0
source

It cannot be faster than this; -)

function HexToInt(num:pointer; size:Cardinal): UInt64;
var i: integer;
    inp: Cardinal absolute num;
begin
  if(size > SizeOf(Result)) then Exit;
  result := 0;
  for i := 0 to size-1 do begin
    result := result shl 4;
    case(PByte(inp+i)^) of
      ord('0')..ord('9'): Inc(Result, PByte(inp+i)^ - ord('0'));
      ord('A')..ord('F'): Inc(Result, PByte(inp+i)^ - ord('A') + 10);
      ord('a')..ord('f'): Inc(Result, PByte(inp+i)^ - ord('a') + 10);
    end;
  end;
end;
function fHexToInt(b:TBytes): UInt64; inline;
begin
  Result:=HexToInt(@b[0], Length(b));
end;

...
b:TBytes = ($35, $36, $37);
HexToInt(@b[0], 3);
fHexToInt(b);
0
source

Source: https://habr.com/ru/post/1795095/


All Articles