Adding some convinience functions to TNullable

This commit is contained in:
Frederic Kehrein 2024-09-28 14:06:58 +02:00 committed by Michael Van Canneyt
parent 8cacfc3355
commit b5a0c3b1b6
2 changed files with 101 additions and 0 deletions

View File

@ -28,6 +28,8 @@ uses sysutils;
{$ENDIF FPC_DOTTEDUNITS}
Type
TNull = record
end;
{ TNullable }
@ -44,6 +46,10 @@ Type
// Make things more readable
Type
TMyType = specialize TNullable<T>;
// Return if it has value and if so unpack
function Unpack(out aDest: T): Boolean;
// Return value if present, else return fallback
function ValueOr(const Fallback: T): T;
// Clear value, no value present after this.
procedure Clear;
// Is a value present ?
@ -62,9 +68,16 @@ Type
class operator Explicit(aValue: T): TMyType;
class operator Explicit(aValue: TMyType): T;
class operator := (aValue: T): TMyType;
class operator := (aValue: TNull): TMyType;
class operator := (aValue: TMyType): T;
class operator Not (aValue: TMyType): Boolean;
end;
{$Push}
{$WriteableConst Off}
const null: TNull = ();
{$Pop}
implementation
{$IFDEF FPC_DOTTEDUNITS}
@ -110,6 +123,21 @@ begin
FHasValue:=True;
end;
function TNullable.Unpack(out aDest: T): Boolean;
begin
Result := HasValue;
if Result then
aDest := GetValue;
end;
function TNullable.ValueOr(const Fallback: T): T;
begin
if HasValue then
Result := GetValue
else
Result := Fallback;
end;
procedure TNullable.Clear;
begin
HasValue:=False;
@ -143,6 +171,12 @@ begin
Result.Value:=aValue;
end;
class operator TNullable.:=(aValue: TNull): TMyType;
begin
Result := Default(TMyType);
Result.Clear;
end;
class operator TNullable.:= (aValue: TMyType): T;
begin
@ -150,4 +184,9 @@ begin
Result:=aValue.Value;
end;
class operator TNullable.Not(aValue: TMyType): Boolean;
begin
Result := Not aValue.HasValue;
end;
end.

View File

@ -194,6 +194,64 @@ begin
end;
end;
Function TestAssignNull : string;
Var
A : specialize TNullable<String>;
begin
Result:='';
A.Value:=Val1;
If Not A.HasValue then
Exit('Assign not correct');
A := null;
if A.HasValue then
Exit('Null assignement not correct');
end;
Function TestBoolCheck : string;
Var
A : specialize TNullable<String>;
begin
Result:='';
A.Value:=Val1;
If Not A then
Exit('Bool check not correct');
end;
Function TestUnpack : string;
Var
A : specialize TNullable<String>;
B : String;
begin
Result:='';
A.Value:=Val1;
if not A.unpack(B) then
Exit('Unpack return not correct');
If Not (B=Val1) then
Exit('Unpack value not correct');
A.Clear;
if A.unpack(B) then
Exit('Unpack return not correct');
end;
Function TestValueOr : string;
Var
A : specialize TNullable<String>;
B : String;
begin
Result:='';
A.Value:=Val1;
B:=A.ValueOr(Val2);
If Not (B=Val1) then
Exit('ValueOr not correct');
A.Clear;
B:=A.ValueOr(Val2);
If Not (B=Val2) then
Exit('ValueOr not correct');
end;
Procedure DoTest(aTest,aResult : String);
@ -220,5 +278,9 @@ begin
DoTest('TestAssign2',TestAssign2);
DoTest('TestGetEmptyValue',TestGetEmptyValue);
DoTest('TestGetEmptyValueOrDefault',TestGetEmptyValueOrDefault);
DoTest('TestAssignNull',TestAssignNull);
DoTest('TestBoolCheck',TestBoolCheck);
DoTest('TestUnpack',TestUnpack);
DoTest('TestValueOr',TestValueOr);
end.