source: branches/AS8051toC/Packages/TemplateGenerics/Generic/GenericList.inc

Last change on this file was 26, checked in by chronos, 12 years ago
  • Upraveno: Překlad rozdělen do fáze zpracování maker a druhé fáze zpracování instrukcí.
File size: 18.0 KB
Line 
1{$IFDEF INTERFACE}
2
3 // TGList implemented using templates
4 // - item operations (Add, Insert, ReplaceArray, Get, Set, IndexOf,
5 // Extract, Delete, Exchange)
6 // - item range operations (DeleteItems, InsertItems, ReplaceItems,
7 // Move, Fill)
8 // - other TGList operations (AddList, InsertList,
9 // ReplaceList, GetList, IndexOfList)
10 // - dynamic array operations (AddArray, InsertArray,
11 // ReplaceArray, GetArray, IndexOfArray)
12 // - all items operations (Clear, Reverse, Sort)
13
14 //TGAbstractList = class
15
16 //end;
17
18 // TGList<TGListIndex, TGListItem> = class
19 TGList = class//(TGAbstractList)
20 public
21 type
22 PItem = ^TGListItem;
23 TSortCompare = function(Item1, Item2: TGListItem): Integer of object;
24 TToStringConverter = function(Item: TGListItem): string;
25 TFromStringConverter = function(Text: string): TGListItem;
26 TItemArray = array of TGListItem;
27 private
28 FItems: array of TGListItem;
29 FCount: TGListIndex;
30 FUpdateCount: Integer;
31 FOnUpdate: TNotifyEvent;
32 function Get(Index: TGListIndex): TGListItem;
33 function GetCapacity: TGListIndex;
34 function GetLast: TGListItem;
35 function GetFirst: TGListItem;
36 procedure SetCapacity(const AValue: TGListIndex);
37 procedure SetCapacityOptimized(const NewCapacity: TGListIndex);
38 procedure SetLast(AValue: TGListItem);
39 procedure SetFirst(AValue: TGListItem);
40 procedure QuickSort(L, R : TGListIndex; Compare: TSortCompare);
41 protected
42 procedure Put(Index: TGListIndex; const AValue: TGListItem); virtual;
43 procedure SetCount(const AValue: TGListIndex); virtual;
44 public
45 function CompareMem(P1, P2: Pointer; Length: cardinal): Boolean; inline;
46 function Add(Item: TGListItem): TGListIndex;
47 procedure AddArray(Values: array of TGListItem);
48 procedure AddList(List: TGList);
49 procedure AddListPart(List: TGList; ItemIndex, ItemCount: TGListIndex);
50 procedure Assign(Source: TGList); virtual;
51 constructor Create; virtual;
52 procedure Clear; virtual;
53 procedure Delete(Index: TGListIndex); virtual;
54 procedure DeleteItems(Index, Count: TGListIndex);
55 function EqualTo(List: TGList): Boolean;
56 procedure Exchange(Index1, Index2: TGListIndex);
57 procedure Explode(Text, Separator: string; Converter: TFromStringConverter; SlicesCount: Integer = -1);
58 function Extract(Item: TGListItem): TGListItem;
59 property First: TGListItem read GetFirst write SetFirst;
60 procedure Fill(Start, Count: TGListIndex; Value: TGListItem);
61 function GetArray(Index, ACount: TGListIndex): TItemArray;
62 procedure GetList(List: TGList; Index, ACount: TGListIndex);
63 procedure GetBuffer(Index: TGListIndex; var Buffer; Count: TGListIndex);
64 function Implode(Separator: string; Converter: TToStringConverter): string;
65 function IndexOf(Item: TGListItem; Start: TGListIndex = 0): TGListIndex; virtual;
66 function IndexOfList(List: TGList; Start: TGListIndex = 0): TGListIndex;
67 function IndexOfArray(Values: array of TGListItem; Start: TGListIndex = 0): TGListIndex;
68 procedure Insert(Index: TGListIndex; Item: TGListItem);
69 procedure InsertList(Index: TGListIndex; List: TGList);
70 procedure InsertArray(Index: TGListIndex; Values: array of TGListItem);
71 procedure InsertCount(Index: TGListIndex; ACount: TGListIndex);
72 procedure Move(CurIndex, NewIndex: TGListIndex);
73 procedure MoveItems(CurIndex, NewIndex, Count: TGListIndex);
74 function Remove(Item: TGListItem): TGListIndex;
75 procedure Reverse;
76 procedure ReplaceArray(Index: TGListIndex; Values: array of TGListItem);
77 procedure ReplaceList(Index: TGListIndex; Source: TGList);
78 procedure ReplaceListPart(Index: TGListIndex; Source: TGList;
79 SourceIndex, SourceCount: TGListIndex);
80 procedure ReplaceBuffer(Index: TGListIndex; var Buffer; Count: TGListIndex);
81 procedure Sort(Compare: TSortCompare);
82 procedure SetArray(Values: array of TGListItem);
83 procedure BeginUpdate;
84 procedure EndUpdate;
85 procedure Update;
86 property Count: TGListIndex read FCount write SetCount;
87 property Capacity: TGListIndex read GetCapacity write SetCapacity;
88 property Items[Index: TGListIndex]: TGListItem read Get write Put; default;
89 property Last: TGListItem read GetLast write SetLast;
90 property OnUpdate: TNotifyEvent read FOnUpdate write FOnUpdate;
91 end;
92
93{$UNDEF INTERFACE}
94{$ENDIF}
95
96{$IFDEF IMPLEMENTATION_USES}
97
98uses
99 RtlConsts;
100
101{$UNDEF IMPLEMENTATION_USES}
102{$ENDIF}
103
104{$IFDEF IMPLEMENTATION}
105
106{ TGList }
107
108constructor TGList.Create;
109begin
110 FCount := 0;
111end;
112
113procedure TGList.GetBuffer(Index: TGListIndex; var Buffer; Count: TGListIndex);
114var
115 P: PItem;
116 I: TGListIndex;
117begin
118 if (Index + Count) > FCount then
119 raise EListError.CreateFmt(SListIndexError, [Index + Count]);
120 P := PItem(@Buffer);
121 I := 0;
122 while I < Count do begin
123 P^ := Items[Index + I];
124 Inc(P, 1);
125 I := I + 1;
126 end;
127end;
128
129procedure TGList.ReplaceBuffer(Index: TGListIndex; var Buffer; Count: TGListIndex);
130var
131 P: PItem;
132 I: TGListIndex;
133begin
134 if (Index + Count) > FCount then
135 raise EListError.CreateFmt(SListIndexError, [Index + Count]);
136 P := PItem(@Buffer);
137 I := 0;
138 while I < Count do begin
139 Items[Index + I] := P^;
140 Inc(P, 1);
141 I := I + 1;
142 end;
143end;
144
145procedure TGList.ReplaceArray(Index: TGListIndex; Values: array of TGListItem);
146var
147 I: TGListIndex;
148begin
149 I := 0;
150 while I < Length(Values) do begin
151 Items[Index + I] := Values[I];
152 I := I + 1;
153 end;
154 Update;
155end;
156
157procedure TGList.ReplaceList(Index: TGListIndex; Source: TGList);
158var
159 I: TGListIndex;
160begin
161 I := 0;
162 while I < Source.Count do begin
163 Items[Index + I] := Source[I];
164 I := I + 1;
165 end;
166 Update;
167end;
168
169procedure TGList.ReplaceListPart(Index: TGListIndex; Source: TGList;
170 SourceIndex, SourceCount: TGListIndex);
171var
172 I: TGListIndex;
173begin
174 I := 0;
175 while I < SourceCount do begin
176 Items[Index + I] := Source[SourceIndex + I];
177 I := I + 1;
178 end;
179 Update;
180end;
181
182function TGList.GetCapacity: TGListIndex;
183begin
184 Result := Length(FItems);
185end;
186
187procedure TGList.SetCapacity(const AValue: TGListIndex);
188begin
189 if (AValue < FCount) then
190 raise EListError.CreateFmt(SListCapacityError, [AValue]);
191 SetLength(FItems, AValue);
192end;
193
194procedure TGList.SetCapacityOptimized(const NewCapacity: TGListIndex);
195var
196 IncSize: TGListIndex;
197begin
198 if NewCapacity > Capacity then begin
199 IncSize := NewCapacity - Capacity;
200 // Expand
201 if IncSize = 1 then begin
202 IncSize := 4;
203 if Capacity > 3 then IncSize := IncSize + 4;
204 if Capacity > 8 then IncSize := IncSize + 8;
205 if Capacity > 63 then IncSize := IncSize + Capacity shr 2; // Grow by one quarter
206 end;
207 Capacity := Capacity + IncSize;
208 end else
209 if NewCapacity < Capacity then begin
210 // Contract
211 if (Capacity > 256) and (FCount < Capacity shr 2) then
212 begin
213 Capacity := Capacity shr 1;
214 end;
215 end;
216end;
217
218function TGList.Get(Index: TGListIndex): TGListItem;
219begin
220 if (Index < 0) or (Index >= Count) then
221 raise EListError.CreateFmt(SListIndexError, [Index]);
222 Result := FItems[Index];
223end;
224
225procedure TGList.Put(Index: TGListIndex; const AValue: TGListItem);
226begin
227 if (Index < 0) or (Index >= Count) then
228 raise EListError.CreateFmt(SListIndexError, [Index]);
229 FItems[Index] := AValue;
230end;
231
232procedure TGList.SetCount(const AValue: TGListIndex);
233begin
234 if (AValue < 0) then
235 raise EListError.CreateFmt(SListCountError, [AValue]);
236 if AValue > Capacity then SetCapacityOptimized(AValue); // Before FCount change
237 FCount := AValue;
238 if AValue < Capacity then SetCapacityOptimized(AValue); // After FCount change
239end;
240
241function TGList.GetArray(Index, ACount: TGListIndex): TItemArray;
242var
243 I: Integer;
244begin
245 SetLength(Result, ACount);
246 I := 0;
247 while I < Count do begin
248 Result[I] := FItems[Index + I];
249 I := I + 1;
250 end;
251end;
252
253procedure TGList.GetList(List: TGList; Index, ACount: TGListIndex);
254begin
255 List.Clear;
256 List.AddListPart(Self, Index, ACount);
257end;
258
259procedure TGList.QuickSort(L, R: TGListIndex; Compare: TSortCompare);
260var
261 I, J: TGListIndex;
262 P, Q: TGListItem;
263begin
264 repeat
265 I := L;
266 J := R;
267 P := FItems[(L + R) div 2];
268 repeat
269 while Compare(P, FItems[I]) > 0 do
270 I := I + 1;
271 while Compare(P, FItems[J]) < 0 do
272 J := J - 1;
273 if I <= J then
274 begin
275 Q := FItems[I];
276 FItems[I] := FItems[J];
277 FItems[J] := Q;
278 I := I + 1;
279 J := J - 1;
280 end;
281 until I > J;
282 if L < J then
283 QuickSort(L, J, Compare);
284 L := I;
285 until I >= R;
286end;
287
288procedure TGList.Assign(Source: TGList);
289var
290 I: TGListIndex;
291begin
292 Count := Source.Count;
293 I := 0;
294 while I < Count do begin
295 FItems[I] := Source[I];
296 I := I + 1;
297 end;
298 Update;
299end;
300
301function TGList.Extract(Item: TGListItem): TGListItem;
302var
303 I: TGListIndex;
304begin
305 I := IndexOf(Item);
306 if I >= 0 then begin
307 Result := Item;
308 Delete(I);
309 end else
310 raise EListError.CreateFmt(SListIndexError, [0]);
311end;
312
313function TGList.CompareMem(P1, P2: Pointer; Length: cardinal): Boolean;
314var
315 I: Cardinal;
316begin
317 Result := True;
318 I := 0;
319 if (P1) <> (P2) then
320 while Result and (I < Length) do
321 begin
322 Result := PByte(P1)^ = PByte(P2)^;
323 Inc(I);
324 Inc(pchar(P1));
325 Inc(pchar(P2));
326 end;
327end;
328
329function TGList.IndexOf(Item: TGListItem; Start: TGListIndex): TGListIndex;
330begin
331 Result := Start;
332 while (Result < FCount) and
333// not CompareMem(@FItems[Result], @Item, SizeOf(TGListItem)) do
334 not (CompareByte(FItems[Result], Item, SizeOf(TGListItem)) = 0) do
335 Result := Result + 1;
336 if Result = FCount then Result := -1;
337end;
338
339procedure TGList.Insert(Index: TGListIndex; Item: TGListItem);
340begin
341 if (Index < 0) or (Index > FCount) then
342 raise EListError.CreateFmt(SListIndexError, [Index]);
343 InsertCount(Index, 1);
344 FItems[Index] := Item;
345 Update;
346end;
347
348procedure TGList.InsertList(Index: TGListIndex; List: TGList);
349begin
350 if (Index < 0) or (Index > FCount) then
351 raise EListError.CreateFmt(SListIndexError, [Index]);
352 InsertCount(Index, List.Count);
353 ReplaceList(Index, List);
354end;
355
356procedure TGList.InsertArray(Index: TGListIndex; Values: array of TGListItem);
357begin
358 if (Index < 0) or (Index > FCount) then
359 raise EListError.CreateFmt(SListIndexError, [Index]);
360 InsertCount(Index, Length(Values));
361 ReplaceArray(Index, Values);
362end;
363
364procedure TGList.InsertCount(Index: TGListIndex; ACount: TGListIndex);
365begin
366 if (Index < 0) or (Index > FCount) then
367 raise EListError.CreateFmt(SListIndexError, [Index]);
368 Count := Count + ACount;
369 if Index < FCount then
370 System.Move(FItems[Index], FItems[Index + ACount], (FCount - ACount - Index) * SizeOf(TGListItem));
371 Update;
372end;
373
374function TGList.IndexOfList(List: TGList; Start: TGListIndex): TGListIndex;
375var
376 I: TGListIndex;
377begin
378 if List.Count > 0 then begin
379 Result := IndexOf(List[0], Start);
380 if Result <> -1 then begin
381 I := 1;
382 while I < List.Count do begin
383 if not CompareMem(Addr(FItems[Result + I]), Addr(List.FItems[I]), SizeOf(TGListItem)) then begin
384 Result := -1;
385 Break;
386 end;
387 I := I + 1;
388 end;
389 end;
390 end else Result := -1;
391end;
392
393function TGList.IndexOfArray(Values: array of TGListItem; Start: TGListIndex): TGListIndex;
394var
395 I: TGListIndex;
396begin
397 if Length(Values) > 0 then begin
398 Result := IndexOf(Values[0], Start);
399 if Result <> -1 then begin
400 I := 1;
401 while I < Length(Values) do begin
402 if not CompareMem(Addr(FItems[Result + I]), Addr(Values[I]), SizeOf(TGListItem)) then begin
403 Result := -1;
404 Break;
405 end;
406 I := I + 1;
407 end;
408 end;
409 end else Result := -1;
410end;
411
412function TGList.GetLast: TGListItem;
413begin
414 if FCount = 0 then
415 raise EListError.CreateFmt(SListIndexError, [0])
416 else
417 Result := FItems[FCount - 1];
418end;
419
420procedure TGList.SetLast(AValue: TGListItem);
421begin
422 if FCount = 0 then
423 raise EListError.CreateFmt(SListIndexError, [0])
424 else
425 FItems[FCount - 1] := AValue;
426end;
427
428function TGList.GetFirst: TGListItem;
429begin
430 if FCount = 0 then
431 raise EListError.CreateFmt(SListIndexError, [0])
432 else
433 Result := FItems[0];
434end;
435
436procedure TGList.SetFirst(AValue: TGListItem);
437begin
438 if FCount = 0 then
439 raise EListError.CreateFmt(SListIndexError, [0])
440 else
441 FItems[0] := AValue;
442end;
443
444procedure TGList.Move(CurIndex, NewIndex: TGListIndex);
445var
446 Temp: TGListItem;
447begin
448 if ((CurIndex < 0) or (CurIndex > Count - 1)) then
449 raise EListError.CreateFmt(SListIndexError, [CurIndex]);
450 if ((NewIndex < 0) or (NewIndex > Count -1)) then
451 raise EListError.CreateFmt(SlistIndexError, [NewIndex]);
452 Temp := FItems[CurIndex];
453 if NewIndex > CurIndex then begin
454 System.Move(FItems[CurIndex + 1], FItems[CurIndex], (NewIndex - CurIndex) * SizeOf(TGListItem));
455 end else
456 if NewIndex < CurIndex then begin
457 System.Move(FItems[NewIndex], FItems[NewIndex + 1], (CurIndex - NewIndex) * SizeOf(TGListItem));
458 end;
459 FItems[NewIndex] := Temp;
460 //Delete(CurIndex);
461 //Insert(NewIndex, Temp);
462 Update;
463end;
464
465procedure TGList.MoveItems(CurIndex, NewIndex, Count: TGListIndex);
466var
467 S: Integer;
468 D: Integer;
469begin
470 if CurIndex < NewIndex then begin
471 S := CurIndex + Count - 1;
472 D := NewIndex + Count - 1;
473 while S >= CurIndex do begin
474 Move(S, D);
475 S := S - 1;
476 D := D - 1;
477 end;
478 end else
479 if CurIndex > NewIndex then begin
480 S := CurIndex;
481 D := NewIndex;
482 while S < (CurIndex + Count) do begin
483 Move(S, D);
484 S := S + 1;
485 D := D + 1;
486 end;
487 end;
488 Update;
489end;
490
491function TGList.Remove(Item: TGListItem): TGListIndex;
492begin
493 Result := IndexOf(Item);
494 if Result <> -1 then
495 Delete(Result)
496 else raise Exception.CreateFmt(SItemNotFound, [0]);
497end;
498
499function TGList.EqualTo(List: TGList): Boolean;
500var
501 I: TGListIndex;
502begin
503 Result := Count = List.Count;
504 if Result then begin
505 I := 0;
506 while I < Count do begin
507 if not CompareMem(Addr(FItems[I]), Addr(List.FItems[I]), SizeOf(TGListItem)) then begin
508 Result := False;
509 Break;
510 end;
511 I := I + 1;
512 end;
513 end;
514end;
515
516procedure TGList.Reverse;
517var
518 I: TGListIndex;
519begin
520 I := 0;
521 while I < (Count div 2) do begin
522 Exchange(I, Count - 1 - I);
523 I := I + 1;
524 end;
525 Update;
526end;
527
528procedure TGList.Sort(Compare: TSortCompare);
529begin
530 if FCount > 1 then
531 QuickSort(0, FCount - 1, Compare);
532 Update;
533end;
534
535procedure TGList.AddArray(Values: array of TGListItem);
536var
537 I: TGListIndex;
538begin
539 I := 0;
540 while I <= High(Values) do begin
541 Add(Values[I]);
542 I := I + 1;
543 end;
544 Update;
545end;
546
547procedure TGList.SetArray(Values: array of TGListItem);
548var
549 I: TGListIndex;
550begin
551 Clear;
552 I := 0;
553 while I <= High(Values) do begin
554 Add(Values[I]);
555 I := I + 1;
556 end;
557end;
558
559procedure TGList.BeginUpdate;
560begin
561 Inc(FUpdateCount);
562end;
563
564procedure TGList.EndUpdate;
565begin
566 Dec(FUpdateCount);
567 Update;
568end;
569
570procedure TGList.Update;
571begin
572 if Assigned(FOnUpdate) and (FUpdateCount = 0) then FOnUpdate(Self);
573end;
574
575function TGList.Implode(Separator: string; Converter: TToStringConverter): string;
576var
577 I: TGListIndex;
578begin
579 Result := '';
580 I := 0;
581 while I < Count do begin
582 Result := Result + Converter(FItems[I]);
583 if I < (Count - 1) then
584 Result := Result + Separator;
585 I := I + 1;
586 end;
587end;
588
589procedure TGList.Explode(Text, Separator: string; Converter: TFromStringConverter; SlicesCount: Integer = -1);
590begin
591 Clear;
592 while (Pos(Separator, Text) > 0) and
593 ((Count < (SlicesCount - 1)) or (SlicesCount = -1)) do begin
594 Add(Converter(Copy(Text, 1, Pos(Separator, Text) - 1)));
595 System.Delete(Text, 1, Pos(Separator, Text) + Length(Separator) - 1);
596 end;
597 Add(Converter(Text));
598end;
599
600function TGList.Add(Item: TGListItem): TGListIndex;
601begin
602 Count := Count + 1;
603 Result := FCount - 1;
604 FItems[Result] := Item;
605 Update;
606end;
607
608procedure TGList.AddList(List: TGList);
609var
610 I: TGListIndex;
611 J: TGListIndex;
612begin
613 I := Count;
614 J := 0;
615 Count := Count + List.Count;
616 while I < Count do begin
617 Items[I] := List[J];
618 I := I + 1;
619 J := J + 1;
620 end;
621 Update;
622end;
623
624procedure TGList.AddListPart(List: TGList; ItemIndex, ItemCount: TGListIndex);
625var
626 I: TGListIndex;
627 J: TGListIndex;
628begin
629 I := Count;
630 J := ItemIndex;
631 Count := Count + ItemCount;
632 while I < Count do begin
633 Items[I] := List[J];
634 I := I + 1;
635 J := J + 1;
636 end;
637 Update;
638end;
639
640procedure TGList.Clear;
641begin
642 Count := 0;
643 Capacity := 0;
644end;
645
646procedure TGList.Delete(Index: TGListIndex);
647begin
648 if (Index < 0) or (Index >= FCount) then
649 raise EListError.CreateFmt(SListIndexError, [Index]);
650 FCount := FCount - 1;
651 System.Move(FItems[Index + 1], FItems[Index], (FCount - Index) * SizeOf(TGListItem));
652 SetCapacityOptimized(Capacity - 1);
653 Update;
654end;
655
656procedure TGList.DeleteItems(Index, Count: TGListIndex);
657var
658 I: TGListIndex;
659begin
660 I := Index;
661 while I < (Index + Count) do begin
662 Delete(Index);
663 I := I + 1;
664 end;
665 Update;
666end;
667
668procedure TGList.Fill(Start, Count: TGListIndex; Value: TGListItem);
669var
670 I: TGListIndex;
671begin
672 I := Start;
673 while I < Count do begin
674 FItems[I] := Value;
675 I := I + 1;
676 end;
677 Update;
678end;
679
680procedure TGList.Exchange(Index1, Index2: TGListIndex);
681var
682 Temp: TGListItem;
683begin
684 if ((Index1 >= FCount) or (Index1 < 0)) then
685 raise EListError.CreateFmt(SListIndexError, [Index1]);
686 if ((Index2 >= FCount) or (Index2 < 0)) then
687 raise EListError.CreateFmt(SListIndexError, [Index2]);
688 Temp := FItems[Index1];
689 FItems[Index1] := FItems[Index2];
690 FItems[Index2] := Temp;
691 Update;
692end;
693
694{$UNDEF IMPLEMENTATION}
695{$ENDIF}
Note: See TracBrowser for help on using the repository browser.