-
Notifications
You must be signed in to change notification settings - Fork 6
/
Copy pathDynArray.pas
220 lines (194 loc) · 6.45 KB
/
DynArray.pas
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
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
unit DynArray;
////////////////////////////////////////////////////////////////////////////////
//
// Author: Jaap Baak
// https://github.com/transportmodelling/Utils
//
// Implementation of an array with dynamic rank
//
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
interface
////////////////////////////////////////////////////////////////////////////////
Uses
SysUtils, Ranges, ArrayBld;
Type
TCompositeIndex = record
// This record converts between indices and a single composite index
//
// Example (composition of Index1 and Index2):
//
// Index1 Index2 CompositeIndex
// 0 0 0
// 0 1 1
// 1 0 2
// 1 1 3
private
FCount: Integer;
Multipliers: array of Integer;
public
Class Operator Initialize(out CompositeIndex: TCompositeIndex);
public
Constructor Create(const Shape: array of Integer);
Property Count: Integer read FCount;
Procedure Reset; overload;
Function Rank: Integer; inline;
Function Shape: TArray<Integer>;
Function Indices(CompositeIndex: Integer): TArray<Integer>;
Function CompositeIndex(const Indices: array of Integer): Integer;
Function CompositeIndexRange(const Indices: array of Integer): TRange;
end;
TDynamicArray<T> = record
// The multidimensional dynamic array stores its values in a one-dimensional array,
// using a TCompositeIndex-record to convert between indices and a single composite index.
private
FValues: TArray<T>;
Index: TCompositeIndex;
Function GetValue(const Indices: array of Integer): T;
Procedure SetValue(const Indices: array of Integer; const Value: T);
public
Class Operator Implicit(const Values: array of T): TDynamicArray<T>;
Class Operator Implicit(const Values: TDynamicArray<T>): TArray<T>;
public
Constructor Create(const Shape: array of Integer);
Function Allocated: Boolean;
Procedure Allocate(const Shape: array of Integer);
Function Rank: Integer; inline;
Function Shape: TArray<Integer>; inline;
public
Property Value[const Indices: array of Integer]: T read GetValue write SetValue; default;
end;
TDynamicIntArray = TDynamicArray<Integer>;
TDynamicFloatArray = TDynamicArray<Float64>;
TDynamicFloat32Array = TDynamicArray<Float32>;
////////////////////////////////////////////////////////////////////////////////
implementation
////////////////////////////////////////////////////////////////////////////////
Class Operator TCompositeIndex.Initialize(out CompositeIndex: TCompositeIndex);
begin
CompositeIndex.FCount := 0;
end;
Constructor TCompositeIndex.Create(Const Shape: array of Integer);
begin
var Rank := Length(Shape);
if Rank > 0 then
begin
FCount := Shape[Rank-1];
SetLength(Multipliers,Rank-1);
for var Dim := Rank-2 downto 0 do
begin
Multipliers[Dim] := FCount;
FCount := FCount*Shape[Dim];
end;
if FCount = 0 then raise Exception.Create('Invalid shape');
end else Reset;
end;
Procedure TCompositeIndex.Reset;
begin
FCount := 0;
Finalize(Multipliers);
end;
Function TCompositeIndex.Rank: Integer;
begin
if FCount = 0 then Result := 0 else Result := Length(Multipliers)+1;
end;
Function TCompositeIndex.Shape: TArray<Integer>;
begin
var Cnt := FCount;
SetLength(Result,Rank);
for var Dim := low(Result) to pred(high(Result)) do
begin
Result[Dim] := Cnt div Multipliers[Dim];
Cnt := Cnt div Result[Dim];
end;
Result[high(Result)] := Cnt;
end;
Function TCompositeIndex.Indices(CompositeIndex: Integer): TArray<Integer>;
begin
SetLength(Result,Rank);
for var Dim := low(Result) to pred(high(Result)) do
if CompositeIndex >= Multipliers[Dim] then
begin
Result[Dim] := CompositeIndex div Multipliers[Dim];
CompositeIndex := CompositeIndex - Result[Dim]*Multipliers[Dim];
end else Result[Dim] := 0;
Result[high(Result)] := CompositeIndex;
end;
Function TCompositeIndex.CompositeIndex(Const Indices: array of Integer): Integer;
begin
if Length(Indices) = Rank then
begin
Result := Indices[Length(Multipliers)];
for var Dim := low(Multipliers) to high(Multipliers) do
Result := Result + Multipliers[Dim]*Indices[Dim];
end else raise Exception.Create('Invalid rank');
end;
Function TCompositeIndex.CompositeIndexRange(const Indices: array of Integer): TRange;
begin
if Length(Indices) = Rank then
begin
var Index := CompositeIndex(Indices);
Result := TRange.Create(Index,Index)
end else
if Length(Indices) < Rank then
begin
// Set minimum
var MinIndex := 0;
for var Dim := low(Indices) to high(Indices) do
MinIndex := MinIndex + Multipliers[Dim]*Indices[Dim];
// Set maximum
var MaxIndex := MinIndex + Multipliers[high(Indices)] - 1;
// Set result
Result := TRange.Create(MinIndex,MaxIndex);
end else raise Exception.Create('Invalid rank');
end;
////////////////////////////////////////////////////////////////////////////////
Class Operator TDynamicArray<T>.Implicit(const Values: array of T): TDynamicArray<T>;
begin
Result.Index := TCompositeIndex.Create([Length(Values)]);
Result.FValues := TArrayBuilder<T>.Create(Values);
end;
Class Operator TDynamicArray<T>.Implicit(const Values: TDynamicArray<T>): TArray<T>;
begin
if Values.Rank = 1 then
Result := Copy(Values.FValues,0,Length(Values.FValues))
else
raise Exception.Create('Invalid rank');
end;
Constructor TDynamicArray<T>.Create(const Shape: array of Integer);
begin
Allocate(Shape);
end;
Function TDynamicArray<T>.Allocated: Boolean;
begin
Result := Length(FValues) > 0;
end;
Procedure TDynamicArray<T>.Allocate(const Shape: array of Integer);
begin
FValues := nil;
Index := TCompositeIndex.Create(Shape);
SetLength(FValues,Index.FCount);
end;
Function TDynamicArray<T>.Rank: Integer;
begin
if Allocated then Result := Index.Rank else Result := 0;
end;
Function TDynamicArray<T>.Shape: TArray<Integer>;
begin
Result := Index.Shape;
end;
Function TDynamicArray<T>.GetValue(const Indices: array of Integer): T;
begin
if Length(Indices) = Rank then
Result := FValues[Index.CompositeIndex(Indices)]
else
raise Exception.Create('Invalid rank');
end;
Procedure TDynamicArray<T>.SetValue(const Indices: array of Integer; const Value: T);
begin
if Length(Indices) = Rank then
FValues[Index.CompositeIndex(Indices)] := Value
else
raise Exception.Create('Invalid rank');
end;
end.