| 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.
|
|---|