unit dstrnum;

{$MODE FPC}
{$MODESWITCH DEFAULTPARAMETERS}
{$MODESWITCH OUT}
{$MODESWITCH RESULT}

interface

uses
  dtypes;

function IntToStr(Value: LongInt): TString;
function UIntToStr(Value: Cardinal): TString;
function StrToInt(const Value: TString): LongInt;
function StrToIntDef(const Value: TString; Def: LongInt): LongInt;
function StrToFloat(const S: TString): Single;
function FloatToStr(F: Single): TString; overload;
function FloatToStr(F: Single; Digitals: LongInt): TString; overload;
function HexToInt(S: TString): LongInt;
function IntToHex(Value: LongInt; Digits: LongInt = 0): TString;
function UintToHex(Value: TUint; Digits: LongInt = 0): TString;
function TryStrToInt(const S: TString; out Value: LongInt): Boolean;
function HexDigitToInt(C: TChar): Byte;

// Input:
//   V -- divident
// Output:
//   V -- quotient  (V / 100)
//   R -- remainder (V % 100)
procedure Div100InPlace(var V: Cardinal; out R: Cardinal); inline;

type
  // Буфер, в который будут сохраняться результаты конвертирования чисел
  // Его длины должно хватать на знаковые и беззнаковые Int64
  TIntConvBuffer = array[0 .. 20] of AnsiChar;
function FastUInt32ToDecimal(Value: Cardinal; var Buf: TIntConvBuffer): PAnsiChar;
function FastInt32ToDecimal(Value: LongInt; var Buf: TIntConvBuffer): PAnsiChar; inline;

type
  TIntBinaryBuffer = array[0 .. 65] of AnsiChar;
procedure FastUInt32ToBinary(Value: Cardinal; Start: PAnsiChar; Count: Cardinal); overload;
function FastUInt32ToBinary(Value: Cardinal; var Buf: TIntBinaryBuffer): PAnsiChar; overload;

type
  TIntToHexBuf = array[0 .. 8] of AnsiChar;
procedure FastUInt32ToHex8(Value: Cardinal; var Buf: TIntToHexBuf);

implementation

function IntToStr(Value: LongInt): TString;
begin
  Str(Value, Result);
end;

function UIntToStr(Value: Cardinal): TString;
begin
  Str(Value, Result);
end;

function StrToInt(const Value: TString): LongInt;
  Var
    Code: LongInt;
begin
  Val(Value, Result, Code);
end;

function StrToIntDef(const Value: TString; Def: LongInt): LongInt;
  Var
    Code: LongInt;
begin
  Val(Value, Result, Code);
  if Code <> 0 then
    Result := Def;
end;

function StrToFloat(const S: TString): Single;
var
  Code: LongInt;
begin
    If Pos('.', S) <> 0 then begin
      //Insert(',', S, Pos('.', S));
      //Delete(S, Pos('.', S), 1);
    end;
  Val(S, Result, Code);
end;

function FloatToStr(F: Single): TString;
begin
  Str(F, Result);
    If Pos(',', Result) <> 0 then begin
      Insert('.', Result, Pos(',', Result));
      Delete(Result, Pos(',', Result), 1);
    end;
end;

function FloatToStr(F: Single; Digitals: LongInt): TString;
begin
  Str(F:0:Digitals, Result);
    If Pos(',', Result) <> 0 then begin
      Insert('.', Result, Pos(',', Result));
      Delete(Result, Pos(',', Result), 1);
    end;
end;

function HexDigitToInt(C: TChar): Byte;
begin
  if C in ['A'..'F'] then
    Result := Ord(C) - Ord('A') + 10
  else if C in ['a'..'f'] then
    Result := Ord(C) - Ord('a') + 10
  else if C in ['0'..'9'] then
    Result := Ord(C) - Ord('0')
  else
    Result := 0;
end;

function HexToInt(S: TString): LongInt;
begin
  Result := 0;
  while Length(S) > 0 do begin
    Result := Result*16 + HexDigitToInt(S[1]);
    Delete(S, 1, 1);
  end;
end;

const
   HexDigits: array[0..15] of TChar = '0123456789ABCDEF';

function IntToHex(Value: LongInt; Digits: LongInt = 0): TString;
begin
  Result := UintToHex(Value, Digits);
end;

function UintToHex(Value: TUint; Digits: LongInt = 0): TString;
  var
    i: LongInt;
begin
 SetLength(result, digits);
 for i := 0 to digits - 1 do
  begin
   result[digits - i] := HexDigits[value and 15];
   value := value shr 4;
  end ;
 while value <> 0 do begin
   result := HexDigits[value and 15] + result;
   value := value shr 4;
 end;
end;

function TryStrToInt(const S: TString; out Value: LongInt): Boolean;
var
  Code: LongInt;
begin
  Val(S, Value, Code);
  Result := Code = 0;
end;

procedure Div100InPlace(var V: Cardinal; out R: Cardinal);
var
  Temp: Cardinal;
begin
  Temp := V div 100;
  R := V - Temp * 100;
  V := Temp;
end;

const
  DIGITS: array[0 .. 200 - 1] of AnsiChar = '00010203040506070809101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899';

function FastUInt32ToDecimal(Value: Cardinal; var Buf: TIntConvBuffer): PAnsiChar;
var
  Index: Cardinal;
begin
  Result := @Buf[High(Buf)];
  Result^ := #0;
  while Value >= 100 do begin
    Div100InPlace(Value, Index);
    Dec(Result, 2);
    Word(Pointer(Result)^) := Word(Pointer(@DIGITS[Index * 2])^);
  end;
  if Value < 10 then begin
    Dec(Result);
    Result^ := AnsiChar(Ord('0') + Value);
    Exit;
  end;
  Dec(Result, 2);
  Word(Pointer(Result)^) := Word(Pointer(@DIGITS[Value * 2])^);
end;

function FastInt32ToDecimal(Value: LongInt; var Buf: TIntConvBuffer): PAnsiChar;
begin
  Result := FastUInt32ToDecimal(Abs(Value), Buf);
  if Value < 0 then begin
    Dec(Result);
    Result^ := '-';
  end;
end;

procedure FastUInt32ToBinary(Value: Cardinal; Start: PAnsiChar; Count: Cardinal);
var
  E: PAnsiChar;
begin
  E := Start + Count - 1;
  while Start < E do begin
    E^ := AnsiChar(48 + (Value and 1));
    Value := Value shr 1;
    Dec(E);
  end;
end;

function FastUInt32ToBinary(Value: Cardinal; var Buf: TIntBinaryBuffer): PAnsiChar;
begin
  Result := @Buf[High(Buf)];
  Result^ := #0;
  {if Value = 0 then begin
    Dec(Result);
    Result^ := '0';
    Exit;
  end;
  while Value > 15 do begin
    Dec(Result);
    Result^ := AnsiChar(Ord('0') + (Value and 1));
    Dec(Result);
    Result^ := AnsiChar(Ord('0') + Ord(Value and 2 <> 0));
    Dec(Result);
    Result^ := AnsiChar(Ord('0') + Ord(Value and 4 <> 0));
    Dec(Result);
    Result^ := AnsiChar(Ord('0') + Ord(Value and 8 <> 0));
    Value := Value shr 4;
  end;}
  repeat
    Dec(Result);
    Result^ := AnsiChar(Ord('0') + (Value and 1));
    Value := Value shr 1;
  until Value = 0;
end;

procedure FastUInt32ToHex8_Half(Value: Cardinal; P: PAnsiChar); inline;
var
  Mask: Cardinal;
begin
  Mask := ((Value + $06060606) and $10101010) shr 4;
  Value := (Value or $30303030) + 39 * Mask;
  //{$IFDEF ENDIAN_BIG}Value := SwapEndian(Value);{$ENDIF}
  P[0] := AnsiChar( Value shr 24);
  P[2] := AnsiChar((Value shr 16) and $FF);
  P[4] := AnsiChar((Value shr  8) and $FF);
  P[6] := AnsiChar( Value         and $FF);
end;

procedure FastUInt32ToHex8(Value: Cardinal; var Buf: TIntToHexBuf);
begin
  FastUInt32ToHex8_Half((Value and $F0F0F0F0) shr 4, @Buf[0]);
  FastUInt32ToHex8_Half( Value and $0F0F0F0F, @Buf[1]);
  Buf[High(Buf)] := #0;
end;

end.
