blob: c66e7d914c532e05df915b7907af07ac8c7ca3ce (
plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
|
unit nullable;
{$mode objfpc}
{$modeswitch advancedrecords}
interface
uses sysutils;
Type
{ TNullable }
generic TNullable<T> = record
private
FValue: T;
FHasValue: Boolean; // Default False
function GetIsNull: Boolean;
function GetValue: T;
function GetValueOrDefault: T;
procedure SetHasValue(AValue: Boolean);
procedure SetValue(AValue: T);
Public
// Make things more readable
Type
TMyType = specialize TNullable<T>;
// Clear value, no value present after this.
procedure Clear;
// Is a value present ?
property HasValue: Boolean read FHasValue write SetHasValue;
// Is No value present
property IsNull: Boolean read GetIsNull;
// return the value.
property Value: T read GetValue write SetValue;
// If a value is present, return it, otherwise return the default.
property ValueOrDefault: T read GetValueOrDefault;
// Return an empty value
class function Empty: TMyType; static;
// management operator
class operator Initialize(var aSelf : TNullable);
// Conversion.
class operator Explicit(aValue: T): TMyType;
class operator Explicit(aValue: TMyType): T;
class operator := (aValue: T): TMyType;
class operator := (aValue: TMyType): T;
end;
implementation
uses rtlconsts,typinfo;
{ TNullable }
function TNullable.GetIsNull: Boolean;
begin
Result:=Not HasValue;
end;
function TNullable.GetValue: T;
begin
if not FHasValue then
raise EConvertError.CreateFmt(SErrCannotConvertNullToType,[PtypeInfo(TypeInfo(T))^.Name]);
Result:=FValue;
end;
function TNullable.GetValueOrDefault: T;
begin
if HasValue then
Result:=Value
else
Result:=Default(T);
end;
procedure TNullable.SetHasValue(AValue: Boolean);
begin
if FHasValue=AValue then Exit;
if aValue then
Value:=Default(T)
else
FHasValue:=False;
end;
procedure TNullable.SetValue(AValue: T);
begin
FValue:=aValue;
FHasValue:=True;
end;
procedure TNullable.Clear;
begin
HasValue:=False;
end;
class operator TNullable.Initialize(var aSelf: TNullable);
begin
aSelf.FHasValue:=False;
end;
class function TNullable.Empty: TMyType; static;
begin
Result.HasValue:=False;
end;
class operator TNullable.Explicit(aValue: T): TMyType;
begin
Result.Value:=aValue;
end;
class operator TNullable.Explicit(aValue: TMyType): T;
begin
Result:=aValue.Value;
end;
class operator TNullable.:= (aValue: T): TMyType;
begin
Result.Value:=aValue;
end;
class operator TNullable.:= (aValue: TMyType): T;
begin
// We could use :=This is in line with TField's behaviour.
Result:=aValue.Value;
end;
end.
|