mirror of
https://gitlab.com/freepascal.org/lazarus/lazarus.git
synced 2025-08-18 20:59:08 +02:00
LazUtils: add thread-save map iterator (lock map)
git-svn-id: trunk@64127 -
This commit is contained in:
parent
0a7abce1cf
commit
689df5211a
@ -82,6 +82,13 @@ type
|
|||||||
|
|
||||||
{ TBaseMap }
|
{ TBaseMap }
|
||||||
|
|
||||||
|
{ TLockedMapModifyException }
|
||||||
|
|
||||||
|
TLockedMapModifyException = class(Exception)
|
||||||
|
public
|
||||||
|
constructor Create;
|
||||||
|
end;
|
||||||
|
|
||||||
TBaseMapIterator = class;
|
TBaseMapIterator = class;
|
||||||
|
|
||||||
TBaseMap = class(TPersistent)
|
TBaseMap = class(TPersistent)
|
||||||
@ -92,6 +99,7 @@ type
|
|||||||
FFirst: PMapItem; // First element of our linkedlist
|
FFirst: PMapItem; // First element of our linkedlist
|
||||||
FLast: PMapItem; // Last element of our linkedlist
|
FLast: PMapItem; // Last element of our linkedlist
|
||||||
FIterators: TList; // A List of iterators iterating us
|
FIterators: TList; // A List of iterators iterating us
|
||||||
|
FLocked: integer;
|
||||||
function FindNode(const AId): TAvlTreeNode;
|
function FindNode(const AId): TAvlTreeNode;
|
||||||
function FindItem(const AId): PMapItem;
|
function FindItem(const AId): PMapItem;
|
||||||
procedure FreeData(ANode: TAvlTreeNode);
|
procedure FreeData(ANode: TAvlTreeNode);
|
||||||
@ -100,6 +108,8 @@ type
|
|||||||
procedure IteratorAdd(AIterator: TBaseMapIterator);
|
procedure IteratorAdd(AIterator: TBaseMapIterator);
|
||||||
procedure IteratorRemove(AIterator: TBaseMapIterator);
|
procedure IteratorRemove(AIterator: TBaseMapIterator);
|
||||||
protected
|
protected
|
||||||
|
procedure LockMap;
|
||||||
|
procedure UnLockMap;
|
||||||
procedure InternalAdd(const AId, AData);
|
procedure InternalAdd(const AId, AData);
|
||||||
function InternalGetData(AItem: PMapItem; out AData): Boolean;
|
function InternalGetData(AItem: PMapItem; out AData): Boolean;
|
||||||
function InternalGetDataPtr(AItem: PMapItem): Pointer;
|
function InternalGetDataPtr(AItem: PMapItem): Pointer;
|
||||||
@ -128,6 +138,8 @@ type
|
|||||||
procedure MapCleared; // Called when our map is cleared
|
procedure MapCleared; // Called when our map is cleared
|
||||||
procedure ItemRemove(AData: Pointer); // Called when an Item is removed from the map
|
procedure ItemRemove(AData: Pointer); // Called when an Item is removed from the map
|
||||||
protected
|
protected
|
||||||
|
procedure AddToMap; virtual;
|
||||||
|
procedure RemoveFromMap; virtual;
|
||||||
procedure InternalCreate(AMap: TBaseMap);
|
procedure InternalCreate(AMap: TBaseMap);
|
||||||
function InternalLocate(const AId): Boolean; //True if match found. If not found, current is next and Invalid is set
|
function InternalLocate(const AId): Boolean; //True if match found. If not found, current is next and Invalid is set
|
||||||
procedure Validate;
|
procedure Validate;
|
||||||
@ -172,6 +184,17 @@ type
|
|||||||
procedure SetData(const AData);
|
procedure SetData(const AData);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
{ TLockedMapIterator
|
||||||
|
Allow iteration of a map in multiple threads.
|
||||||
|
The map will be locked againts adding/removing entries.
|
||||||
|
}
|
||||||
|
|
||||||
|
TLockedMapIterator = class(TMapIterator)
|
||||||
|
protected
|
||||||
|
procedure AddToMap; override;
|
||||||
|
procedure RemoveFromMap; override;
|
||||||
|
end;
|
||||||
|
|
||||||
{ TTypedMap }
|
{ TTypedMap }
|
||||||
|
|
||||||
TTypedMap = class(TBaseMap)
|
TTypedMap = class(TBaseMap)
|
||||||
@ -222,6 +245,12 @@ begin
|
|||||||
else Result := AMap.FTree.ReportAsString;
|
else Result := AMap.FTree.ReportAsString;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
{ TLockedMapModifyException }
|
||||||
|
|
||||||
|
constructor TLockedMapModifyException.Create;
|
||||||
|
begin
|
||||||
|
inherited Create('Map modification not allowed');
|
||||||
|
end;
|
||||||
|
|
||||||
{ TBaseMap }
|
{ TBaseMap }
|
||||||
|
|
||||||
@ -229,6 +258,8 @@ procedure TBaseMap.Clear;
|
|||||||
var
|
var
|
||||||
n: Integer;
|
n: Integer;
|
||||||
begin
|
begin
|
||||||
|
if FLocked > 0 then
|
||||||
|
raise TLockedMapModifyException.Create;
|
||||||
FreeData(FTree.Root);
|
FreeData(FTree.Root);
|
||||||
FTree.Clear;
|
FTree.Clear;
|
||||||
FFirst := nil;
|
FFirst := nil;
|
||||||
@ -260,6 +291,9 @@ var
|
|||||||
Node: TAvlTreeNode;
|
Node: TAvlTreeNode;
|
||||||
n: integer;
|
n: integer;
|
||||||
begin
|
begin
|
||||||
|
if FLocked > 0 then
|
||||||
|
raise TLockedMapModifyException.Create;
|
||||||
|
|
||||||
Node := FindNode(AId);
|
Node := FindNode(AId);
|
||||||
Result := Node <> nil;
|
Result := Node <> nil;
|
||||||
if not result then Exit;
|
if not result then Exit;
|
||||||
@ -288,6 +322,9 @@ destructor TBaseMap.Destroy;
|
|||||||
var
|
var
|
||||||
n: Integer;
|
n: Integer;
|
||||||
begin
|
begin
|
||||||
|
if FLocked > 0 then
|
||||||
|
raise TLockedMapModifyException.Create;
|
||||||
|
|
||||||
// notify our iterators
|
// notify our iterators
|
||||||
if FIterators <> nil
|
if FIterators <> nil
|
||||||
then begin
|
then begin
|
||||||
@ -361,6 +398,9 @@ var
|
|||||||
p: Pointer;
|
p: Pointer;
|
||||||
Node, NewNode: TAvlTreeNode;
|
Node, NewNode: TAvlTreeNode;
|
||||||
begin
|
begin
|
||||||
|
if FLocked > 0 then
|
||||||
|
raise TLockedMapModifyException.Create;
|
||||||
|
|
||||||
if FindNode(AId) <> nil
|
if FindNode(AId) <> nil
|
||||||
then begin
|
then begin
|
||||||
Error;
|
Error;
|
||||||
@ -461,6 +501,16 @@ begin
|
|||||||
if FIterators.Count = 0 then FreeAndNil(FIterators);
|
if FIterators.Count = 0 then FreeAndNil(FIterators);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
procedure TBaseMap.LockMap;
|
||||||
|
begin
|
||||||
|
InterLockedIncrement(FLocked);
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure TBaseMap.UnLockMap;
|
||||||
|
begin
|
||||||
|
InterLockedDecrement(FLocked);
|
||||||
|
end;
|
||||||
|
|
||||||
procedure TBaseMap.ReleaseData(ADataPtr: Pointer);
|
procedure TBaseMap.ReleaseData(ADataPtr: Pointer);
|
||||||
begin
|
begin
|
||||||
end;
|
end;
|
||||||
@ -515,7 +565,7 @@ end;
|
|||||||
|
|
||||||
destructor TBaseMapIterator.Destroy;
|
destructor TBaseMapIterator.Destroy;
|
||||||
begin
|
begin
|
||||||
if FMap <> nil then FMap.IteratorRemove(Self);
|
if FMap <> nil then RemoveFromMap;
|
||||||
FMap := nil;
|
FMap := nil;
|
||||||
inherited Destroy;
|
inherited Destroy;
|
||||||
end;
|
end;
|
||||||
@ -532,7 +582,7 @@ procedure TBaseMapIterator.InternalCreate(AMap: TBaseMap);
|
|||||||
begin
|
begin
|
||||||
inherited Create;
|
inherited Create;
|
||||||
FMap := AMap;
|
FMap := AMap;
|
||||||
FMap.IteratorAdd(Self);
|
AddToMap;
|
||||||
FCurrent := FMap.FFirst;
|
FCurrent := FMap.FFirst;
|
||||||
FBOM := FCurrent = nil;
|
FBOM := FCurrent = nil;
|
||||||
FEOM := FCurrent = nil;
|
FEOM := FCurrent = nil;
|
||||||
@ -600,6 +650,16 @@ begin
|
|||||||
FEOM := FCurrent = nil;
|
FEOM := FCurrent = nil;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
procedure TBaseMapIterator.AddToMap;
|
||||||
|
begin
|
||||||
|
FMap.IteratorAdd(Self);
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure TBaseMapIterator.RemoveFromMap;
|
||||||
|
begin
|
||||||
|
FMap.IteratorRemove(Self);
|
||||||
|
end;
|
||||||
|
|
||||||
procedure TBaseMapIterator.Last;
|
procedure TBaseMapIterator.Last;
|
||||||
begin
|
begin
|
||||||
if FMap = nil then Exit;
|
if FMap = nil then Exit;
|
||||||
@ -878,6 +938,18 @@ begin
|
|||||||
FMap.InternalSetData(FCurrent, AData);
|
FMap.InternalSetData(FCurrent, AData);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
{ TLockedMapIterator }
|
||||||
|
|
||||||
|
procedure TLockedMapIterator.AddToMap;
|
||||||
|
begin
|
||||||
|
FMap.LockMap;
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure TLockedMapIterator.RemoveFromMap;
|
||||||
|
begin
|
||||||
|
FMap.UnLockMap;
|
||||||
|
end;
|
||||||
|
|
||||||
{ TTypedMapIterator }
|
{ TTypedMapIterator }
|
||||||
|
|
||||||
constructor TTypedMapIterator.Create(AMap: TTypedMap);
|
constructor TTypedMapIterator.Create(AMap: TTypedMap);
|
||||||
|
Loading…
Reference in New Issue
Block a user