-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathXARRAY.PAS
More file actions
277 lines (197 loc) · 6.69 KB
/
XARRAY.PAS
File metadata and controls
277 lines (197 loc) · 6.69 KB
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
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
{ XARRAY.PAS
Description:
Contains the type definitions and operators for an "extendable array"
data structure - a "chunked linked list". This list will be circular
so that append operations are O(1).
Indexing operations will be O(N/c) where N is the number of elements
and c is the chunk size.
Search operations will be somewhat more difficult to implement in
an optimized fashion.
}
unit xarray;
interface
uses misc;
const
CHUNK_SIZE = 128;
type
chunk_array = array[0 .. CHUNK_SIZE - 1] of pointer;
chunk_ptr = ^chunk_node;
chunk_node =
record
data: chunk_array;
next: chunk_ptr
end;
xarray_type = { actually a "header" node }
record
size: integer;
start: chunk_ptr
end;
access_type = (POKE_ACCESS, PEEK_ACCESS);
{ Procedures and Functions }
procedure new_xarray(var the_xarray: xarray_type);
procedure dispose_xarray(var the_xarray: xarray_type);
procedure append_to_xarray(var the_xarray: xarray_type; element: pointer);
function access_xarray(var the_xarray: xarray_type; index: integer;
var result: pointer;
direction : access_type): boolean;
function index_xarray(var the_xarray: xarray_type; index: integer;
var result: pointer): boolean;
procedure shrink_xarray(var the_xarray: xarray_type);
implementation
{ new_xarray
Description:
The constructor.
Arguments:
the_xarray (OUT) -- the array to be "refreshed"
}
procedure new_xarray(var the_xarray: xarray_type);
begin
with the_xarray do begin
size := 0;
start := nil
end
end; { new_xarray }
{ dispose_xarray
Description:
The destructor for the class. Calls to this procedure must be followed
by a call to new_xarray in order to use the same xarray again.
Arguments:
the_xarray (IN/OUT) -- the xarray whose memory needs to be deallocated.
}
procedure dispose_xarray(var the_xarray: xarray_type);
var
index, axe: chunk_ptr;
begin
if the_xarray.start <> nil then begin
index := the_xarray.start^.next;
while index <> the_xarray.start do begin
axe := index;
index := index^.next;
add_bytes(-SizeOf(axe^));
dispose(axe)
end;
add_bytes(-SizeOf(index^));
dispose(index)
end;
with the_xarray do begin
size := 0;
start := nil
end
end; { dispose_xarray }
{ append_to_xarray
Description:
An O(1) appending of an element to an xarray.
Arguments:
the_xarray (IN/OUT) -- xarray to be appended to
element (IN) -- pointer to element to be appended
}
procedure append_to_xarray(var the_xarray: xarray_type; element: pointer);
var
new_chunk_ptr: chunk_ptr;
inner_index: integer;
begin
with the_xarray do begin
inner_index := size mod CHUNK_SIZE;
if inner_index = 0 then begin { add new chunk }
new(new_chunk_ptr);
add_bytes(SizeOf(new_chunk_ptr^));
if start = nil then
new_chunk_ptr^.next := new_chunk_ptr
else begin
new_chunk_ptr^.next := start^.next;
start^.next := new_chunk_ptr
end;
start := new_chunk_ptr
end;
start^.data[inner_index] := element; { store the element }
inc(size) { increment size AFTERWARD }
end
end; { append_to_xarray }
{ access_xarray
Description:
Accesses the <index>th element of the given xarray.
Arguments:
the_xarray (IN) -- xarray to be indexed
index (IN) -- number of the element in the xarray
result (IN/OUT) -- holds the value of the element
direction (IN) -- if POKE_ACCESS, indicates that the
accessed element should be replaced by
<result>; otherwise, <result> should
replace the element.
Returns:
TRUE if the xarray was successfully indexed; FALSE if the index was
out of range.
}
function access_xarray(var the_xarray: xarray_type; index: integer;
var result: pointer; direction : access_type): boolean;
var
i: integer;
ptr_index: chunk_ptr;
begin
with the_xarray do
if (index > size) or (index < 1) then
access_xarray := FALSE
else begin
dec(index); { to normalize it }
ptr_index := start^.next; { first element }
for i := 1 to (index div CHUNK_SIZE) do
ptr_index := ptr_index^.next;
if direction = POKE_ACCESS then
ptr_index^.data[index mod CHUNK_SIZE] := result
else
result := ptr_index^.data[index mod CHUNK_SIZE];
access_xarray := TRUE
end
end; { access_xarray }
{ index_xarray
Description:
Passes back the element of the xarray at the given index.
Arguments:
the_xarray (IN) -- xarray to be indexed
index (IN) -- number of the element in the xarray
result (OUT) -- holds the value of the element
Returns:
TRUE if the xarray was successfully indexed; FALSE if the index was
out of range.
}
function index_xarray(var the_xarray: xarray_type; index: integer;
var result: pointer): boolean;
var
i: integer;
ptr_index: chunk_ptr;
begin
index_xarray := access_xarray(the_xarray, index, result, PEEK_ACCESS)
end; { index_xarray }
{ shrink_xarray
Description:
Deletes the last element from the given xarray. The case of the
inner index being well within a chunk is simple; the boundary condition
is much more complex. Is effectively the inverse of append_xarray.
It hopes you have disposed of whatever the pointer is pointing to
before you shrink the xarray.
}
procedure shrink_xarray(var the_xarray: xarray_type);
var
inner_index : integer;
ptr_index : chunk_ptr;
begin
with the_xarray do
if size > 0 then begin
inner_index := (size - 1) mod CHUNK_SIZE;
start^.data[inner_index] := nil; { deleted }
if inner_index = 0 then begin { must de-chunk }
{ Need to chase around the linked list to find the
node just before the start node. }
ptr_index := start;
while ptr_index^.next <> start do
ptr_index := ptr_index^.next;
ptr_index^.next := start^.next;
add_bytes(-Sizeof(start^));
dispose(start);
start := ptr_index
end;
dec(size);
if size = 0 then the_xarray.start := nil
end
end; { shrink_xarray }
end. { unit xarray }