[fpc-devel] TAVLTree(avl_tree.pp) thread safety : second proposition

Henri Gourvest hgourvest at progdigy.com
Fri Aug 8 12:01:25 CEST 2008


I just found another one, I made long time ago, I stopped to use it
because it is based on libavl and licence is GPL.



unit libavl;

interface
{$ALIGN ON}
{$MINENUMSIZE 4}

const
 MAX_STACK = 32;

type

 TBranchDir = (bLeft, bRight);

 PIndexSlot = ^TIndexSlot;
 TIndexSlot = record
   FData: Pointer;
   FPrev: PIndexSlot;
   FNext: PIndexSlot;
 end;

 PIndexNode = ^TIndexNode;
 TIndexNode = record
   FBranch: array[TBranchDir] of PIndexNode;
   FFirst: TIndexSlot;
   FLast: PIndexSlot;
   FBalance: Integer;
 end;

 TStackNodeArray = array[0..MAX_STACK - 1] of PIndexNode;

 TIndexedList = class
 private
   FRoot: PIndexNode;
   FCount: Cardinal;
   FGeneration: Cardinal;
   FCursor: PIndexNode;
   FCursorSlot: PIndexSlot;
   FStack: TStackNodeArray;
   FStackSize: Cardinal;
   FNeedResync: boolean;
   procedure Resync;
   function GetData: Pointer;
   procedure DeleteItem(const p: PIndexNode);
 protected
   function doCompare(const item1, item2: Pointer): Integer; virtual;
   procedure doDelete(const item: Pointer); virtual;
 public
   constructor Create; virtual;
   destructor Destroy; override;
   procedure Clear;
   function Add(const item: Pointer; unique: boolean): Pointer;
   function Delete(const item: Pointer): Pointer;
   function Find(const item: Pointer): Pointer;
   function First: Pointer;
   function Last: Pointer;
   function Prior: Pointer;
   function Next: Pointer;

   function FindNext: Pointer;
   function FindPrior: Pointer;
   property Data: Pointer read GetData;
   property Count: Cardinal read FCount;
 end;

implementation
uses SysUtils;

type
 TStackDirArray = array[0..MAX_STACK - 1] of TBranchDir;

{ TIndexdList }

function TIndexedList.doCompare(const item1, item2: Pointer): Integer;
begin
 result := 0;
end;

procedure TIndexedList.doDelete(const item: Pointer);
begin

end;

procedure TIndexedList.Resync;
var
 node, i: PIndexNode;
begin
 FNeedResync := False;
 if (FCursor <> nil) then
 begin
   node := FCursor;
   FStackSize := 0;
   i := FRoot;
   while i <> node do
   begin
     assert(FStackSize < MAX_STACK);
     assert(i <> nil);
     FStack[FStackSize] := i;
     inc(FStackSize);
     i := i.FBranch[TBranchDir(
doCompare(node.FFirst.FData, i.FFirst.FData) > 0)];
   end;
 end;
end;

function TIndexedList.GetData: Pointer;
begin
 if FCursorSlot <> nil then
   Result := FCursorSlot.FData
 else
   Result := nil;
end;

constructor TIndexedList.Create;
begin
 FRoot := nil;
 FCursor := nil;
 FCursorSlot := nil;
 FCount := 0;
 FGeneration := 0;
 FStackSize := 0;
 FNeedResync := False;
end;

function TIndexedList.Delete(const item: Pointer): Pointer;
var
 na: TStackNodeArray;
 da: TStackDirArray;
 k, j, comp: Integer;
 i: Pointer;
 dir: TBranchDir;
 p1, p2, p3, p4, p5, p6: PIndexNode;
begin
 assert(item <> nil);
 p3 := nil;
 k := 0;
 p1 := @FRoot;
 comp := -1;
 while comp <> 0 do
 begin
   dir := TBranchDir(comp > 0);
   na[k] := p1;
   da[k] := dir;
   inc(k);
   p1 := p1.FBranch[dir];
   if (p1 = nil) then
   begin
     Result := nil;
     exit;
   end;
   comp := doCompare(item, p1.FFirst.FData);
 end;
 i := p1.FFirst.FData;
 if (p1.FBranch[bRight] = nil) then
   na[k - 1].FBranch[da[k - 1]] := p1.FBranch[bLeft]
 else
 begin
   p2 := p1.FBranch[bRight];
   if (p2.FBranch[bLeft] = nil) then
   begin
     p2.FBranch[bLeft] := p1.FBranch[bLeft];
     p2.FBalance := p1.FBalance;
     na[k - 1].FBranch[da[k - 1]] := p2;
     da[k] := bRight;
     na[k] := p2;
     inc(k);
   end
   else
   begin
     j := k;
     inc(k);
     while True do
     begin
       da[k] := bLeft;
       na[k] := p2;
       inc(k);
       p3 := p2.FBranch[bLeft];
       if (p3.FBranch[bLeft] = nil) then
         break;
       p2 := p3;
     end;
     p3.FBranch[bLeft] := p1.FBranch[bLeft];
     p2.FBranch[bLeft] := p3.FBranch[bRight];
     p3.FBranch[bRight] := p1.FBranch[bRight];
     p3.FBalance := p1.FBalance;
     na[j - 1].FBranch[da[j - 1]] := p3;
     da[j] := bRight;
     na[j] := p3;
   end;
 end;
 DeleteItem(p1);
 assert(k > 0);
 dec(k);
 while (k > 0) do
 begin
   p4 := na[k];
   if (da[k] = bLeft) then
   begin
     inc(p4.FBalance);
     if (p4.FBalance = 1) then
       break
     else
       if (p4.FBalance = 2) then
       begin
         p5 := p4.FBranch[bRight];
         if (p5.FBalance = -1) then
         begin
           assert(p5.FBalance = -1);
           p6 := p5.FBranch[bLeft];
           p5.FBranch[bLeft] := p6.FBranch[bRight];
           p6.FBranch[bRight] := p5;
           p4.FBranch[bRight] := p6.FBranch[bLeft];
           p6.FBranch[bLeft] := p4;
           if (p6.FBalance = 1) then
           begin
             p5.FBalance := 0;
             p4.FBalance := -1;
           end
           else
             if (p6.FBalance = 0) then
             begin
               p5.FBalance := 0;
               p4.FBalance := 0;
             end
             else
             begin
               p5.FBalance := 1;
               p4.FBalance := 0;
             end;
           p6.FBalance := 0;
           na[k - 1].FBranch[da[k - 1]] := p6;
         end
         else
         begin
           p4.FBranch[bRight] := p5.FBranch[bLeft];
           p5.FBranch[bLeft] := p4;
           na[k - 1].FBranch[da[k - 1]] := p5;
           if (p5.FBalance = 0) then
           begin
             p5.FBalance := -1;
             p4.FBalance := 1;
             break;
           end
           else
           begin
             p5.FBalance := 0;
             p4.FBalance := 0;
           end;
         end;
       end;
   end
   else
   begin
     dec(p4.FBalance);
     if (p4.FBalance = -1) then
       break
     else
       if (p4.FBalance = -2) then
       begin
         p5 := p4.FBranch[bLeft];
         if (p5.FBalance = 1) then
         begin
           assert(p5.FBalance = 1);
           p6 := p5.FBranch[bRight];
           p5.FBranch[bRight] := p6.FBranch[bLeft];
           p6.FBranch[bLeft] := p5;
           p4.FBranch[bLeft] := p6.FBranch[bRight];
           p6.FBranch[bRight] := p4;
           if (p6.FBalance = -1) then
           begin
             p5.FBalance := 0;
             p4.FBalance := 1;
           end
           else
             if (p6.FBalance = 0) then
             begin
               p5.FBalance := 0;
               p4.FBalance := 0;
             end
             else
             begin
               p5.FBalance := -1;
               p4.FBalance := 0;
             end;
           p6.FBalance := 0;
           na[k - 1].FBranch[da[k - 1]] := p6;
         end
         else
         begin
           p4.FBranch[bLeft] := p5.FBranch[bRight];
           p5.FBranch[bRight] := p4;
           na[k - 1].FBranch[da[k - 1]] := p5;
           if (p5.FBalance = 0) then
           begin
             p5.FBalance := 1;
             p4.FBalance := -1;
             break;
           end
           else
           begin
             p5.FBalance := 0;
             p4.FBalance := 0;
           end;
         end;
       end;
   end;
   dec(k);
 end;
 dec(FCount);
 inc(FGeneration);
 Result := i;
end;

destructor TIndexedList.Destroy;
begin
 Clear;
 inherited;
end;

function TIndexedList.First: Pointer;
var
 p: PIndexNode;
begin
 FStackSize := 0;
 FNeedResync := False;
 p := FRoot;
 if (p <> nil) then
   while (p.FBranch[bLeft] <> nil) do
   begin
     assert(FStackSize < MAX_STACK);
     FStack[FStackSize] := p;
     inc(FStackSize);
     p := p.FBranch[bLeft];
   end;
 FCursor := p;
 if p <> nil then
 begin
   FCursorSlot := @p.FFirst;
   Result := FCursorSlot.FData
 end
 else
 begin
   FCursorSlot := nil;
   Result := nil;
 end;
end;

function TIndexedList.Last: Pointer;
var
 p: PIndexNode;
begin
 FStackSize := 0;
 FNeedResync := False;
 p := FRoot;
 if (p <> nil) then
   while (p.FBranch[bRight] <> nil) do
   begin
     assert(FStackSize < MAX_STACK);
     FStack[FStackSize] := p;
     inc(FStackSize);
     p := p.FBranch[bRight];
   end;
 FCursor := p;

 if p <> nil then
 begin
   FCursorSlot := FCursor.FLast;
   Result := FCursorSlot.FData
 end
 else
 begin
   FCursorSlot := nil;
   Result := nil;
 end;
end;

function TIndexedList.Find(const item: Pointer): Pointer;
var
 p, q: PIndexNode;
 comp: integer;
begin
 assert(item <> nil);
 FStackSize := 0;
 FNeedResync := False;
 p := FRoot;
 q := nil;
 while p <> nil do
 begin
   comp := doCompare(item, p.FFirst.FData);
   if (comp < 0) then
     q := p.FBranch[bLeft]
   else
     if (comp > 0) then
       q := p.FBranch[bRight]
     else
     begin
       FCursor := p;
       FCursorSlot := @p.FFirst;
       Result := FCursorSlot.FData;
       exit;
     end;
   assert(FStackSize < MAX_STACK);
   FStack[FStackSize] := p;
   inc(FStackSize);
   p := q;
 end;
 FStackSize := 0;
 FCursor := nil;
 FCursorSlot := nil;
 Result := nil;
end;

function TIndexedList.Add(const item: Pointer; unique: boolean): Pointer;
var
 da: TStackDirArray;
 p1, p2, p3, p4, p5, p6, p7: PIndexNode;
 i, comp: Integer;
 dir: TBranchDir;
begin
 assert(item <> nil);
 i := 0;
 p7 := @FRoot;
 p6 := FRoot;
 dir := bLeft;
 p3 := p7;
 p2 := p6;
 while p2 <> nil do
 begin
   comp := doCompare(item, p2.FFirst.FData);
   if (comp = 0) then
   begin
     if unique then
     begin
       FCursor := p2;
       FCursorSlot := @FCursor.FFirst;
       result := FCursorSlot.FData;
       doDelete(item);
     end else
     begin
       FCursor := p2;
       GetMem(FCursorSlot, SizeOf(TIndexSlot));
       FCursorSlot.FData := item;
       FCursorSlot.FPrev := FCursor.FLast;
       FCursorSlot.FNext := nil;
       FCursor.FLast.FNext := FCursorSlot;
       FCursor.FLast := FCursorSlot;
       FNeedResync := True;
       Result := FCursorSlot.FData;
       inc(FCount);
     end;
     exit;
   end;
   if (p2.FBalance <> 0) then
   begin
     p7 := p3;
     p6 := p2;
     i := 0;
   end;
   dir := TBranchDir(comp > 0);
   da[i] := dir;
   inc(i);
   p3 := p2;
   p2 := p2.FBranch[dir]
 end;

 GetMem(p1, sizeof(TIndexNode));
 p3.FBranch[dir] := p1;
 inc(FCount);
 p1.FFirst.FData := item;
 p1.FFirst.FNext := nil;
 p1.FFirst.FPrev := nil;
 p1.FLast := @p1.FFirst;
 p1.FBranch[bLeft] := nil;
 p1.FBranch[bRight] := nil;
 p1.FBalance := 0;
 if (p6 = nil) then
 begin
   FCursor := p1;
   FCursorSlot := @p1.FFirst;
   FNeedResync := True;
   Result := FCursorSlot.FData;
   exit;
 end;

 p2 := p6;
 i := 0;
 while p2 <> p1 do
 begin
   if (da[i] = bLeft) then
     dec(p2.FBalance)
   else
     inc(p2.FBalance);
   p2 := p2.FBranch[da[i]];
   inc(i);
 end;

 if (p6.FBalance = -2) then
 begin
   p5 := p6.FBranch[bLeft];
   if (p5.FBalance = -1) then
   begin
     p4 := p5;
     p6.FBranch[bLeft] := p5.FBranch[bRight];
     p5.FBranch[bRight] := p6;
     p5.FBalance := 0;
     p6.FBalance := 0;
   end
   else
   begin
     assert(p5.FBalance = 1);
     p4 := p5.FBranch[bRight];
     p5.FBranch[bRight] := p4.FBranch[bLeft];
     p4.FBranch[bLeft] := p5;
     p6.FBranch[bLeft] := p4.FBranch[bRight];
     p4.FBranch[bRight] := p6;
     if (p4.FBalance = -1) then
     begin
       p5.FBalance := 0;
       p6.FBalance := 1;
     end
     else
       if (p4.FBalance = 0) then
       begin
         p5.FBalance := 0;
         p6.FBalance := 0;
       end
       else
       begin
         p5.FBalance := -1;
         p6.FBalance := 0;
       end;
     p4.FBalance := 0;
   end;
 end
 else
   if (p6.FBalance = 2) then
   begin
     p5 := p6.FBranch[bRight];
     if (p5.FBalance = 1) then
     begin
       p4 := p5;
       p6.FBranch[bRight] := p5.FBranch[bLeft];
       p5.FBranch[bLeft] := p6;
       p5.FBalance := 0;
       p6.FBalance := 0;
     end
     else
     begin
       assert(p5.FBalance = -1);
       p4 := p5.FBranch[bLeft];
       p5.FBranch[bLeft] := p4.FBranch[bRight];
       p4.FBranch[bRight] := p5;
       p6.FBranch[bRight] := p4.FBranch[bLeft];
       p4.FBranch[bLeft] := p6;
       if (p4.FBalance = 1) then
       begin
         p5.FBalance := 0;
         p6.FBalance := -1;
       end
       else
         if (p4.FBalance = 0) then
         begin
           p5.FBalance := 0;
           p6.FBalance := 0;
         end
         else
         begin
           p5.FBalance := 1;
           p6.FBalance := 0;
         end;
       p4.FBalance := 0;
     end;
   end
   else
   begin
     FCursor := p1;
     FCursorSlot := @p1.FFirst;
     FNeedResync := True;
     Result := FCursorSlot.FData;
     exit;
   end;
 p7.FBranch[TBranchDir(p6 <> p7.FBranch[bLeft])] := p4;
 inc(FGeneration);
 FCursor := p1;
 FCursorSlot := @p1.FFirst;
 FNeedResync := True;
 Result := FCursorSlot.FData;
end;

function TIndexedList.Next: Pointer;
var
 p1, p2: PIndexNode;
begin
 if FNeedResync then
   Resync;

 Result := FindNext;
 if Result <> nil then
   Exit;

 p1 := FCursor;
 if (p1 = nil) then
 begin
   Result := First;
   exit;
 end
 else
   if (p1.FBranch[bRight] <> nil) then
   begin
     assert(FStackSize < MAX_STACK);
     FStack[FStackSize] := p1;
     inc(FStackSize);
     p1 := p1.FBranch[bRight];
     while (p1.FBranch[bLeft] <> nil) do
     begin
       assert(FStackSize < MAX_STACK);
       FStack[FStackSize] := p1;
       inc(FStackSize);
       p1 := p1.FBranch[bLeft];
     end;
   end
   else
     repeat
       if (FStackSize = 0) then
       begin
         FCursor := nil;
         FCursorSlot := nil;
         Result := nil;
         exit;
       end;
       p2 := p1;
       dec(FStackSize);
       p1 := FStack[FStackSize];
     until (p2 <> p1.FBranch[bRight]);
 FCursor := p1;
 FCursorSlot := @p1.FFirst;
 Result := FCursorSlot.FData;
end;

function TIndexedList.Prior: Pointer;
var
 p1, p2: PIndexNode;
begin
 if FNeedResync then
   Resync;

 Result := FindPrior;
 if Result <> nil then
   Exit;

 p1 := FCursor;
 if (p1 = nil) then
 begin
   Result := Last;
   exit;
 end
 else
   if (p1.FBranch[bLeft] <> nil) then
   begin
     assert(FStackSize < MAX_STACK);
     FStack[FStackSize] := p1;
     inc(FStackSize);
     p1 := p1.FBranch[bLeft];
     while (p1.FBranch[bRight] <> nil) do
     begin
       assert(FStackSize < MAX_STACK);
       FStack[FStackSize] := p1;
       inc(FStackSize);
       p1 := p1.FBranch[bRight];
     end;
   end
   else
     repeat
       if (FStackSize = 0) then
       begin
         FCursor := nil;
         FCursorSlot := nil;
         Result := nil;
         exit;
       end;
       p2 := p1;
       dec(FStackSize);
       p1 := FStack[FStackSize];
     until (p2 <> p1.FBranch[bLeft]);
 FCursor := p1;
 FCursorSlot := @p1.FFirst;
 Result := FCursorSlot.FData;
end;

procedure TIndexedList.Clear;
var
 p1, p2: PIndexNode;
begin
 p1 := FRoot;
 while p1 <> nil do
 begin
   if (p1.FBranch[bLeft] = nil) then
   begin
     p2 := p1.FBranch[bRight];
     DeleteItem(p1);
   end
   else
   begin
     p2 := p1.FBranch[bLeft];
     p1.FBranch[bLeft] := p2.FBranch[bRight];
     p2.FBranch[bRight] := p1;
   end;
   p1 := p2;
 end;
 FRoot := nil;
 FCount := 0;
 FGeneration := 0;
 FCursor := nil;
 FCursorSlot := nil;
 FStackSize := 0;
 FNeedResync := False;
end;

procedure TIndexedList.DeleteItem(const p: PIndexNode);
var
 p1, p2: PIndexSlot;
begin
 doDelete(p.FFirst.FData);
 p1 := p.FFirst.FNext;
 while p1 <> nil do
 begin
   if p1.FData <> nil then
     doDelete(p1.FData);
   p2 := p1;
   p1 := p2.FNext;
   FreeMem(p2);
   dec(FCount);
 end;
 FreeMem(p);
end;

function TIndexedList.FindNext: Pointer;
begin
 if FCursorSlot <> nil then
 begin
   FCursorSlot := FCursorSlot.FNext;
   if FCursorSlot <> nil then
     Result := FCursorSlot.FData else
     Result := nil;
 end else
   Result := nil
end;

function TIndexedList.FindPrior: Pointer;
begin
 if FCursorSlot <> nil then
 begin
   FCursorSlot := FCursorSlot.FPrev;
   if FCursorSlot <> nil then
     Result := FCursorSlot.FData else
     Result := nil;
 end else
   Result := nil
end;

end.



More information about the fpc-devel mailing list