unit myGuid;
interface
uses
System.Classes;
type
PmyGUID = ^TmyGUID;
TmyGUID =
record //: 12 Byte / 96 Bit
C : Cardinal;
//: 4 Byte / 32 Bit
TS1: Cardinal;
//: 4 Byte / 32 Bit
TS2: Cardinal;
//: 4 Byte / 32 Bit
class function Create(
const aGuid: PmyGUID): TmyGUID;
overload;
static;
class function Create(
const aGuid:
String): TmyGUID;
overload;
static;
class function Create(
const aGuid: TmyGUID): TmyGUID;
overload;
static;
class function CreateEmpty: TmyGUID;
static;
class function CreateNew: TmyGUID;
static;
class function StringIsValidGuid(
const aGuid:
String): Boolean;
static;
class operator Equal(
const Left, Right: TmyGUID): Boolean;
class operator NotEqual(
const Left, Right: TmyGUID): Boolean;
inline;
function GetHashCode: Integer;
function IsEmpty: Boolean;
function ToString:
String;
procedure DoEmpty;
procedure DoNew;
procedure FromString(
const aGuid:
String);
procedure ReadFromStream(
const aStream: TMemoryStream);
procedure WriteToStream(
const aStream: TMemoryStream);
end;
implementation
uses
System.SysUtils, System.Hash,
Winapi.Windows;
const
MaxCardinal = 4294967295;
var
customTS1: Cardinal = 0;
customTS2: Cardinal = 0;
customC : Cardinal = 0;
{: **************************************** TmyGUID *************************************** :}
{: ---------------------------------------- default --------------------------------------- :}
//: 2023-10-30
class function TmyGUID.Create(
const aGuid:
String): TmyGUID;
begin
if (aGuid <> '
')
then
begin
Result := TmyGUID.CreateEmpty;
Result.FromString(aGuid)
end
else
begin
Result := TmyGUID.CreateNew;
end;
end;
//: 2023-10-30
class function TmyGUID.Create(
const aGuid: TmyGUID): TmyGUID;
begin
Result := aGuid;
end;
//: 2023-10-30
class function TmyGUID.Create(
const aGuid: PmyGUID): TmyGUID;
begin
Result := aGuid^;
end;
//: 2023-10-30
class function TmyGUID.CreateEmpty: TmyGUID;
begin
Result.TS1 := 0;
Result.TS2 := 0;
Result.C := 0;
end;
//: 2023-10-30
class function TmyGUID.CreateNew: TmyGUID;
begin
customTS2 := GetTickCount;
Result.TS1 := customTS1;
Result.TS2 := customTS2;
Result.C := customC;
if (customC = MaxCardinal)
then
customC := 0
else
Inc(customC);
end;
//: 2023-10-30
class function TmyGUID.StringIsValidGuid(
const aGuid:
String): Boolean;
var
I: Integer;
C: Char;
begin
//: #FFFFFFFF-FFFFFFFF-FFFFFFFF
//: 123456789012345678901234567 - > Length = 27
if (Length(aGuid) = 27)
then
begin
Result := True;
for I := 1
to Length(aGuid)
do
begin
C := aGuid[I];
case I
of
1:
if C <> '
#'
then
begin
Result := False;
Break;
end;
10, 19:
if C <> '
-'
then
begin
Result := False;
Break;
end;
else
if not CharInSet(C, ['
0'..'
9', '
A'..'
F'])
then
begin
Result := False;
Break;
end;
end;
end;
end
else
Result := False;
end;
//: 2023-10-30
class operator TmyGUID.Equal(
const Left, Right: TmyGUID): Boolean;
begin
Result := ((Left.TS1 = Right.TS1)
and (Left.TS2 = Right.TS2)
and (Left.C = Right.C));
end;
//: 2023-10-30
class operator TmyGUID.NotEqual(
const Left, Right: TmyGUID): Boolean;
begin
Result := ((Left.TS1 <> Right.TS1)
or (Left.TS2 <> Right.TS2)
or (Left.C <> Right.C));
end;
//: 2023-10-30
function TmyGuid.GetHashCode: Integer;
begin
Result := 17;
Result := Result * 397 + Integer(C);
Result := Result * 397 + THashBobJenkins.GetHashValue(TS1, sizeOf(Cardinal), 5);
Result := Result * 397 + THashBobJenkins.GetHashValue(TS2, sizeOf(Cardinal), 7);
end;
//: 2023-10-30
function TmyGUID.IsEmpty: Boolean;
begin
Result := ((TS1 = 0)
and (Ts2 = 0)
and (C = 0));
end;
function TmyGUID.ToString:
String;
begin
//: #FFFFFFFF-FFFFFFFF-FFFFFFFF
//: 123456789012345678901234567 - > Length = 27
Result := '
#' + TS1.ToHexString + '
-' + TS2.ToHexString + '
-' + C.ToHexString;
end;
//: 2023-10-30
procedure TmyGUID.DoEmpty;
begin
TS1 := 0;
TS2 := 0;
C := 0;
end;
//: 2023-10-30
procedure TmyGUID.DoNew;
var
lGuid: TmyGUID;
begin
lGuid := CreateNew;
TS1 := lGuid.TS1;
TS2 := lGuid.TS2;
C := lGuid.C;
end;
//: 2023-10-30
procedure TmyGUID.FromString(
const aGuid:
String);
begin
//: #FFFFFFFF-FFFFFFFF-FFFFFFFF
//: 123456789012345678901234567 - > Length = 27
if (StringIsValidGuid(aGuid))
then
begin
TS1 := StrToInt('
$' + Copy(aGuid, 2, 8));
TS2 := StrToInt('
$' + Copy(aGuid, 11, 8));
C := StrToInt('
$' + Copy(aGuid, 20, 8));
end
else
begin
TS1 := 0;
Ts2 := 0;
C := 0;
end;
end;
//: 2023-10-30
procedure TmyGUID.ReadFromStream(
const aStream: TMemoryStream);
begin
aStream.ReadData(C);
aStream.ReadData(TS1);
aStream.ReadData(Ts2);
end;
//: 2023-10-30
procedure TmyGUID.WriteToStream(
const aStream: TMemoryStream);
begin
aStream.WriteData(C);
aStream.WriteData(TS1);
aStream.WriteData(Ts2);
end;
initialization
//: 2023-10-30
customTS1 := GetTickCount;
customTS2 := GetTickCount;
customC := 0;
end.