1 | unit 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 |
|
---|
36 | interface
|
---|
37 |
|
---|
38 | {$I GR32.inc}
|
---|
39 |
|
---|
40 | uses
|
---|
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 |
|
---|
53 | const
|
---|
54 | BUCKET_MASK = $FF;
|
---|
55 | BUCKET_COUNT = BUCKET_MASK + 1; // 256 buckets by default
|
---|
56 |
|
---|
57 | type
|
---|
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 |
|
---|
229 | procedure SmartAssign(Src, Dst: TPersistent; TypeKinds: TTypeKinds = tkProperties);
|
---|
230 | procedure Advance(var Node: PLinkedNode; Steps: Integer = 1);
|
---|
231 |
|
---|
232 | implementation
|
---|
233 |
|
---|
234 | uses
|
---|
235 | GR32_LowLevel;
|
---|
236 |
|
---|
237 | procedure SmartAssign(Src, Dst: TPersistent; TypeKinds: TTypeKinds = tkProperties);
|
---|
238 | var
|
---|
239 | Count, I: Integer;
|
---|
240 | Props: PPropList;
|
---|
241 | SubSrc, SubDst: TPersistent;
|
---|
242 | begin
|
---|
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;
|
---|
273 | end;
|
---|
274 |
|
---|
275 | procedure Advance(var Node: PLinkedNode; Steps: Integer);
|
---|
276 | begin
|
---|
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;
|
---|
293 | end;
|
---|
294 |
|
---|
295 |
|
---|
296 | { TPointerMap }
|
---|
297 |
|
---|
298 | function TPointerMap.Add(NewItem: PItem; NewData: PData): PPData;
|
---|
299 | var
|
---|
300 | Dummy: Boolean;
|
---|
301 | begin
|
---|
302 | Result := Add(NewItem, NewData, Dummy);
|
---|
303 | end;
|
---|
304 |
|
---|
305 | function TPointerMap.Add(NewItem: PItem): PPData;
|
---|
306 | var
|
---|
307 | Dummy: Boolean;
|
---|
308 | begin
|
---|
309 | Result := Add(NewItem, nil, Dummy);
|
---|
310 | end;
|
---|
311 |
|
---|
312 | function TPointerMap.Add(NewItem: PItem; out IsNew: Boolean): PPData;
|
---|
313 | begin
|
---|
314 | Result := Add(NewItem, nil, IsNew);
|
---|
315 | end;
|
---|
316 |
|
---|
317 | function TPointerMap.Add(NewItem: PItem; NewData: PData; out IsNew: Boolean): PPData;
|
---|
318 | var
|
---|
319 | BucketIndex, ItemIndex, Capacity: Integer;
|
---|
320 | begin
|
---|
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;
|
---|
357 | end;
|
---|
358 |
|
---|
359 | procedure TPointerMap.Clear;
|
---|
360 | var
|
---|
361 | BucketIndex, ItemIndex: Integer;
|
---|
362 | begin
|
---|
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;
|
---|
374 | end;
|
---|
375 |
|
---|
376 | destructor TPointerMap.Destroy;
|
---|
377 | begin
|
---|
378 | Clear;
|
---|
379 | inherited Destroy;
|
---|
380 | end;
|
---|
381 |
|
---|
382 | function TPointerMap.Delete(BucketIndex, ItemIndex: Integer): PData;
|
---|
383 | begin
|
---|
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);
|
---|
398 | end;
|
---|
399 |
|
---|
400 | function TPointerMap.Remove(Item: PItem): PData;
|
---|
401 | var
|
---|
402 | BucketIndex, ItemIndex: Integer;
|
---|
403 | begin
|
---|
404 | if Exists(Item, BucketIndex, ItemIndex) then
|
---|
405 | Result := Delete(BucketIndex, ItemIndex)
|
---|
406 | else
|
---|
407 | Result := nil;
|
---|
408 | end;
|
---|
409 |
|
---|
410 | function TPointerMap.Contains(Item: PItem): Boolean;
|
---|
411 | var
|
---|
412 | Dummy: Integer;
|
---|
413 | begin
|
---|
414 | Result := Exists(Item, Dummy, Dummy);
|
---|
415 | end;
|
---|
416 |
|
---|
417 | function TPointerMap.Find(Item: PItem; out Data: PPData): Boolean;
|
---|
418 | var
|
---|
419 | BucketIndex, ItemIndex: Integer;
|
---|
420 | begin
|
---|
421 | Result := Exists(Item, BucketIndex, ItemIndex);
|
---|
422 | if Result then
|
---|
423 | Data := @FBuckets[BucketIndex].Items[ItemIndex].Data;
|
---|
424 | end;
|
---|
425 |
|
---|
426 | function TPointerMap.Exists(Item: PItem; out BucketIndex, ItemIndex: Integer): Boolean;
|
---|
427 | var
|
---|
428 | I: Integer;
|
---|
429 | begin
|
---|
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;
|
---|
449 | end;
|
---|
450 |
|
---|
451 | function TPointerMap.GetData(Item: PItem): PData;
|
---|
452 | var
|
---|
453 | BucketIndex, ItemIndex: Integer;
|
---|
454 | begin
|
---|
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;
|
---|
467 | end;
|
---|
468 |
|
---|
469 | procedure TPointerMap.SetData(Item: PItem; const Data: PData);
|
---|
470 | var
|
---|
471 | BucketIndex, ItemIndex: Integer;
|
---|
472 | begin
|
---|
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;
|
---|
485 | end;
|
---|
486 |
|
---|
487 | { TPointerMapIterator }
|
---|
488 |
|
---|
489 | constructor TPointerMapIterator.Create(SrcPointerMap: TPointerMap);
|
---|
490 | begin
|
---|
491 | inherited Create;
|
---|
492 | FSrcPointerMap := SrcPointerMap;
|
---|
493 |
|
---|
494 | FCurBucketIndex := -1;
|
---|
495 | FCurItemIndex := -1;
|
---|
496 | end;
|
---|
497 |
|
---|
498 | function TPointerMapIterator.Next: Boolean;
|
---|
499 | begin
|
---|
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;
|
---|
524 | end;
|
---|
525 |
|
---|
526 |
|
---|
527 | { TRectList }
|
---|
528 |
|
---|
529 | destructor TRectList.Destroy;
|
---|
530 | begin
|
---|
531 | SetCount(0);
|
---|
532 | SetCapacity(0);
|
---|
533 | end;
|
---|
534 |
|
---|
535 | function TRectList.Add(const Rect: TRect): Integer;
|
---|
536 | begin
|
---|
537 | Result := FCount;
|
---|
538 | if Result = FCapacity then
|
---|
539 | Grow;
|
---|
540 | FList^[Result] := Rect;
|
---|
541 | Inc(FCount);
|
---|
542 | end;
|
---|
543 |
|
---|
544 | procedure TRectList.Clear;
|
---|
545 | begin
|
---|
546 | SetCount(0);
|
---|
547 | SetCapacity(10);
|
---|
548 | end;
|
---|
549 |
|
---|
550 | procedure TRectList.Delete(Index: Integer);
|
---|
551 | begin
|
---|
552 | Dec(FCount);
|
---|
553 | if Index < FCount then
|
---|
554 | System.Move(FList^[Index + 1], FList^[Index],
|
---|
555 | (FCount - Index) * SizeOf(TRect));
|
---|
556 | end;
|
---|
557 |
|
---|
558 | procedure TRectList.Exchange(Index1, Index2: Integer);
|
---|
559 | var
|
---|
560 | Item: TRect;
|
---|
561 | begin
|
---|
562 | Item := FList^[Index1];
|
---|
563 | FList^[Index1] := FList^[Index2];
|
---|
564 | FList^[Index2] := Item;
|
---|
565 | end;
|
---|
566 |
|
---|
567 | function TRectList.Get(Index: Integer): PRect;
|
---|
568 | begin
|
---|
569 | if (Index < 0) or (Index >= FCount) then
|
---|
570 | Result := nil
|
---|
571 | else
|
---|
572 | Result := @FList^[Index];
|
---|
573 | end;
|
---|
574 |
|
---|
575 | procedure TRectList.Grow;
|
---|
576 | var
|
---|
577 | Delta: Integer;
|
---|
578 | begin
|
---|
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);
|
---|
587 | end;
|
---|
588 |
|
---|
589 | function TRectList.IndexOf(const Rect: TRect): Integer;
|
---|
590 | begin
|
---|
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;
|
---|
596 | end;
|
---|
597 |
|
---|
598 | procedure TRectList.Insert(Index: Integer; const Rect: TRect);
|
---|
599 | begin
|
---|
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);
|
---|
607 | end;
|
---|
608 |
|
---|
609 | procedure TRectList.Move(CurIndex, NewIndex: Integer);
|
---|
610 | var
|
---|
611 | Item: TRect;
|
---|
612 | begin
|
---|
613 | if CurIndex <> NewIndex then
|
---|
614 | begin
|
---|
615 | Item := Get(CurIndex)^;
|
---|
616 | Delete(CurIndex);
|
---|
617 | Insert(NewIndex, Item);
|
---|
618 | end;
|
---|
619 | end;
|
---|
620 |
|
---|
621 | function TRectList.Remove(const Rect: TRect): Integer;
|
---|
622 | begin
|
---|
623 | Result := IndexOf(Rect);
|
---|
624 | if Result >= 0 then
|
---|
625 | Delete(Result);
|
---|
626 | end;
|
---|
627 |
|
---|
628 | procedure TRectList.Pack;
|
---|
629 | var
|
---|
630 | I: Integer;
|
---|
631 | begin
|
---|
632 | for I := FCount - 1 downto 0 do
|
---|
633 | if Items[I] = nil then
|
---|
634 | Delete(I);
|
---|
635 | end;
|
---|
636 |
|
---|
637 | procedure TRectList.SetCapacity(NewCapacity: Integer);
|
---|
638 | begin
|
---|
639 | if NewCapacity <> FCapacity then
|
---|
640 | begin
|
---|
641 | ReallocMem(FList, NewCapacity * SizeOf(TRect));
|
---|
642 | FCapacity := NewCapacity;
|
---|
643 | end;
|
---|
644 | end;
|
---|
645 |
|
---|
646 | procedure TRectList.SetCount(NewCount: Integer);
|
---|
647 | var
|
---|
648 | I: Integer;
|
---|
649 | begin
|
---|
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;
|
---|
658 | end;
|
---|
659 |
|
---|
660 | { TClassList }
|
---|
661 |
|
---|
662 | function TClassList.Add(AClass: TClass): Integer;
|
---|
663 | begin
|
---|
664 | Result := inherited Add(AClass);
|
---|
665 | end;
|
---|
666 |
|
---|
667 | function TClassList.Extract(Item: TClass): TClass;
|
---|
668 | begin
|
---|
669 | Result := TClass(inherited Extract(Item));
|
---|
670 | end;
|
---|
671 |
|
---|
672 | function TClassList.Find(const AClassName: string): TClass;
|
---|
673 | var
|
---|
674 | I: Integer;
|
---|
675 | begin
|
---|
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;
|
---|
683 | end;
|
---|
684 |
|
---|
685 | function TClassList.First: TClass;
|
---|
686 | begin
|
---|
687 | Result := TClass(inherited First);
|
---|
688 | end;
|
---|
689 |
|
---|
690 | procedure TClassList.GetClassNames(Strings: TStrings);
|
---|
691 | var
|
---|
692 | I: Integer;
|
---|
693 | begin
|
---|
694 | for I := 0 to Count - 1 do
|
---|
695 | Strings.Add(TClass(List[I]).ClassName);
|
---|
696 | end;
|
---|
697 |
|
---|
698 | function TClassList.GetItems(Index: Integer): TClass;
|
---|
699 | begin
|
---|
700 | Result := TClass(inherited Items[Index]);
|
---|
701 | end;
|
---|
702 |
|
---|
703 | function TClassList.IndexOf(AClass: TClass): Integer;
|
---|
704 | begin
|
---|
705 | Result := inherited IndexOf(AClass);
|
---|
706 | end;
|
---|
707 |
|
---|
708 | procedure TClassList.Insert(Index: Integer; AClass: TClass);
|
---|
709 | begin
|
---|
710 | inherited Insert(Index, AClass);
|
---|
711 | end;
|
---|
712 |
|
---|
713 | function TClassList.Last: TClass;
|
---|
714 | begin
|
---|
715 | Result := TClass(inherited Last);
|
---|
716 | end;
|
---|
717 |
|
---|
718 | function TClassList.Remove(AClass: TClass): Integer;
|
---|
719 | begin
|
---|
720 | Result := inherited Remove(AClass);
|
---|
721 | end;
|
---|
722 |
|
---|
723 | procedure TClassList.SetItems(Index: Integer; AClass: TClass);
|
---|
724 | begin
|
---|
725 | inherited Items[Index] := AClass;
|
---|
726 | end;
|
---|
727 |
|
---|
728 | { TLinkedList }
|
---|
729 |
|
---|
730 | function TLinkedList.Add: PLinkedNode;
|
---|
731 | begin
|
---|
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);
|
---|
743 | end;
|
---|
744 |
|
---|
745 | procedure TLinkedList.Clear;
|
---|
746 | var
|
---|
747 | P, NextP: PLinkedNode;
|
---|
748 | begin
|
---|
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;
|
---|
760 | end;
|
---|
761 |
|
---|
762 | destructor TLinkedList.Destroy;
|
---|
763 | begin
|
---|
764 | Clear;
|
---|
765 | end;
|
---|
766 |
|
---|
767 | procedure TLinkedList.DoFreeData(Data: Pointer);
|
---|
768 | begin
|
---|
769 | if Assigned(FOnFreeData) then FOnFreeData(Data);
|
---|
770 | end;
|
---|
771 |
|
---|
772 | procedure TLinkedList.Exchange(Node1, Node2: PLinkedNode);
|
---|
773 | begin
|
---|
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;
|
---|
785 | end;
|
---|
786 |
|
---|
787 | function TLinkedList.GetNode(Index: Integer): PLinkedNode;
|
---|
788 | begin
|
---|
789 | Result := Head;
|
---|
790 | Advance(Result, Index);
|
---|
791 | end;
|
---|
792 |
|
---|
793 | function TLinkedList.IndexOf(Node: PLinkedNode): Integer;
|
---|
794 | var
|
---|
795 | I: Integer;
|
---|
796 | P: PLinkedNode;
|
---|
797 | begin
|
---|
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;
|
---|
809 | end;
|
---|
810 |
|
---|
811 | procedure TLinkedList.InsertAfter(Node, NewNode: PLinkedNode);
|
---|
812 | begin
|
---|
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;
|
---|
822 | end;
|
---|
823 |
|
---|
824 | procedure TLinkedList.InsertBefore(Node, NewNode: PLinkedNode);
|
---|
825 | begin
|
---|
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;
|
---|
835 | end;
|
---|
836 |
|
---|
837 | procedure TLinkedList.IterateList(CallBack: TIteratorProc);
|
---|
838 | var
|
---|
839 | I: Integer;
|
---|
840 | P: PLinkedNode;
|
---|
841 | begin
|
---|
842 | P := Head;
|
---|
843 | for I := 0 to Count - 1 do
|
---|
844 | begin
|
---|
845 | CallBack(P, I);
|
---|
846 | P := P.Next;
|
---|
847 | end;
|
---|
848 | end;
|
---|
849 |
|
---|
850 | procedure TLinkedList.Remove(Node: PLinkedNode);
|
---|
851 | begin
|
---|
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;
|
---|
862 | end;
|
---|
863 |
|
---|
864 | end.
|
---|