[fpc-pascal] Primitive Record Wrappers

Mazola Winstrol mazofeifer at gmail.com
Sat Feb 27 18:49:59 CET 2016


I've implemented a new version. For this version i created a mock class to
use with FHasValue (the previous implementation uses a hack to the
interface internal layout).


unit NullableTypes;

{$mode delphi}{$H+}

interface

type

  { TMockInterfacedObject }

  TMockInterfacedObject = class(TObject, IUnknown)
  strict private
    class var FInstance: TMockInterfacedObject;
  public
    class constructor Create;
    class destructor Destroy;
    class property Instance: TMockInterfacedObject read FInstance;
    function QueryInterface({$IFDEF
FPC_HAS_CONSTREF}constref{$ELSE}const{$ENDIF} iid : tguid;out obj) :
longint;{$IFNDEF WINDOWS}cdecl{$ELSE}stdcall{$ENDIF};
    function _AddRef: longint; {$IFNDEF WINDOWS}cdecl{$ELSE}stdcall{$ENDIF};
    function _Release: longint; {$IFNDEF
WINDOWS}cdecl{$ELSE}stdcall{$ENDIF};
  end;

  { TNullable }

  TNullable<T> = record
  strict private
    FValue: T;
    FHasValue: IInterface;
    function GetValue: T;
    function GetHasValue: Boolean;
    procedure SetValue(const AValue: T);
    procedure SetFlatInterface(var Intf: IInterface);
  public
    constructor Create(const AValue: T);
    procedure Clear;
    function GetValueOrDefault: T; overload;
    function GetValueOrDefault(Default: T): T; overload;
    property HasValue: Boolean read GetHasValue;
    property Value: T read GetValue;

    class operator Implicit(const AValue: Pointer): TNullable<T>;
    class operator Implicit(AValue: TNullable<T>): T;
    class operator Implicit(const AValue: T): TNullable<T>;
    class operator Explicit(AValue: TNullable<T>): T;
  end;


  TInteger = TNullable<Integer>;

implementation

uses
  SysUtils;

{ TNullable }

procedure TNullable<T>.SetFlatInterface(var Intf: IInterface);
begin
  Intf := TMockInterfacedObject.Instance;
end;

class operator TNullable<T>.Explicit(AValue: TNullable<T>): T;
begin
  Result := AValue.Value;
end;

function TNullable<T>.GetHasValue: Boolean;
begin
  Result := FHasValue <> nil;
end;

function TNullable<T>.GetValue: T;
begin
  if not HasValue then
    raise Exception.Create('Invalid operation, Nullable type has no value');
  Result := FValue;
end;

function TNullable<T>.GetValueOrDefault: T;
begin
  if HasValue then
    Result := FValue
  else
   Result := Default(T);
end;

function TNullable<T>.GetValueOrDefault(Default: T): T;
begin
  if not HasValue then
    Result := Default
  else
    Result := FValue;
end;

class operator TNullable<T>.Implicit(const AValue: Pointer): TNullable<T>;
begin
  if AValue = nil then
    Result.Clear
  else
    raise Exception.Create('Invalid operation, incompatible values.');
end;

class operator TNullable<T>.Implicit(AValue: TNullable<T>): T;
begin
  Result := AValue.Value;
end;

class operator TNullable<T>.Implicit(const AValue: T): TNullable<T>;
begin
  Result := TNullable<T>.Create(AValue);
end;

procedure TNullable<T>.SetValue(const AValue: T);
begin
  FValue := AValue;
  SetFlatInterface(FHasValue);
end;

constructor TNullable<T>.Create(const AValue: T);
begin
  FValue := AValue;
  SetFlatInterface(FHasValue);
end;

procedure TNullable<T>.Clear;
begin
  FHasValue := nil;
end;

{ TMockInterfacedObject }

class constructor TMockInterfacedObject.Create;
begin
  FInstance := TMockInterfacedObject.Create;
end;

class destructor TMockInterfacedObject.Destroy;
begin
  FInstance.Free;
end;

function TMockInterfacedObject.QueryInterface({$IFDEF
FPC_HAS_CONSTREF}constref
  {$ELSE}const{$ENDIF} iid : tguid;out obj): longint;
begin
  Result := E_NOINTERFACE;
end;

function TMockInterfacedObject._AddRef: longint;
begin
  Result := -1;
end;

function TMockInterfacedObject._Release: longint;
begin
  Result := -1;
end;

end.
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.freepascal.org/pipermail/fpc-pascal/attachments/20160227/7d4c1870/attachment.html>


More information about the fpc-pascal mailing list