{ ***************************************************************************** This file is part of the Lazarus Component Library (LCL) See the file COPYING.modifiedLGPL.txt, included in this distribution, for details about the license. ***************************************************************************** Author: Mattias Gaertner Abstract: Types and methods to cache interface resources. See graphics.pp for examples. } unit LCLResCache; {$mode objfpc}{$H+} interface uses Classes, SysUtils, Types, Laz_AVL_Tree, // LazUtils FPCAdds, LazLoggerBase, LazTracer, // LCL LCLType, WSReferences, syncobjs; // This FCL unit must be in the end. {off $DEFINE CheckResCacheConsistency} type TResourceCache = class; TResourceCacheDescriptor = class; { TResourceCacheItem } TResourceCacheItem = class protected FDestroying: boolean; FReferenceCount: integer; public Handle: TLCLHandle; Cache: TResourceCache; FirstDescriptor, LastDescriptor: TResourceCacheDescriptor; Next, Prev: TResourceCacheItem; constructor Create(TheCache: TResourceCache; TheHandle: TLCLHandle); destructor Destroy; override; procedure IncreaseRefCount; procedure DecreaseRefCount; procedure AddToList(var First, Last: TResourceCacheItem); procedure RemoveFromList(var First, Last: TResourceCacheItem); procedure WarnReferenceHigh; virtual; public property ReferenceCount: integer read FReferenceCount; end; TResourceCacheItemClass = class of TResourceCacheItem; { TResourceCacheDescriptor } TResourceCacheDescriptor = class protected FDestroying: boolean; public Item: TResourceCacheItem; Cache: TResourceCache; Next, Prev: TResourceCacheDescriptor; constructor Create(TheCache: TResourceCache; TheItem: TResourceCacheItem); destructor Destroy; override; procedure AddToList(var First, Last: TResourceCacheDescriptor); procedure RemoveFromList(var First, Last: TResourceCacheDescriptor); end; TResourceCacheDescriptorClass = class of TResourceCacheDescriptor; { TResourceCache } TResourceCache = class protected FItems: TAvlTree; FDescriptors: TAvlTree; FDestroying: boolean; FResourceCacheDescriptorClass: TResourceCacheDescriptorClass; FResourceCacheItemClass: TResourceCacheItemClass; FMaxUnusedItem: integer; // how many freed resources to keep FFirstUnusedItem, FLastUnusedItem: TResourceCacheItem; FUnUsedItemCount: integer; FLock: TCriticalSection; procedure RemoveItem(Item: TResourceCacheItem); virtual; procedure RemoveDescriptor(Desc: TResourceCacheDescriptor); virtual; procedure ItemUsed(Item: TResourceCacheItem); procedure ItemUnused(Item: TResourceCacheItem); function ItemIsUsed(Item: TResourceCacheItem): boolean; public constructor Create; procedure Clear; destructor Destroy; override; function CompareItems(Tree: TAvlTree; Item1, Item2: Pointer): integer; virtual; function CompareDescriptors(Tree: TAvlTree; Desc1, Desc2: Pointer): integer; virtual; abstract; procedure ConsistencyCheck; procedure Lock; procedure Unlock; public property MaxUnusedItem: integer read FMaxUnusedItem write FMaxUnusedItem; property ResourceCacheItemClass: TResourceCacheItemClass read FResourceCacheItemClass; property ResourceCacheDescriptorClass: TResourceCacheDescriptorClass read FResourceCacheDescriptorClass; end; { THandleResourceCache } THandleResourceCache = class(TResourceCache) public function FindItem(Handle: TLCLHandle): TResourceCacheItem; end; { TBlockResourceCacheDescriptor } TBlockResourceCacheDescriptor = class(TResourceCacheDescriptor) public Data: Pointer; destructor Destroy; override; end; { TBlockResourceCache } TBlockResourceCache = class(THandleResourceCache) private FDataSize: integer; protected FOnCompareDescPtrWithDescriptor: TListSortCompare; public constructor Create(TheDataSize: integer); function FindDescriptor(DescPtr: Pointer): TBlockResourceCacheDescriptor; function AddResource(Handle: TLCLHandle; DescPtr: Pointer): TBlockResourceCacheDescriptor; function CompareDescriptors(Tree: TAvlTree; Desc1, Desc2: Pointer): integer; override; public property DataSize: integer read FDataSize; property OnCompareDescPtrWithDescriptor: TListSortCompare read FOnCompareDescPtrWithDescriptor; end; function ComparePHandleWithResourceCacheItem(HandlePtr: PLCLHandle; Item: TResourceCacheItem): integer; function CompareDescPtrWithBlockResDesc(DescPtr: Pointer; Item: TBlockResourceCacheDescriptor): integer; implementation function CompareLCLHandles(h1, h2: TLCLHandle): integer; begin if h1>h2 then Result:=1 else if h1