📄 gr32_containers.pas
字号:
unit GR32_Containers;
(* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is Repaint Optimizer Extension for Graphics32
*
* The Initial Developer of the Original Code is
* Andre Beckedorf - metaException OHG
* Andre@metaException.de
*
* Portions created by the Initial Developer are Copyright (C) 2005-2006
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
*
* ***** END LICENSE BLOCK ***** *)
interface
{$I GR32.inc}
uses
{$IFDEF CLX}
Qt, Types, {$IFDEF LINUX}Libc, {$ENDIF}
{$ELSE}
Windows,
{$ENDIF}
{$IFDEF COMPILER6}RTLConsts, {$ENDIF}
GR32, SysUtils, GR32_LowLevel, Classes, TypInfo;
{$IFNDEF COMPILER6}
const
SItemNotFound = 'Item not found ($0%x)';
{$ENDIF}
const
BUCKET_MASK = $FF;
BUCKET_COUNT = BUCKET_MASK + 1; // 256 buckets by default
type
PPItem = ^PItem;
PItem = Pointer;
PPData = ^PData;
PData = Pointer;
PPointerBucketItem = ^TPointerBucketItem;
TPointerBucketItem = record
Item: PItem;
Data: PData;
end;
TPointerBucketItemArray = array of TPointerBucketItem;
TPointerBucket = record
Count: Integer;
Items: TPointerBucketItemArray;
end;
TPointerBucketArray = array[0..BUCKET_MASK] of TPointerBucket;
{ TPointerMap }
{ Associative pointer map
Inspired by TBucketList, which is not available on D5/CB5, it is
reimplemented from scratch, simple, optimized and light-weight.
Not thread-safe. Does use exceptions only for Data property. }
TPointerMap = class
private
FBuckets: TPointerBucketArray;
FCount: Integer;
protected
function GetData(Item: PItem): PData;
procedure SetData(Item: PItem; const Data: PData);
function Exists(Item: Pointer; out BucketIndex, ItemIndex: Integer): Boolean;
function Delete(BucketIndex, ItemIndex: Integer): PData; virtual;
public
destructor Destroy; override;
function Add(NewItem: PItem): PPData; overload;
function Add(NewItem: PItem; out IsNew: Boolean): PPData; overload;
function Add(NewItem: PItem; NewData: PData): PPData; overload;
function Add(NewItem: PItem; NewData: PData; out IsNew: Boolean): PPData; overload;
function Remove(Item: PItem): PData;
procedure Clear;
function Contains(Item: PItem): Boolean;
function Find(Item: PItem; out Data: PPData): Boolean;
property Data[Item: PItem]: PData read GetData write SetData; default;
property Count: Integer read FCount;
end;
{ TPointerMapIterator }
{ Iterator object for the associative pointer map
See below for usage example... }
TPointerMapIterator = class
private
FSrcPointerMap: TPointerMap;
FItem: PItem;
FData: PData;
FCurBucketIndex: Integer;
FCurItemIndex: Integer;
public
constructor Create(SrcPointerMap: TPointerMap);
function Next: Boolean;
property Item: PItem read FItem;
property Data: PData read FData;
end;
{
USAGE EXAMPLE:
--------------
with TPointerMapIterator.Create(MyPointerMap) do
try
while Next do
begin
// do something with Item and Data here...
end;
finally
Free;
end;
}
PPolyRects = ^TPolyRects;
TPolyRects = Array[0..Maxint div 32 - 1] of TRect;
{ TRectList }
{ List that holds Rects
Do not reuse TList due to pointer structure.
A direct structure is more memory efficient.
stripped version of TList blatantly stolen from Classes.pas }
TRectList = class
private
FList: PPolyRects;
FCount: Integer;
FCapacity: Integer;
protected
function Get(Index: Integer): PRect;
procedure Grow; virtual;
procedure SetCapacity(NewCapacity: Integer);
procedure SetCount(NewCount: Integer);
public
destructor Destroy; override;
function Add(const Rect: TRect): Integer;
procedure Clear; virtual;
procedure Delete(Index: Integer);
procedure Exchange(Index1, Index2: Integer);
function IndexOf(const Rect: TRect): Integer;
procedure Insert(Index: Integer; const Rect: TRect);
procedure Move(CurIndex, NewIndex: Integer);
function Remove(const Rect: TRect): Integer;
procedure Pack;
property Capacity: Integer read FCapacity write SetCapacity;
property Count: Integer read FCount write SetCount;
property Items[Index: Integer]: PRect read Get; default;
property List: PPolyRects read FList;
end;
{ TClassList }
{ This is a class that maintains a list of classes. }
TClassList = class(TList)
protected
function GetItems(Index: Integer): TClass;
procedure SetItems(Index: Integer; AClass: TClass);
public
function Add(AClass: TClass): Integer;
function Extract(Item: TClass): TClass;
function Remove(AClass: TClass): Integer;
function IndexOf(AClass: TClass): Integer;
function First: TClass;
function Last: TClass;
function Find(AClassName: string): TClass;
procedure GetClassNames(Strings: TStrings);
procedure Insert(Index: Integer; AClass: TClass);
property Items[Index: Integer]: TClass read GetItems write SetItems; default;
end;
procedure SmartAssign(Src, Dst: TPersistent; TypeKinds: TTypeKinds = tkProperties);
implementation
procedure SmartAssign(Src, Dst: TPersistent; TypeKinds: TTypeKinds = tkProperties);
var
Count, I: Integer;
Props: PPropList;
SubSrc, SubDst: TPersistent;
begin
Count := GetTypeData(Src.ClassInfo).PropCount;
if Count = 0 then Exit;
GetMem(Props, Count * SizeOf(PPropInfo));
try
// Get the property list in an unsorted fashion.
// This is important so the order in which the properties are defined is obeyed,
// ie. mimic how the Delphi form loader would set the properties.
Count := GetPropList(Src.ClassInfo, TypeKinds, Props{$IFDEF COMPILER6}, False{$ENDIF});
for I := 0 to Count - 1 do
with Props^[I]^ do
begin
if PropType^.Kind = tkClass then
begin
SubDst := TPersistent(GetObjectProp(Dst, Name));
if not Assigned(SubDst) then Continue;
SubSrc := TPersistent(GetObjectProp(Src, Name));
if Assigned(SubSrc) then SubDst.Assign(SubSrc);
end
else
SetPropValue(Dst, Name, GetPropValue(Src, Name, False));
end;
finally
FreeMem(Props, Count * SizeOf(PPropInfo));
end;
end;
{ TPointerMap }
function TPointerMap.Add(NewItem: PItem; NewData: PData): PPData;
var
Dummy: Boolean;
begin
Result := Add(NewItem, NewData, Dummy);
end;
function TPointerMap.Add(NewItem: PItem): PPData;
var
Dummy: Boolean;
begin
Result := Add(NewItem, nil, Dummy);
end;
function TPointerMap.Add(NewItem: PItem; out IsNew: Boolean): PPData;
begin
Result := Add(NewItem, nil, IsNew);
end;
function TPointerMap.Add(NewItem: PItem; NewData: PData; out IsNew: Boolean): PPData;
var
BucketIndex, ItemIndex, Capacity: Integer;
begin
if Exists(NewItem, BucketIndex, ItemIndex) then
begin
IsNew := False;
Result := @FBuckets[BucketIndex].Items[ItemIndex].Data
end
else
begin
with FBuckets[BucketIndex] do
begin
Capacity := Length(Items);
// enlarge capacity if completely used
if Count = Capacity then
begin
if Capacity > 64 then
Inc(Capacity, Capacity div 4)
else if Capacity > 8 then
Inc(Capacity, 16)
else
Inc(Capacity, 4);
SetLength(Items, Capacity);
end;
with Items[Count] do
begin
Item := NewItem;
Data := NewData;
Result := @Data;
end;
Inc(Count);
IsNew := True;
end;
Inc(FCount);
end;
end;
procedure TPointerMap.Clear;
var
BucketIndex, ItemIndex: Integer;
begin
FCount := 0;
for BucketIndex := 0 to BUCKET_MASK do
with FBuckets[BucketIndex] do
begin
for ItemIndex := Count - 1 downto 0 do
Delete(BucketIndex, ItemIndex);
Count := 0;
SetLength(Items, 0);
end;
end;
destructor TPointerMap.Destroy;
begin
Clear;
inherited Destroy;
end;
function TPointerMap.Delete(BucketIndex, ItemIndex: Integer): PData;
begin
with FBuckets[BucketIndex] do
begin
Result := Items[ItemIndex].Data;
if FCount = 0 then Exit;
if Count = 1 then
SetLength(Items, 0)
else
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -