source: trunk/Packages/Graphics32/GR32_Containers.pas

Last change on this file was 2, checked in by chronos, 5 years ago
File size: 21.3 KB
Line 
1unit GR32_Containers;
2
3(* ***** BEGIN LICENSE BLOCK *****
4 * Version: MPL 1.1 or LGPL 2.1 with linking exception
5 *
6 * The contents of this file are subject to the Mozilla Public License Version
7 * 1.1 (the "License"); you may not use this file except in compliance with
8 * the License. You may obtain a copy of the License at
9 * http://www.mozilla.org/MPL/
10 *
11 * Software distributed under the License is distributed on an "AS IS" basis,
12 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
13 * for the specific language governing rights and limitations under the
14 * License.
15 *
16 * Alternatively, the contents of this file may be used under the terms of the
17 * Free Pascal modified version of the GNU Lesser General Public License
18 * Version 2.1 (the "FPC modified LGPL License"), in which case the provisions
19 * of this license are applicable instead of those above.
20 * Please see the file LICENSE.txt for additional information concerning this
21 * license.
22 *
23 * The Original Code is Repaint Optimizer Extension for Graphics32
24 *
25 * The Initial Developer of the Original Code is
26 * Andre Beckedorf - metaException
27 * Andre@metaException.de
28 *
29 * Portions created by the Initial Developer are Copyright (C) 2005-2009
30 * the Initial Developer. All Rights Reserved.
31 *
32 * Contributor(s):
33 *
34 * ***** END LICENSE BLOCK ***** *)
35
36interface
37
38{$I GR32.inc}
39
40uses
41{$IFDEF FPC}
42 {$IFDEF Windows}
43 Windows,
44 {$ELSE}
45 Types,
46 {$ENDIF}
47{$ELSE}
48 Types, Windows,
49{$ENDIF}
50 RTLConsts,
51 GR32, SysUtils, Classes, TypInfo;
52
53const
54 BUCKET_MASK = $FF;
55 BUCKET_COUNT = BUCKET_MASK + 1; // 256 buckets by default
56
57type
58 PPItem = ^PItem;
59 PItem = Pointer;
60
61 PPData = ^PData;
62 PData = Pointer;
63
64 PPointerBucketItem = ^TPointerBucketItem;
65 TPointerBucketItem = record
66 Item: PItem;
67 Data: PData;
68 end;
69 TPointerBucketItemArray = array of TPointerBucketItem;
70
71 TPointerBucket = record
72 Count: Integer;
73 Items: TPointerBucketItemArray;
74 end;
75 TPointerBucketArray = array[0..BUCKET_MASK] of TPointerBucket;
76
77 { TPointerMap }
78 { Associative pointer map
79 Inspired by TBucketList, which is not available on D5/CB5, it is
80 reimplemented from scratch, simple, optimized and light-weight.
81 Not thread-safe. Does use exceptions only for Data property. }
82 TPointerMap = class
83 private
84 FBuckets: TPointerBucketArray;
85 FCount: Integer;
86 protected
87 function GetData(Item: PItem): PData;
88 procedure SetData(Item: PItem; const Data: PData);
89 function Exists(Item: Pointer; out BucketIndex, ItemIndex: Integer): Boolean;
90 function Delete(BucketIndex, ItemIndex: Integer): PData; virtual;
91 public
92 destructor Destroy; override;
93 function Add(NewItem: PItem): PPData; overload;
94 function Add(NewItem: PItem; out IsNew: Boolean): PPData; overload;
95 function Add(NewItem: PItem; NewData: PData): PPData; overload;
96 function Add(NewItem: PItem; NewData: PData; out IsNew: Boolean): PPData; overload;
97 function Remove(Item: PItem): PData;
98 procedure Clear;
99 function Contains(Item: PItem): Boolean;
100 function Find(Item: PItem; out Data: PPData): Boolean;
101 property Data[Item: PItem]: PData read GetData write SetData; default;
102 property Count: Integer read FCount;
103 end;
104
105 { TPointerMapIterator }
106 { Iterator object for the associative pointer map
107 See below for usage example... }
108 TPointerMapIterator = class
109 private
110 FSrcPointerMap: TPointerMap;
111 FItem: PItem;
112 FData: PData;
113 FCurBucketIndex: Integer;
114 FCurItemIndex: Integer;
115 public
116 constructor Create(SrcPointerMap: TPointerMap);
117 function Next: Boolean;
118 property Item: PItem read FItem;
119 property Data: PData read FData;
120 end;
121 {
122 USAGE EXAMPLE:
123 --------------
124 with TPointerMapIterator.Create(MyPointerMap) do
125 try
126 while Next do
127 begin
128 // do something with Item and Data here...
129 end;
130 finally
131 Free;
132 end;
133 }
134
135 PPolyRects = ^TPolyRects;
136 TPolyRects = Array[0..Maxint div 32 - 1] of TRect;
137
138 { TRectList }
139 { List that holds Rects
140 Do not reuse TList due to pointer structure.
141 A direct structure is more memory efficient.
142 stripped version of TList blatantly stolen from Classes.pas }
143 TRectList = class
144 private
145 FList: PPolyRects;
146 FCount: Integer;
147 FCapacity: Integer;
148 protected
149 function Get(Index: Integer): PRect;
150 procedure Grow; virtual;
151 procedure SetCapacity(NewCapacity: Integer);
152 procedure SetCount(NewCount: Integer);
153 public
154 destructor Destroy; override;
155 function Add(const Rect: TRect): Integer;
156 procedure Clear; virtual;
157 procedure Delete(Index: Integer);
158 procedure Exchange(Index1, Index2: Integer);
159 function IndexOf(const Rect: TRect): Integer;
160 procedure Insert(Index: Integer; const Rect: TRect);
161 procedure Move(CurIndex, NewIndex: Integer);
162 function Remove(const Rect: TRect): Integer;
163 procedure Pack;
164 property Capacity: Integer read FCapacity write SetCapacity;
165 property Count: Integer read FCount write SetCount;
166 property Items[Index: Integer]: PRect read Get; default;
167 property List: PPolyRects read FList;
168 end;
169
170 { TClassList }
171 { This is a class that maintains a list of classes. }
172 TClassList = class(TList)
173 protected
174 function GetItems(Index: Integer): TClass;
175 procedure SetItems(Index: Integer; AClass: TClass);
176 public
177 function Add(AClass: TClass): Integer;
178 function Extract(Item: TClass): TClass;
179 function Remove(AClass: TClass): Integer;
180 function IndexOf(AClass: TClass): Integer;
181 function First: TClass;
182 function Last: TClass;
183 function Find(const AClassName: string): TClass;
184 procedure GetClassNames(Strings: TStrings);
185 procedure Insert(Index: Integer; AClass: TClass);
186 property Items[Index: Integer]: TClass read GetItems write SetItems; default;
187 end;
188
189
190 PLinkedNode = ^TLinkedNode;
191 TLinkedNode = record
192 Prev: PLinkedNode;
193 Next: PLinkedNode;
194 Data: Pointer;
195 end;
196
197 TIteratorProc = procedure(Node: PLinkedNode; Index: Integer);
198
199 TFreeDataEvent = procedure(Data: Pointer) of object;
200
201 { TLinkedList }
202 { A class for maintaining a linked list }
203 TLinkedList = class
204 private
205 FCount: Integer;
206 FHead: PLinkedNode;
207 FTail: PLinkedNode;
208 FOnFreeData: TFreeDataEvent;
209 protected
210 procedure DoFreeData(Data: Pointer); virtual;
211 public
212 destructor Destroy; override;
213 function Add: PLinkedNode;
214 procedure Remove(Node: PLinkedNode);
215 function IndexOf(Node: PLinkedNode): Integer;
216 function GetNode(Index: Integer): PLinkedNode;
217 procedure Exchange(Node1, Node2: PLinkedNode);
218 procedure InsertBefore(Node, NewNode: PLinkedNode);
219 procedure InsertAfter(Node, NewNode: PLinkedNode);
220 procedure Clear;
221 procedure IterateList(CallBack: TIteratorProc);
222 property Head: PLinkedNode read FHead write FHead;
223 property Tail: PLinkedNode read FTail write FTail;
224 property Count: Integer read FCount write FCount;
225 property OnFreeData: TFreeDataEvent read FOnFreeData write FOnFreeData;
226 end;
227
228
229procedure SmartAssign(Src, Dst: TPersistent; TypeKinds: TTypeKinds = tkProperties);
230procedure Advance(var Node: PLinkedNode; Steps: Integer = 1);
231
232implementation
233
234uses
235 GR32_LowLevel;
236
237procedure SmartAssign(Src, Dst: TPersistent; TypeKinds: TTypeKinds = tkProperties);
238var
239 Count, I: Integer;
240 Props: PPropList;
241 SubSrc, SubDst: TPersistent;
242begin
243 Count := GetTypeData(Src.ClassInfo).PropCount;
244 if Count = 0 then Exit;
245
246 GetMem(Props, Count * SizeOf(PPropInfo));
247 try
248 // Get the property list in an unsorted fashion.
249 // This is important so the order in which the properties are defined is obeyed,
250 // ie. mimic how the Delphi form loader would set the properties.
251 Count := GetPropList(Src.ClassInfo, TypeKinds, Props, False);
252
253 {$IFNDEF NEXTGEN}
254 for I := 0 to Count - 1 do
255 with Props^[I]^ do
256 begin
257 if PropType^.Kind = tkClass then
258 begin
259 // TODO DVT Added cast to fix ShortString to String warnings. Need to verify is OK
260 SubDst := TPersistent(GetObjectProp(Dst, string(Name)));
261 if not Assigned(SubDst) then Continue;
262
263 SubSrc := TPersistent(GetObjectProp(Src, string(Name)));
264 if Assigned(SubSrc) then SubDst.Assign(SubSrc);
265 end
266 else
267 SetPropValue(Dst, string(Name), GetPropValue(Src, string(Name), True));
268 end;
269 {$ENDIF}
270 finally
271 FreeMem(Props, Count * SizeOf(PPropInfo));
272 end;
273end;
274
275procedure Advance(var Node: PLinkedNode; Steps: Integer);
276begin
277 if Steps > 0 then
278 begin
279 while Assigned(Node) and (Steps > 0) do
280 begin
281 Dec(Steps);
282 Node := Node.Next;
283 end;
284 end
285 else
286 begin
287 while Assigned(Node) and (Steps < 0) do
288 begin
289 Inc(Steps);
290 Node := Node.Prev;
291 end;
292 end;
293end;
294
295
296{ TPointerMap }
297
298function TPointerMap.Add(NewItem: PItem; NewData: PData): PPData;
299var
300 Dummy: Boolean;
301begin
302 Result := Add(NewItem, NewData, Dummy);
303end;
304
305function TPointerMap.Add(NewItem: PItem): PPData;
306var
307 Dummy: Boolean;
308begin
309 Result := Add(NewItem, nil, Dummy);
310end;
311
312function TPointerMap.Add(NewItem: PItem; out IsNew: Boolean): PPData;
313begin
314 Result := Add(NewItem, nil, IsNew);
315end;
316
317function TPointerMap.Add(NewItem: PItem; NewData: PData; out IsNew: Boolean): PPData;
318var
319 BucketIndex, ItemIndex, Capacity: Integer;
320begin
321 if Exists(NewItem, BucketIndex, ItemIndex) then
322 begin
323 IsNew := False;
324 Result := @FBuckets[BucketIndex].Items[ItemIndex].Data
325 end
326 else
327 begin
328 with FBuckets[BucketIndex] do
329 begin
330 Capacity := Length(Items);
331
332 // enlarge capacity if completely used
333 if Count = Capacity then
334 begin
335 if Capacity > 64 then
336 Inc(Capacity, Capacity div 4)
337 else if Capacity > 8 then
338 Inc(Capacity, 16)
339 else
340 Inc(Capacity, 4);
341
342 SetLength(Items, Capacity);
343 end;
344
345 with Items[Count] do
346 begin
347 Item := NewItem;
348 Data := NewData;
349 Result := @Data;
350 end;
351
352 Inc(Count);
353 IsNew := True;
354 end;
355 Inc(FCount);
356 end;
357end;
358
359procedure TPointerMap.Clear;
360var
361 BucketIndex, ItemIndex: Integer;
362begin
363 FCount := 0;
364
365 for BucketIndex := 0 to BUCKET_MASK do
366 with FBuckets[BucketIndex] do
367 begin
368 for ItemIndex := Count - 1 downto 0 do
369 Delete(BucketIndex, ItemIndex);
370
371 Count := 0;
372 SetLength(Items, 0);
373 end;
374end;
375
376destructor TPointerMap.Destroy;
377begin
378 Clear;
379 inherited Destroy;
380end;
381
382function TPointerMap.Delete(BucketIndex, ItemIndex: Integer): PData;
383begin
384 with FBuckets[BucketIndex] do
385 begin
386 Result := Items[ItemIndex].Data;
387
388 if FCount = 0 then Exit;
389
390 Dec(Count);
391 if Count = 0 then
392 SetLength(Items, 0)
393 else
394 if (ItemIndex < Count) then
395 Move(Items[ItemIndex + 1], Items[ItemIndex], (Count - ItemIndex) * SizeOf(TPointerBucketItem));
396 end;
397 Dec(FCount);
398end;
399
400function TPointerMap.Remove(Item: PItem): PData;
401var
402 BucketIndex, ItemIndex: Integer;
403begin
404 if Exists(Item, BucketIndex, ItemIndex) then
405 Result := Delete(BucketIndex, ItemIndex)
406 else
407 Result := nil;
408end;
409
410function TPointerMap.Contains(Item: PItem): Boolean;
411var
412 Dummy: Integer;
413begin
414 Result := Exists(Item, Dummy, Dummy);
415end;
416
417function TPointerMap.Find(Item: PItem; out Data: PPData): Boolean;
418var
419 BucketIndex, ItemIndex: Integer;
420begin
421 Result := Exists(Item, BucketIndex, ItemIndex);
422 if Result then
423 Data := @FBuckets[BucketIndex].Items[ItemIndex].Data;
424end;
425
426function TPointerMap.Exists(Item: PItem; out BucketIndex, ItemIndex: Integer): Boolean;
427var
428 I: Integer;
429begin
430{$IFDEF HAS_NATIVEINT}
431 BucketIndex := NativeUInt(Item) shr 8 and BUCKET_MASK; // KISS pointer hash(TM)
432{$ELSE}
433 BucketIndex := Cardinal(Item) shr 8 and BUCKET_MASK; // KISS pointer hash(TM)
434{$ENDIF}
435 // due to their randomness, pointers most commonly differ at byte 1, we use
436 // this characteristic for our hash and just apply the mask to it.
437 // Worst case scenario happens when most changes are at byte 0, which causes
438 // one bucket to be saturated whereas the other buckets are almost empty...
439
440 Result := False;
441 with FBuckets[BucketIndex] do
442 for I := 0 to Count - 1 do
443 if Items[I].Item = Item then
444 begin
445 ItemIndex := I;
446 Result := True;
447 Exit;
448 end;
449end;
450
451function TPointerMap.GetData(Item: PItem): PData;
452var
453 BucketIndex, ItemIndex: Integer;
454begin
455 if not Exists(Item, BucketIndex, ItemIndex) then
456{$IFDEF FPC}
457 raise EListError.CreateFmt(SItemNotFound, [Item])
458{$ELSE}
459{$IFDEF HAS_NATIVEINT}
460 raise EListError.CreateFmt(SItemNotFound, [NativeInt(Item)])
461{$ELSE}
462 raise EListError.CreateFmt(SItemNotFound, [Integer(Item)])
463{$ENDIF}
464{$ENDIF}
465 else
466 Result := FBuckets[BucketIndex].Items[ItemIndex].Data;
467end;
468
469procedure TPointerMap.SetData(Item: PItem; const Data: PData);
470var
471 BucketIndex, ItemIndex: Integer;
472begin
473 if not Exists(Item, BucketIndex, ItemIndex) then
474{$IFDEF FPC}
475 raise EListError.CreateFmt(SItemNotFound, [Item])
476{$ELSE}
477{$IFDEF HAS_NATIVEINT}
478 raise EListError.CreateFmt(SItemNotFound, [NativeInt(Item)])
479{$ELSE}
480 raise EListError.CreateFmt(SItemNotFound, [Integer(Item)])
481{$ENDIF}
482{$ENDIF}
483 else
484 FBuckets[BucketIndex].Items[ItemIndex].Data := Data;
485end;
486
487{ TPointerMapIterator }
488
489constructor TPointerMapIterator.Create(SrcPointerMap: TPointerMap);
490begin
491 inherited Create;
492 FSrcPointerMap := SrcPointerMap;
493
494 FCurBucketIndex := -1;
495 FCurItemIndex := -1;
496end;
497
498function TPointerMapIterator.Next: Boolean;
499begin
500 if FCurItemIndex > 0 then
501 Dec(FCurItemIndex)
502 else
503 begin
504 FCurItemIndex := -1;
505 while (FCurBucketIndex < BUCKET_MASK) and (FCurItemIndex = -1) do
506 begin
507 Inc(FCurBucketIndex);
508 FCurItemIndex := FSrcPointerMap.FBuckets[FCurBucketIndex].Count - 1;
509 end;
510
511 if FCurBucketIndex = BUCKET_MASK then
512 begin
513 Result := False;
514 Exit;
515 end
516 end;
517
518 Result := True;
519 with FSrcPointerMap.FBuckets[FCurBucketIndex].Items[FCurItemIndex] do
520 begin
521 FItem := Item;
522 FData := Data;
523 end;
524end;
525
526
527{ TRectList }
528
529destructor TRectList.Destroy;
530begin
531 SetCount(0);
532 SetCapacity(0);
533end;
534
535function TRectList.Add(const Rect: TRect): Integer;
536begin
537 Result := FCount;
538 if Result = FCapacity then
539 Grow;
540 FList^[Result] := Rect;
541 Inc(FCount);
542end;
543
544procedure TRectList.Clear;
545begin
546 SetCount(0);
547 SetCapacity(10);
548end;
549
550procedure TRectList.Delete(Index: Integer);
551begin
552 Dec(FCount);
553 if Index < FCount then
554 System.Move(FList^[Index + 1], FList^[Index],
555 (FCount - Index) * SizeOf(TRect));
556end;
557
558procedure TRectList.Exchange(Index1, Index2: Integer);
559var
560 Item: TRect;
561begin
562 Item := FList^[Index1];
563 FList^[Index1] := FList^[Index2];
564 FList^[Index2] := Item;
565end;
566
567function TRectList.Get(Index: Integer): PRect;
568begin
569 if (Index < 0) or (Index >= FCount) then
570 Result := nil
571 else
572 Result := @FList^[Index];
573end;
574
575procedure TRectList.Grow;
576var
577 Delta: Integer;
578begin
579 if FCapacity > 128 then
580 Delta := FCapacity div 4
581 else
582 if FCapacity > 8 then
583 Delta := 32
584 else
585 Delta := 8;
586 SetCapacity(FCapacity + Delta);
587end;
588
589function TRectList.IndexOf(const Rect: TRect): Integer;
590begin
591 Result := 0;
592 while (Result < FCount) and not EqualRect(FList^[Result], Rect) do
593 Inc(Result);
594 if Result = FCount then
595 Result := -1;
596end;
597
598procedure TRectList.Insert(Index: Integer; const Rect: TRect);
599begin
600 if FCount = FCapacity then
601 Grow;
602 if Index < FCount then
603 System.Move(FList^[Index], FList^[Index + 1],
604 (FCount - Index) * SizeOf(TRect));
605 FList^[Index] := Rect;
606 Inc(FCount);
607end;
608
609procedure TRectList.Move(CurIndex, NewIndex: Integer);
610var
611 Item: TRect;
612begin
613 if CurIndex <> NewIndex then
614 begin
615 Item := Get(CurIndex)^;
616 Delete(CurIndex);
617 Insert(NewIndex, Item);
618 end;
619end;
620
621function TRectList.Remove(const Rect: TRect): Integer;
622begin
623 Result := IndexOf(Rect);
624 if Result >= 0 then
625 Delete(Result);
626end;
627
628procedure TRectList.Pack;
629var
630 I: Integer;
631begin
632 for I := FCount - 1 downto 0 do
633 if Items[I] = nil then
634 Delete(I);
635end;
636
637procedure TRectList.SetCapacity(NewCapacity: Integer);
638begin
639 if NewCapacity <> FCapacity then
640 begin
641 ReallocMem(FList, NewCapacity * SizeOf(TRect));
642 FCapacity := NewCapacity;
643 end;
644end;
645
646procedure TRectList.SetCount(NewCount: Integer);
647var
648 I: Integer;
649begin
650 if NewCount > FCapacity then
651 SetCapacity(NewCount);
652 if NewCount > FCount then
653 FillChar(FList^[FCount], (NewCount - FCount) * SizeOf(TRect), 0)
654 else
655 for I := FCount - 1 downto NewCount do
656 Delete(I);
657 FCount := NewCount;
658end;
659
660{ TClassList }
661
662function TClassList.Add(AClass: TClass): Integer;
663begin
664 Result := inherited Add(AClass);
665end;
666
667function TClassList.Extract(Item: TClass): TClass;
668begin
669 Result := TClass(inherited Extract(Item));
670end;
671
672function TClassList.Find(const AClassName: string): TClass;
673var
674 I: Integer;
675begin
676 Result := nil;
677 for I := 0 to Count - 1 do
678 if TClass(List[I]).ClassName = AClassName then
679 begin
680 Result := TClass(List[I]);
681 Break;
682 end;
683end;
684
685function TClassList.First: TClass;
686begin
687 Result := TClass(inherited First);
688end;
689
690procedure TClassList.GetClassNames(Strings: TStrings);
691var
692 I: Integer;
693begin
694 for I := 0 to Count - 1 do
695 Strings.Add(TClass(List[I]).ClassName);
696end;
697
698function TClassList.GetItems(Index: Integer): TClass;
699begin
700 Result := TClass(inherited Items[Index]);
701end;
702
703function TClassList.IndexOf(AClass: TClass): Integer;
704begin
705 Result := inherited IndexOf(AClass);
706end;
707
708procedure TClassList.Insert(Index: Integer; AClass: TClass);
709begin
710 inherited Insert(Index, AClass);
711end;
712
713function TClassList.Last: TClass;
714begin
715 Result := TClass(inherited Last);
716end;
717
718function TClassList.Remove(AClass: TClass): Integer;
719begin
720 Result := inherited Remove(AClass);
721end;
722
723procedure TClassList.SetItems(Index: Integer; AClass: TClass);
724begin
725 inherited Items[Index] := AClass;
726end;
727
728{ TLinkedList }
729
730function TLinkedList.Add: PLinkedNode;
731begin
732 New(Result);
733 Result.Data := nil;
734 Result.Next := nil;
735 Result.Prev := nil;
736 if Head = nil then
737 begin
738 Head := Result;
739 Tail := Result;
740 end
741 else
742 InsertAfter(FTail, Result);
743end;
744
745procedure TLinkedList.Clear;
746var
747 P, NextP: PLinkedNode;
748begin
749 P := Head;
750 while Assigned(P) do
751 begin
752 NextP := P.Next;
753 DoFreeData(P.Data);
754 Dispose(P);
755 P := NextP;
756 end;
757 Head := nil;
758 Tail := nil;
759 Count := 0;
760end;
761
762destructor TLinkedList.Destroy;
763begin
764 Clear;
765end;
766
767procedure TLinkedList.DoFreeData(Data: Pointer);
768begin
769 if Assigned(FOnFreeData) then FOnFreeData(Data);
770end;
771
772procedure TLinkedList.Exchange(Node1, Node2: PLinkedNode);
773begin
774 if Assigned(Node1) and Assigned(Node2) and (Node1 <> Node2) then
775 begin
776 if Assigned(Node1.Prev) then Node1.Prev.Next := Node2;
777 if Assigned(Node1.Next) then Node1.Next.Prev := Node2;
778 if Assigned(Node2.Prev) then Node2.Prev.Next := Node1;
779 if Assigned(Node2.Next) then Node2.Next.Prev := Node1;
780 if Head = Node1 then Head := Node2 else if Head = Node2 then Head := Node1;
781 if Tail = Node1 then Tail := Node2 else if Tail = Node2 then Tail := Node1;
782 Swap(Pointer(Node1.Next), Pointer(Node2.Next));
783 Swap(Pointer(Node1.Prev), Pointer(Node2.Prev));
784 end;
785end;
786
787function TLinkedList.GetNode(Index: Integer): PLinkedNode;
788begin
789 Result := Head;
790 Advance(Result, Index);
791end;
792
793function TLinkedList.IndexOf(Node: PLinkedNode): Integer;
794var
795 I: Integer;
796 P: PLinkedNode;
797begin
798 Result := -1;
799 P := Head;
800 for I := 0 to Count - 1 do
801 begin
802 if P = Node then
803 begin
804 Result := I;
805 Exit;
806 end;
807 P := P.Next;
808 end;
809end;
810
811procedure TLinkedList.InsertAfter(Node, NewNode: PLinkedNode);
812begin
813 if Assigned(Node) and Assigned(NewNode) then
814 begin
815 NewNode.Prev := Node;
816 NewNode.Next := Node.Next;
817 if Assigned(Node.Next) then Node.Next.Prev := NewNode;
818 Node.Next := NewNode;
819 if Node = Tail then Tail := NewNode;
820 Inc(FCount);
821 end;
822end;
823
824procedure TLinkedList.InsertBefore(Node, NewNode: PLinkedNode);
825begin
826 if Assigned(Node) and Assigned(NewNode) then
827 begin
828 NewNode.Next := Node;
829 NewNode.Prev := Node.Prev;
830 if Assigned(Node.Prev) then Node.Prev.Next := NewNode;
831 Node.Prev := NewNode;
832 if Node = Head then Head := NewNode;
833 Inc(FCount);
834 end;
835end;
836
837procedure TLinkedList.IterateList(CallBack: TIteratorProc);
838var
839 I: Integer;
840 P: PLinkedNode;
841begin
842 P := Head;
843 for I := 0 to Count - 1 do
844 begin
845 CallBack(P, I);
846 P := P.Next;
847 end;
848end;
849
850procedure TLinkedList.Remove(Node: PLinkedNode);
851begin
852 if Assigned(Node) then
853 begin
854 DoFreeData(Node.Data);
855 if Assigned(Node.Prev) then Node.Prev.Next := Node.Next;
856 if Assigned(Node.Next) then Node.Next.Prev := Node.Prev;
857 if Node = Head then Head := Node.Next;
858 if Node = Tail then Tail := Node.Prev;
859 Dispose(Node);
860 Dec(FCount);
861 end;
862end;
863
864end.
Note: See TracBrowser for help on using the repository browser.