source: trunk/Demos/Generics/List.pas

Last change on this file was 39, checked in by chronos, 13 years ago
  • Modified: Reorganized docked forms. Target code is now accessible through main PageControl tab.
  • Added: Store right and bottom panels size.
File size: 10.3 KB
Line 
1unit List;
2
3interface
4
5type
6 TList<TItem, TIndex = NativeInt> = class
7 public
8 type
9 TSortCompare = function(const Item1, Item2: TItem): Integer of object;
10 TStringConverter = function(Item: TItem): string;
11 private
12 FItems: array of TItem;
13 FCount: TIndex;
14 function Get(Index: TIndex): TItem;
15 function GetCapacity: TIndex;
16 function GetLast: TItem;
17 function GetFirst: TItem;
18 procedure SetCapacity(const AValue: TIndex);
19 procedure SetLast(AValue: TItem);
20 procedure SetFirst(AValue: TItem);
21 procedure Put(Index: TIndex; const AValue: TItem); virtual;
22 procedure SetCount(const AValue: TIndex);
23 procedure QuickSort(L, R : TIndex; Compare: TSortCompare);
24 public
25 function Add(Item: TItem): TIndex;
26 procedure AddArray(Values: array of TItem);
27 procedure AddList(List: TList);
28 procedure Assign(List: TList);
29 procedure Clear; virtual;
30 procedure Contract;
31 procedure Delete(Index: TIndex); virtual;
32 procedure DeleteItems(Index, Count: TIndex);
33 function Equals(List: TList): Boolean;
34 procedure Expand;
35 function Extract(Item: TItem): TItem;
36 procedure Exchange(Index1, Index2: TIndex);
37 property First: TItem read GetFirst write SetFirst;
38 procedure Fill(Start, Count: TIndex; Value: TItem);
39 function Implode(Separator: string; Converter: TStringConverter): string;
40 function IndexOf(Item: TItem; Start: TIndex = 0): TIndex;
41 function IndexOfList(List: TList; Start: TIndex = 0): TIndex;
42 procedure Insert(Index: TIndex; Item: TItem);
43 procedure InsertList(Index: TIndex; List: TList);
44 procedure InsertArray(Index: TIndex; Values: array of TItem);
45 procedure Move(CurIndex, NewIndex: TIndex);
46 procedure MoveItems(CurIndex, NewIndex, Count: TIndex);
47 function Remove(Item: TItem): TIndex;
48 procedure Reverse;
49 procedure Sort(Compare: TSortCompare);
50 procedure SetArray(Values: array of TItem);
51 property Count: TIndex read FCount write SetCount;
52 property Capacity: TIndex read GetCapacity write SetCapacity;
53 property Items[Index: TIndex]: TItem read Get write Put; default;
54 property Last: TItem read GetLast write SetLast;
55 end;
56
57implementation
58
59function TList.GetCapacity: TIndex;
60begin
61 Result := Length(FItems);
62end;
63
64procedure TList.SetCapacity(const AValue: TIndex);
65begin
66 SetLength(FItems, AValue);
67end;
68
69function TList.Get(Index: TIndex): TItem;
70begin
71 Result := FItems[Index];
72end;
73
74procedure TList.Put(Index: TIndex; const AValue: TItem);
75begin
76 FItems[Index] := AValue;
77end;
78
79procedure TList.SetCount(const AValue: TIndex);
80begin
81 SetLength(FItems, AValue);
82 FCount := AValue;
83end;
84
85procedure TList.QuickSort(L, R: TIndex; Compare: TSortCompare);
86var
87 I, J: TIndex;
88 P, Q: TItem;
89begin
90 repeat
91 I := L;
92 J := R;
93 P := FItems[ (L + R) div 2 ];
94 repeat
95 while Compare(P, FItems[I]) > 0 do
96 I := I + 1;
97 while Compare(P, FItems[J]) < 0 do
98 J := J - 1;
99 If I <= J then
100 begin
101 Q := FItems[I];
102 FItems[I] := FItems[J];
103 FItems[J] := Q;
104 I := I + 1;
105 J := J - 1;
106 end;
107 until I > J;
108 if L < J then
109 QuickSort(L, J, Compare);
110 L := I;
111 until I >= R;
112end;
113
114procedure TList.Assign(List: TList);
115var
116 I: Integer;
117begin
118 Count := List.Count;
119 I := 0;
120 while I < Count do begin
121 Items[I] := List[I];
122 I := I + 1;
123 end;
124end;
125
126procedure TList.Expand;
127var
128 IncSize: TIndex;
129begin
130 if FCount = Capacity then begin
131 IncSize := 4;
132 if Capacity > 3 then IncSize := IncSize + 4;
133 if Capacity > 8 then IncSize := IncSize + 8;
134 if Capacity > 63 then IncSize := IncSize + Capacity shr 2;
135 Capacity := Capacity + IncSize;
136 end;
137end;
138
139procedure TList.Contract;
140begin
141 if (Capacity > 256) and (FCount < Capacity shr 2) then
142 begin
143 Capacity := Capacity shr 1;
144 end;
145end;
146
147function TList.Extract(Item: TItem): TItem;
148var
149 I: TIndex;
150begin
151 I := IndexOf(Item);
152 if I >= 0 then begin
153 Result := Item;
154 Delete(I);
155 end else
156 raise EListError.CreateFmt(SListIndexError, [0]);
157end;
158
159function TList.IndexOf(Item: TItem; Start: TIndex): TIndex;
160begin
161 Result := Start;
162 while (Result < FCount) and
163 not CompareMem(Addr(FItems[Result]), Addr(Item), SizeOf(TItem)) do
164 Result := Result + 1;
165 if Result = FCount then Result := -1;
166end;
167
168procedure TList.Insert(Index: TIndex; Item: TItem);
169begin
170 if (Index < 0) or (Index > FCount ) then
171 raise EListError.CreateFmt(SListIndexError, [Index]);
172 if FCount = Capacity then Expand;
173 if Index < FCount then
174 System.Move(FItems[Index], FItems[Index + 1], (FCount - Index) * SizeOf(TItem));
175 FItems[Index] := Item;
176 FCount := FCount + 1;
177end;
178
179procedure TList.InsertList(Index: TIndex; List: TList);
180var
181 I: TIndex;
182begin
183 I := 0;
184 while (I < List.Count) do begin
185 Insert(Index + I, List[I]);
186 I := I + 1;
187 end;
188end;
189
190function TList.IndexOfList(List: TList; Start: TIndex): TIndex;
191var
192 I: TIndex;
193begin
194 if List.Count > 0 then begin
195 Result := IndexOf(List[0], Start);
196 if Result <> -1 then begin
197 I := 1;
198 while I < List.Count do begin
199 if not CompareMem(Addr(FItems[Result + I]), Addr(List.FItems[I]), SizeOf(TItem)) then begin
200 Result := -1;
201 Break;
202 end;
203 I := I + 1;
204 end;
205 end;
206 end else Result := -1;
207end;
208
209function TList.GetLast: TItem;
210begin
211 if FCount = 0 then
212 raise EListError.CreateFmt(SListIndexError, [0])
213 else
214 Result := Items[FCount - 1];
215end;
216
217procedure TList.SetLast(AValue: TItem);
218begin
219 if FCount = 0 then
220 raise EListError.CreateFmt(SListIndexError, [0])
221 else
222 Items[FCount - 1] := AValue;
223end;
224
225function TList.GetFirst: TItem;
226begin
227 if FCount = 0 then
228 raise EListError.CreateFmt(SListIndexError, [0])
229 else
230 Result := Items[0];
231end;
232
233procedure TList.SetFirst(AValue: TItem);
234begin
235 if FCount = 0 then
236 raise EListError.CreateFmt(SListIndexError, [0])
237 else
238 Items[0] := AValue;
239end;
240
241procedure TList.Move(CurIndex, NewIndex: TIndex);
242var
243 Temp: TItem;
244begin
245 if ((CurIndex < 0) or (CurIndex > Count - 1)) then
246 raise EListError.CreateFmt(SListIndexError, [CurIndex]);
247 if ((NewIndex < 0) or (NewIndex > Count -1)) then
248 raise EListError.CreateFmt(SlistIndexError, [NewIndex]);
249 Temp := FItems[CurIndex];
250 if NewIndex > CurIndex then begin
251 System.Move(FItems[CurIndex + 1], FItems[CurIndex], (NewIndex - CurIndex) * SizeOf(TItem));
252 end else
253 if NewIndex < CurIndex then begin
254 System.Move(FItems[NewIndex], FItems[NewIndex + 1], (CurIndex - NewIndex) * SizeOf(TItem));
255 end;
256 FItems[NewIndex] := Temp;
257 //Delete(CurIndex);
258 //Insert(NewIndex, Temp);
259end;
260
261procedure TList.MoveItems(CurIndex, NewIndex, Count: TIndex);
262var
263 S: Integer;
264 D: Integer;
265begin
266 if CurIndex < NewIndex then begin
267 S := CurIndex + Count - 1;
268 D := NewIndex + Count - 1;
269 while S >= CurIndex do begin
270 Move(S, D);
271 S := S - 1;
272 D := D - 1;
273 end;
274 end else
275 if CurIndex > NewIndex then begin
276 S := CurIndex;
277 D := NewIndex;
278 while S < (CurIndex + Count) do begin
279 Move(S, D);
280 S := S + 1;
281 D := D + 1;
282 end;
283 end;
284end;
285
286function TList.Remove(Item: TItem): TIndex;
287begin
288 Result := IndexOf(Item);
289 if Result <> -1 then
290 Delete(Result);
291end;
292
293function TList.Equals(List: TList): Boolean;
294var
295 I: TIndex;
296begin
297 Result := Count = List.Count;
298 if Result then begin
299 I := 0;
300 while I < Count do begin
301 if not CompareMem(Addr(FItems[I]), Addr(List.FItems[I]), SizeOf(TItem)) then begin
302 Result := False;
303 Break;
304 end;
305 I := I + 1;
306 end;
307 end;
308end;
309
310procedure TList.Reverse;
311var
312 I: TIndex;
313begin
314 I := 0;
315 while I < (Count div 2) do begin
316 Exchange(I, Count - 1 - I);
317 I := I + 1;
318 end;
319end;
320
321procedure TList.Sort(Compare: TSortCompare);
322begin
323 if FCount > 1 then
324 QuickSort(0, FCount - 1, Compare);
325end;
326
327procedure TList.AddArray(Values: array of TItem);
328var
329 I: TIndex;
330begin
331 I := 0;
332 while I <= High(Values) do begin
333 Add(Values[I]);
334 I := I + 1;
335 end;
336end;
337
338procedure TList.SetArray(Values: array of TItem);
339var
340 I: TIndex;
341begin
342 Clear;
343 I := 0;
344 while I <= High(Values) do begin
345 Add(Values[I]);
346 I := I + 1;
347 end;
348end;
349
350procedure TList.InsertArray(Index: TIndex; Values: array of TItem);
351var
352 I: TIndex;
353begin
354 I := 0;
355 while I <= High(Values) do begin
356 Insert(Index + I, Values[I]);
357 I := I + 1;
358 end;
359end;
360
361function TList.Implode(Separator: string; Converter: TStringConverter): string;
362var
363 I: TIndex;
364begin
365 Result := '';
366 I := 0;
367 while I < Count do begin
368 Result := Result + Converter(Items[I]);
369 if I < (Count - 1) then
370 Result := Result + Separator;
371 I := I + 1;
372 end;
373end;
374
375function TList.Add(Item: TItem): TIndex;
376begin
377 if FCount = Capacity then
378 Self.Expand;
379 FItems[FCount] := Item;
380 Result := FCount;
381 FCount := FCount + 1;
382end;
383
384procedure TList.AddList(List: TList);
385var
386 I: TIndex;
387begin
388 I := 0;
389 while I < List.Count do begin
390 Add(List[I]);
391 I := I + 1;
392 end;
393end;
394
395procedure TList.Clear;
396begin
397 Count := 0;
398 Capacity := 0;
399end;
400
401procedure TList.Delete(Index: TIndex);
402begin
403 if (Index < 0) or (Index >= FCount) then
404 raise EListError.CreateFmt(SListIndexError, [Index]);
405 FCount := FCount - 1;
406 System.Move(FItems[Index + 1], FItems[Index], (FCount - Index) * SizeOf(TItem));
407 Contract;
408end;
409
410procedure TList.DeleteItems(Index, Count: TIndex);
411var
412 I: TIndex;
413begin
414 I := Index;
415 while I < (Index + Count) do begin
416 Delete(Index);
417 I := I + 1;
418 end;
419end;
420
421procedure TList.Fill(Start, Count: TIndex; Value: TItem);
422begin
423 while Count > 0 do begin
424 Items[Start] := Value;
425 Count := Count - 1;
426 Start := Start + 1;
427 end;
428end;
429
430procedure TList.Exchange(Index1, Index2: TIndex);
431var
432 Temp: TItem;
433begin
434 if ((Index1 >= FCount) or (Index1 < 0)) then
435 raise EListError.CreateFmt(SListIndexError, [Index1]);
436 if ((Index2 >= FCount) or (Index2 < 0)) then
437 raise EListError.CreateFmt(SListIndexError, [Index2]);
438 Temp := FItems[Index1];
439 FItems[Index1] := FItems[Index2];
440 FItems[Index2] := Temp;
441end;
442
443end.
Note: See TracBrowser for help on using the repository browser.