unit recutils.Optional;
{$mode Delphi}
{$ModeSwitch advancedrecords}
interface
uses
SysUtils, Memory.NilPointer;
type
ENoValueFoundException = class(Exception);
TEmptyOptional = TNilPointer;
{ TOptional }
{$Hints Off}
TOptional<T> = record
private
FHasValue: Boolean;
FValue: T;
class operator Initialize(var a: TOptional<T>); {$IFDEF INLINING}inline;{$ENDIF}
public
function Get: T; {$IFDEF INLINING}inline;{$ENDIF}
function GetOrDefault(const ADefault: T): T; {$IFDEF INLINING}inline;{$ENDIF}
function HasValue: Boolean; {$IFDEF INLINING}inline;{$ENDIF}
constructor Create(constref AValue: T);
class operator Implicit(constref AValue: T): TOptional<T>; {$IFDEF INLINING}inline;{$ENDIF}
class operator Explicit(constref AValue: T): TOptional<T>; {$IFDEF INLINING}inline;{$ENDIF}
class operator Implicit(constref AValue: TNilPointer): TOptional<T>; {$IFDEF INLINING}inline;{$ENDIF}
class operator Explicit(constref AValue: TNilPointer): TOptional<T>; {$IFDEF INLINING}inline;{$ENDIF}
class operator Implicit(constref opt: TOptional<T>): Boolean; {$IFDEF INLINING}inline;{$ENDIF}
class operator Explicit(constref opt: TOptional<T>): Boolean; {$IFDEF INLINING}inline;{$ENDIF}
class operator LogicalNot(constref opt: TOptional<T>): Boolean; {$IFDEF INLINING}inline;{$ENDIF}
class function Empty: TOptional<T>; {$IFDEF INLINING}inline;{$ENDIF} static;
end;
function EmptyOptional: TEmptyOptional;
implementation
{ TOptional }
class operator TOptional<T>.Initialize(var a: TOptional<T>);
begin
a.FHasValue := False;
end;
function TOptional<T>.Get: T;
begin
if not FHasValue then
raise ENoValueFoundException.Create('Optional does not contain any value');
Result := FValue;
end;
function TOptional<T>.GetOrDefault(const ADefault: T): T;
begin
if not FHasValue then
Result := ADefault
else
Result := FValue;
end;
function TOptional<T>.HasValue: Boolean;
begin
Result := FHasValue;
end;
constructor TOptional<T>.Create(constref AValue: T);
begin
FHasValue := True;
FValue := AValue;
end;
class operator TOptional<T>.Implicit(constref AValue: T): TOptional<T>;
begin
Result := TOptional<T>.Create(AValue);
end;
class operator TOptional<T>.Explicit(constref AValue: T): TOptional<T>;
begin
Result := TOptional<T>.Create(AValue);
end;
class operator TOptional<T>.Implicit(constref AValue: TNilPointer): TOptional<T>;
begin
Result := TOptional<T>.Empty;
end;
class operator TOptional<T>.Explicit(constref AValue: TNilPointer): TOptional<T>;
begin
Result := TOptional<T>.Empty;
end;
class operator TOptional<T>.Implicit(constref opt: TOptional<T>): Boolean;
begin
Result := opt.HasValue;
end;
class operator TOptional<T>.Explicit(constref opt: TOptional<T>): Boolean;
begin
Result := opt.HasValue;
end;
class operator TOptional<T>.LogicalNot(constref opt: TOptional<T>): Boolean;
begin
Result := not opt.HasValue;
end;
class function TOptional<T>.Empty: TOptional<T>;
begin
Result.FHasValue := False;
Result.FValue := Default(T);
end;
function EmptyOptional: TEmptyOptional;
begin
Result := nilptr;
end;
end.