فهرست منبع

Improve TAbstractMemTList to use 64 bits AbstractMem and add tests

Pascal Coin 3 سال پیش
والد
کامیت
c08c83329f

+ 12 - 2
src/libraries/abstractmem/UAbstractBTree.pas

@@ -127,6 +127,7 @@ type
     function FillList(AStartIndex, ACount : Integer; const AList : TList<TData>) : Integer;
     function Add(const AData: TData) : Boolean;
     function Delete(const AData: TData) : Boolean;
+    function NodeIdentifyToString(const AIdentify : TIdentify) : String; virtual;
     function NodeDataToString(const AData : TData) : String; virtual;
     constructor Create(const AOnCompareIdentifyMethod: TComparison<TIdentify>; const AOnCompareDataMethod: TComparison<TData>; AAllowDuplicates : Boolean; AOrder: Integer);
     destructor Destroy; override;
@@ -376,7 +377,10 @@ begin
       iRight := -1;
     end;
     Lchild := GetNode(ANode.childs[i]);
-    if Not AreEquals(Lchild.parent,ANode.identify) then raise EAbstractBTree.Create(Format('Inconsistent Identify child %d/%d %s invalid pointer to parent at %s',[i+1,Length(ANode.childs),ToString(Lchild),ToString(ANode)]));
+    if Not AreEquals(Lchild.parent,ANode.identify) then begin
+        raise EAbstractBTree.Create(Format('Inconsistent Identify child %d/%d %s invalid pointer to parent %s (%s)',
+          [i+1,Length(ANode.childs),ToString(Lchild),NodeIdentifyToString(ANode.identify),NodeIdentifyToString(Lchild.parent)]));
+    end;
     CheckConsistencyEx(Lchild,
       ((AIsGoingDown) and (i=0)),iLeft,iRight,
       ADatas,AIdents,
@@ -1240,6 +1244,12 @@ begin
   Result := IntToStr(SizeOf(AData));
 end;
 
+function TAbstractBTree<TIdentify, TData>.NodeIdentifyToString(
+  const AIdentify: TIdentify): String;
+begin
+  Result := IntToStr(SizeOf(AIdentify));
+end;
+
 procedure TAbstractBTree<TIdentify, TData>.SetCount(const ANewCount: Integer);
 begin
   FCount := ANewCount;
@@ -1294,7 +1304,7 @@ begin
     if Result<>'' then Result := Result + ',';
     Result := Result + NodeDataToString(ANode.data[i]);
   end;
-  Result := '['+Result+']';
+  Result := NodeIdentifyToString(ANode.identify)+'@'+NodeIdentifyToString(ANode.parent)+'['+Result+']';
 end;
 
 procedure TAbstractBTree<TIdentify, TData>.Unlock;

+ 5 - 3
src/libraries/abstractmem/UAbstractMem.pas

@@ -159,6 +159,8 @@ Type
     function SizeOfAbstractMemPosition : TAbstractMemSize; inline;
   End;
 
+  { TMem }
+
   TMem = Class(TAbstractMem)
   private
     FMem : TBytes;
@@ -581,9 +583,9 @@ begin
   if FIs64Bytes then begin
     if (AMemUnitsSize>=4) and (AMemUnitsSize<256) and ((AMemUnitsSize MOD 4)=0) then begin
       FMemUnitsSize := AMemUnitsSize;
-      FNextAvailablePos := CT_HeaderSize_64b;
-      Result := True;
     end;
+    FNextAvailablePos := CT_HeaderSize_64b;
+    Result := True;
   end else begin
     Result := True;
   end;
@@ -659,7 +661,7 @@ var LBuffer : TBytes;
   LUInt64 : UInt64;
   LByte : Byte;
 begin
-  if FReadOnly then raise EAbstractMem.Create('Cannot save Haeder on a ReadOnly AbstractMem');
+  if FReadOnly then raise EAbstractMem.Create('Cannot save Header on a ReadOnly AbstractMem');
   // Write Header:
   SetLength(LBuffer,HeaderSize);
   if FIs64Bytes then begin

+ 15 - 2
src/libraries/abstractmem/UAbstractMemBTree.pas

@@ -86,6 +86,8 @@ type
     class function MinAbstractMemInitialPositionSize(AAbstractMem : TAbstractMem) : Integer;
     property AbstractMem : TAbstractMem read FAbstractMem;
     property Count;
+    function NodeDataToString(const AData : TAbstractMemPosition) : String; override;
+    function NodeIdentifyToString(const AIdentify : TAbstractMemPosition) : String; override;
   End;
 
   TAbstractMemBTreeData<TData> = Class(TAbstractMemBTree)
@@ -285,7 +287,7 @@ end;
 
 class function TAbstractMemBTree.MinAbstractMemInitialPositionSize(AAbstractMem : TAbstractMem) : Integer;
 begin
-  Result := (AAbstractMem.SizeOfAbstractMemPosition) + 12;
+  Result := (AAbstractMem.SizeOfAbstractMemPosition) + 12 ;
 end;
 
 function TAbstractMemBTree.NewNode: TAbstractBTree<TAbstractMemPosition, TAbstractMemPosition>.TAbstractBTreeNode;
@@ -296,6 +298,17 @@ begin
   SaveNodeHeader(Result,0);
 end;
 
+function TAbstractMemBTree.NodeDataToString(const AData: TAbstractMemPosition): String;
+begin
+  Result := '0x'+AData.ToHexString;
+end;
+
+function TAbstractMemBTree.NodeIdentifyToString(
+  const AIdentify: TAbstractMemPosition): String;
+begin
+  Result := '0x'+AIdentify.ToHexString;
+end;
+
 procedure TAbstractMemBTree.SaveHeader;
 var LBuff : TBytes;
  i : Integer;
@@ -354,7 +367,7 @@ end;
 procedure TAbstractMemBTree.SaveNodeHeader(
   const ANode: TAbstractBTree<TAbstractMemPosition, TAbstractMemPosition>.TAbstractBTreeNode; const AChildsPosition : TAbstractMemPosition);
 var LBuff : TBytes;
-  i, LItemsCount, LChildsCount : Integer;
+  i, LItemsCount, LChildsCount: Integer;
 begin
   SetLength(LBuff, GetNodeHeaderSize );
 

+ 93 - 85
src/libraries/abstractmem/UAbstractMemTList.pas

@@ -55,7 +55,7 @@ type
 
     FElementsOfEachBlock : Integer;
     FFirstBlockPointer : TAbstractMemPosition;
-    FNextElementPosition : Integer;
+    FNextElementIndex : Integer;
 
     FUseCache : Boolean;
     FUseCacheAuto : Boolean;
@@ -100,6 +100,7 @@ type
     property UseCacheAuto : Boolean read FUseCacheAuto write FUseCacheAuto;
     procedure LockList;
     procedure UnlockList;
+    class function MinAbstractMemTListHeaderSize(AAbstractMem : TAbstractMem) : Integer;
   End;
 
   TAbstractMemTListBaseAbstract<T> = Class
@@ -158,13 +159,6 @@ type
     function Get(index : Integer) : T;
   End;
 
-const
-  CT_AbstractMemTList_HeaderSize = 16;
-    // [0] 4 for magic
-    // [4] 4 for elements of each block
-    // [8] 4 for next element (counter)
-    // [12] 4 for first block position
-
 implementation
 
 { TAbstractMemTList }
@@ -176,8 +170,8 @@ function TAbstractMemTList.Add(const APosition: TAbstractMemPosition): Integer;
 begin
   FAbstractMemTListLock.Acquire;
   Try
-  Result := FNextElementPosition;
-  Insert(FNextElementPosition,APosition);
+  Result := FNextElementIndex;
+  Insert(FNextElementIndex,APosition);
   Finally
     FAbstractMemTListLock.Release;
   End;
@@ -189,18 +183,20 @@ var LElements : TBytes;
   LIndexInBlock, i, j, n : Integer;
 begin
   CheckInitialized;
-  if (AIndexStart<0) or (AInsertCount<=0) or (AIndexStart>FNextElementPosition) then raise EAbstractMemTList.Create(Format('%s AddRange %d..%d out of range 0..%d',[ClassName,AIndexStart,AIndexStart+AInsertCount,FNextElementPosition-1]));
+  if (AIndexStart<0) or (AInsertCount<=0) or (AIndexStart>FNextElementIndex) then raise EAbstractMemTList.Create(Format('%s AddRange %d..%d out of range 0..%d',[ClassName,AIndexStart,AIndexStart+AInsertCount,FNextElementIndex-1]));
   if (UseCacheData(True)) then begin
-    if (Length(FCacheData)-FCacheDataUsedBytes)< (AInsertCount*4) then begin
+    if (Length(FCacheData)-FCacheDataUsedBytes)< (AInsertCount*FAbstractMem.SizeOfAbstractMemPosition) then begin
       // Increase
       if (FElementsOfEachBlock>AInsertCount) then i := FElementsOfEachBlock
       else i := AInsertCount;
-      SetLength(FCacheData,Length(FCacheData) + (i * 4));
+      SetLength(FCacheData,Length(FCacheData) + (i * FAbstractMem.SizeOfAbstractMemPosition));
     end;
     FCacheUpdated := True;
-    Inc(FCacheDataUsedBytes,(AInsertCount*4));
-    Move(FCacheData[AIndexStart*4],FCacheData[(AIndexStart+AInsertCount)*4],FCacheDataUsedBytes-((AIndexStart+AInsertCount)*4));
-    Inc(FNextElementPosition,AInsertCount);
+    Inc(FCacheDataUsedBytes,(AInsertCount*FAbstractMem.SizeOfAbstractMemPosition));
+    Move(FCacheData[AIndexStart*FAbstractMem.SizeOfAbstractMemPosition],
+         FCacheData[(AIndexStart+AInsertCount)*FAbstractMem.SizeOfAbstractMemPosition],
+         FCacheDataUsedBytes-((AIndexStart+AInsertCount)*FAbstractMem.SizeOfAbstractMemPosition));
+    Inc(FNextElementIndex,AInsertCount);
     Exit;
   end;
   //
@@ -213,13 +209,14 @@ begin
     GetPointerTo(i,True,LPreviousBlockPointer,LBlockPointer,LIndexInBlock);
     // Move from LIndexInBlock to FElementsOfEachBlock-1 in this block
     j := FElementsOfEachBlock - (LIndexInBlock); // j = Elements to move right on this block
-    if ((n+j)*4>Length(LElements)) then j := (Length(LElements) DIV 4)-n;
-    FAbstractMem.Write( LBlockPointer + (LIndexInBlock*4), LElements[ n*4 ], j*4 );
+    if ((n+j)*FAbstractMem.SizeOfAbstractMemPosition>Length(LElements)) then j := (Length(LElements) DIV FAbstractMem.SizeOfAbstractMemPosition)-n;
+    FAbstractMem.Write( LBlockPointer + (LIndexInBlock*FAbstractMem.SizeOfAbstractMemPosition),
+      LElements[ n*FAbstractMem.SizeOfAbstractMemPosition ], j*FAbstractMem.SizeOfAbstractMemPosition );
     inc(n,j);
     inc(i,j);
-  until (i >= FNextElementPosition + AInsertCount) or (j=0);
-  Inc(FNextElementPosition,AInsertCount);
-  FAbstractMem.Write( FInitialZone.position + 8, FNextElementPosition, 4 );
+  until (i >= FNextElementIndex + AInsertCount) or (j=0);
+  Inc(FNextElementIndex,AInsertCount);
+  FAbstractMem.Write( FInitialZone.position + 8, FNextElementIndex, 4 );
 end;
 
 procedure TAbstractMemTList.CheckInitialized;
@@ -236,11 +233,11 @@ begin
   // Free mem
   LBlockPointer := FFirstBlockPointer;
   FFirstBlockPointer := 0;
-  FNextElementPosition := 0;
-  FAbstractMem.Write( FInitialZone.position + 12, FFirstBlockPointer, 4 );
+  FNextElementIndex := 0;
+  FAbstractMem.Write( FInitialZone.position + 12, FFirstBlockPointer, FAbstractMem.SizeOfAbstractMemPosition );
   while (LBlockPointer>0) do begin
     // Read next
-    FAbstractMem.Read( LBlockPointer + (FElementsOfEachBlock * 4), LNext, 4);
+    FAbstractMem.Read( LBlockPointer + (FElementsOfEachBlock * FAbstractMem.SizeOfAbstractMemPosition), LNext, FAbstractMem.SizeOfAbstractMemPosition);
     FAbstractMem.Dispose(LBlockPointer);
     LBlockPointer := LNext;
   end;
@@ -255,7 +252,7 @@ end;
 
 function TAbstractMemTList.Count: Integer;
 begin
-  Result := FNextElementPosition;
+  Result := FNextElementIndex;
 end;
 
 constructor TAbstractMemTList.Create(AAbstractMem: TAbstractMem; const AInitialZone: TAMZone; ADefaultElementsPerBlock : Integer; AUseCache : Boolean);
@@ -272,7 +269,7 @@ begin
 
   FElementsOfEachBlock := 0;
   FFirstBlockPointer := 0;
-  FNextElementPosition := 0;
+  FNextElementIndex := 0;
 
   FAbstractMemTListLock := TCriticalSection.Create;
 
@@ -323,34 +320,34 @@ begin
   LNext := 0;
   // Save full:
   i := 0;
-  while ((i*4) < (FCacheDataUsedBytes)) do begin
+  while ((i*FAbstractMem.SizeOfAbstractMemPosition) < (FCacheDataUsedBytes)) do begin
     GetPointerTo(i,True,LPreviousBlockPointer,LBlockPointer,LIndexInBlock);
-    if (i+FElementsOfEachBlock-1 >= FNextElementPosition) then begin
-      LElements := FNextElementPosition - i;
+    if (i+FElementsOfEachBlock-1 >= FNextElementIndex) then begin
+      LElements := FNextElementIndex - i;
     end else LElements := FElementsOfEachBlock;
-    FAbstractMem.Write(LBlockPointer,FCacheData[i*4],(LElements*4));
+    FAbstractMem.Write(LBlockPointer,FCacheData[i*FAbstractMem.SizeOfAbstractMemPosition],(LElements*FAbstractMem.SizeOfAbstractMemPosition));
     inc(i,LElements);
-    FAbstractMem.Read( LBlockPointer + (FElementsOfEachBlock * 4), LNext, 4);
+    FAbstractMem.Read( LBlockPointer + (FElementsOfEachBlock * FAbstractMem.SizeOfAbstractMemPosition), LNext, FAbstractMem.SizeOfAbstractMemPosition);
     LPreviousBlockPointer := LBlockPointer;
   end;
   // Save Header:
-  FAbstractMem.Write( FInitialZone.position + 8, FNextElementPosition, 4 );
+  FAbstractMem.Write( FInitialZone.position + 8, FNextElementIndex, 4 );
   // Free unused blocks:
-  if (FNextElementPosition=0) And (FFirstBlockPointer>0) then begin
+  if (FNextElementIndex=0) And (FFirstBlockPointer>0) then begin
     // This is first block pointer
     LNext := FFirstBlockPointer;
     FFirstBlockPointer := 0;
-    FAbstractMem.Write( FInitialZone.position + 12, FFirstBlockPointer, 4 );
+    FAbstractMem.Write( FInitialZone.position + 12, FFirstBlockPointer, FAbstractMem.SizeOfAbstractMemPosition );
     LPreviousBlockPointer := 0;
   end;
   while (LNext>0) do begin
     if LPreviousBlockPointer>0 then begin
       LZero := 0;
-      FAbstractMem.Write( LPreviousBlockPointer + (FElementsOfEachBlock * 4), LZero, 4);
+      FAbstractMem.Write( LPreviousBlockPointer + (FElementsOfEachBlock * FAbstractMem.SizeOfAbstractMemPosition), LZero, FAbstractMem.SizeOfAbstractMemPosition);
     end;
     LPreviousBlockPointer := LBlockPointer;
     LBlockPointer := LNext;
-    FAbstractMem.Read( LBlockPointer + (FElementsOfEachBlock * 4), LNext, 4);
+    FAbstractMem.Read( LBlockPointer + (FElementsOfEachBlock * FAbstractMem.SizeOfAbstractMemPosition), LNext, FAbstractMem.SizeOfAbstractMemPosition);
     FAbstractMem.Dispose(LBlockPointer);
   end;
   //
@@ -364,10 +361,10 @@ procedure TAbstractMemTList.GetPointerTo(AIndex: Integer; AAllowIncrease : Boole
 var LBlockIndex : Integer;
   i : Integer;
   LNewBlock : TAMZone;
-  LZero : Integer;
+  LZero : TAbstractMemPosition;
 begin
   CheckInitialized;
-  if (AIndex<0) or ((Not AAllowIncrease) And (AIndex>=FNextElementPosition)) then raise EAbstractMemTList.Create(Format('%s index %d out of range 0..%d',[ClassName,AIndex,FNextElementPosition-1]));
+  if (AIndex<0) or ((Not AAllowIncrease) And (AIndex>=FNextElementIndex)) then raise EAbstractMemTList.Create(Format('%s index %d out of range 0..%d',[ClassName,AIndex,FNextElementIndex-1]));
 
   // Search ABlockPointer
   LBlockIndex := AIndex DIV FElementsOfEachBlock;
@@ -379,26 +376,26 @@ begin
   repeat
     if (ABlockPointer<=0) then begin
       // Create
-      LNewBlock := FAbstractMem.New( 4 + (FElementsOfEachBlock * 4) );
+      LNewBlock := FAbstractMem.New( FAbstractMem.SizeOfAbstractMemPosition + (FElementsOfEachBlock * FAbstractMem.SizeOfAbstractMemPosition) );
       ABlockPointer := LNewBlock.position;
       // Save this pointer
       if (i=0) then begin
         // This is FFirstBlockPointer
         FFirstBlockPointer := LNewBlock.position;
         // Save header:
-        FAbstractMem.Write( FInitialZone.position + 12, FFirstBlockPointer, 4 );
+        FAbstractMem.Write( FInitialZone.position + 12, FFirstBlockPointer, FAbstractMem.SizeOfAbstractMemPosition );
       end else begin
         // This is previous block
-        FAbstractMem.Write( APreviousBlockPointer + (FElementsOfEachBlock*4), LNewBlock.position, 4 );
+        FAbstractMem.Write( APreviousBlockPointer + (FElementsOfEachBlock*FAbstractMem.SizeOfAbstractMemPosition), LNewBlock.position, FAbstractMem.SizeOfAbstractMemPosition );
       end;
       // Clear next
       LZero := 0;
-      FAbstractMem.Write( ABlockPointer + (FElementsOfEachBlock*4), LZero, 4 );
+      FAbstractMem.Write( ABlockPointer + (FElementsOfEachBlock*FAbstractMem.SizeOfAbstractMemPosition), LZero, FAbstractMem.SizeOfAbstractMemPosition );
     end;
     if (i<LBlockIndex) then begin
       APreviousBlockPointer := ABlockPointer;
       // Read
-      FAbstractMem.Read( ABlockPointer + (FElementsOfEachBlock*4), ABlockPointer, 4 );
+      FAbstractMem.Read( ABlockPointer + (FElementsOfEachBlock*FAbstractMem.SizeOfAbstractMemPosition), ABlockPointer, FAbstractMem.SizeOfAbstractMemPosition );
     end;
     inc(i);
   until (i > LBlockIndex);
@@ -412,11 +409,11 @@ begin
   FAbstractMemTListLock.Acquire;
   try
   if (UseCacheData(False)) then begin
-    if (AIndex<0) or (AIndex>=FNextElementPosition) then raise EAbstractMemTList.Create(Format('%s index %d out of range 0..%d',[ClassName,AIndex,FNextElementPosition-1]));
-    Move( FCacheData[AIndex*4], Result, 4);
+    if (AIndex<0) or (AIndex>=FNextElementIndex) then raise EAbstractMemTList.Create(Format('%s index %d out of range 0..%d',[ClassName,AIndex,FNextElementIndex-1]));
+    Move( FCacheData[AIndex*FAbstractMem.SizeOfAbstractMemPosition], Result, FAbstractMem.SizeOfAbstractMemPosition);
   end else begin
     GetPointerTo(AIndex,False,LPreviousBlockPointer,LBlockPointer,LIndexInBlock);
-    FAbstractMem.Read( LBlockPointer + (LIndexInBlock*4), Result, 4);
+    FAbstractMem.Read( LBlockPointer + (LIndexInBlock*FAbstractMem.SizeOfAbstractMemPosition), Result, FAbstractMem.SizeOfAbstractMemPosition);
   end;
   finally
     FAbstractMemTListLock.Release;
@@ -431,11 +428,11 @@ begin
   // Try to read
   FElementsOfEachBlock := 0;
   FFirstBlockPointer := 0;
-  FNextElementPosition := 0;
-  SetLength(LBytes,CT_AbstractMemTList_HeaderSize);
+  FNextElementIndex := 0;
+  SetLength(LBytes,MinAbstractMemTListHeaderSize(FAbstractMem));
   try
-    if (FInitialZone.position>0) And ((FInitialZone.size=0) or (FInitialZone.size>=CT_AbstractMemTList_HeaderSize)) then begin
-      FAbstractMem.Read(FInitialZone.position,LBytes[0],CT_AbstractMemTList_HeaderSize);
+    if (FInitialZone.position>0) And ((FInitialZone.size=0) or (FInitialZone.size>=MinAbstractMemTListHeaderSize(FAbstractMem))) then begin
+      FAbstractMem.Read(FInitialZone.position,LBytes[0],MinAbstractMemTListHeaderSize(FAbstractMem));
       if Length(CT_AbstractMemTList_Magic)<>4 then raise EAbstractMemTList.Create('Invalid CT_AbstractMemTList_Magic size!');
       // Check magic
       for i := 0 to CT_AbstractMemTList_Magic.Length-1 do begin
@@ -443,17 +440,17 @@ begin
       end;
       // Capture Size
       Move(LBytes[4],FElementsOfEachBlock,4);
-      Move(LBytes[8],FNextElementPosition,4);
-      Move(LBytes[12],FFirstBlockPointer,4);
+      Move(LBytes[8],FNextElementIndex,4);
+      Move(LBytes[12],FFirstBlockPointer,FAbstractMem.SizeOfAbstractMemPosition);
       if (FElementsOfEachBlock<=0) then begin
         // Not valid
         FElementsOfEachBlock := 0;
         FFirstBlockPointer := 0;
-        FNextElementPosition := 0;
+        FNextElementIndex := 0;
       end;
     end;
   finally
-    if (FInitialZone.position>0) and (FElementsOfEachBlock<=0) and ((FInitialZone.size=0) or (FInitialZone.size>=CT_AbstractMemTList_HeaderSize))  then begin
+    if (FInitialZone.position>0) and (FElementsOfEachBlock<=0) and ((FInitialZone.size=0) or (FInitialZone.size>=MinAbstractMemTListHeaderSize(FAbstractMem)))  then begin
       // Need to initialize and save
       FElementsOfEachBlock := ADefaultElementsPerBlock;
       if FElementsOfEachBlock<=0 then raise EAbstractMemTList.Create('Invalid Default Elements per block');
@@ -462,8 +459,8 @@ begin
         LBytes[i] := Byte(Ord(CT_AbstractMemTList_Magic.Chars[i]));
       end;
       Move(FElementsOfEachBlock,LBytes[4],4);
-      Move(FNextElementPosition,LBytes[8],4);
-      Move(FFirstBlockPointer,LBytes[12],4);
+      Move(FNextElementIndex,LBytes[8],4);
+      Move(FFirstBlockPointer,LBytes[12],FAbstractMem.SizeOfAbstractMemPosition);
       // Save header
       FAbstractMem.Write( FInitialZone.position, LBytes[0], Length(LBytes) );
     end;
@@ -478,11 +475,11 @@ begin
   try
   AddRange(AIndex,1);
   if (UseCacheData(True)) then begin
-    Move(APosition, FCacheData[AIndex*4], 4);
+    Move(APosition, FCacheData[AIndex*FAbstractMem.SizeOfAbstractMemPosition], FAbstractMem.SizeOfAbstractMemPosition);
     FCacheUpdated := True;
   end else begin
     GetPointerTo(AIndex,False,LPreviousBlockPointer,LBlockPointer,LIndexInBlock);
-    FAbstractMem.Write( LBlockPointer + (LIndexInBlock*4), APosition, 4 );
+    FAbstractMem.Write( LBlockPointer + (LIndexInBlock*FAbstractMem.SizeOfAbstractMemPosition), APosition, FAbstractMem.SizeOfAbstractMemPosition );
   end;
   finally
     FAbstractMemTListLock.Release;
@@ -494,18 +491,19 @@ var LBlockPointer, LPreviousBlockPointer : TAbstractMemPosition;
   LIndexInBlock, i, j : Integer;
 begin
   CheckInitialized;
-  if (AIndexStart<0) or (AIndexStart>FNextElementPosition) then raise EAbstractMemTList.Create(Format('%s LoadElements out of range %d in 0..%d',[ClassName,AIndexStart,FNextElementPosition-1]));
+  if (AIndexStart<0) or (AIndexStart>FNextElementIndex) then raise EAbstractMemTList.Create(Format('%s LoadElements out of range %d in 0..%d',[ClassName,AIndexStart,FNextElementIndex-1]));
 
-  SetLength(AElements, (FNextElementPosition - AIndexStart)*4);
+  SetLength(AElements, (FNextElementIndex - AIndexStart)*FAbstractMem.SizeOfAbstractMemPosition);
 
   i := AIndexStart;
-  while (i<FNextElementPosition) do begin
+  while (i<FNextElementIndex) do begin
     GetPointerTo( i ,False,LPreviousBlockPointer,LBlockPointer,LIndexInBlock);
     // Load this
     j := FElementsOfEachBlock - LIndexInBlock;
-    if (i + j -1) >= FNextElementPosition then j := FNextElementPosition - i;
+    if (i + j -1) >= FNextElementIndex then j := FNextElementIndex - i;
 
-    FAbstractMem.Read(LBlockPointer + (LindexInBlock * 4), AElements[ (i-AIndexStart)*4 ], (j)*4  );
+    FAbstractMem.Read(LBlockPointer + (LindexInBlock * FAbstractMem.SizeOfAbstractMemPosition),
+        AElements[ (i-AIndexStart)*FAbstractMem.SizeOfAbstractMemPosition ], (j)*FAbstractMem.SizeOfAbstractMemPosition  );
 
     inc(i,j);
   end;
@@ -516,6 +514,16 @@ begin
   FAbstractMemTListLock.Acquire;
 end;
 
+class function TAbstractMemTList.MinAbstractMemTListHeaderSize(AAbstractMem: TAbstractMem): Integer;
+begin
+  //
+  Result := 4 + 4 + 4 + AAbstractMem.SizeOfAbstractMemPosition;
+    // [0] 4 for magic
+    // [4] 4 for elements of each block
+    // [8] 4 for next element (counter)
+    // [12] 4 or 8 for first block position
+end;
+
 procedure TAbstractMemTList.RemoveRange(AIndexStart, ARemoveCount: Integer);
 var LBlockPointer, LPreviousBlockPointer, LNext : TAbstractMemPosition;
   LIndexInBlock, i, j, n : Integer;
@@ -525,21 +533,21 @@ begin
   FAbstractMemTListLock.Acquire;
   try
   if (ARemoveCount<=0) then raise EAbstractMemTList.Create(Format('%s remove count %d',[ClassName,ARemoveCount]));
-  if (AIndexStart+ARemoveCount-1>=FNextElementPosition) then begin
-    if (FNextElementPosition>0) then
-      raise EAbstractMemTList.Create(Format('%s remove %d..%d out of range 0..%d',[ClassName,AIndexStart,AIndexStart + ARemoveCount -1, FNextElementPosition-1]))
+  if (AIndexStart+ARemoveCount-1>=FNextElementIndex) then begin
+    if (FNextElementIndex>0) then
+      raise EAbstractMemTList.Create(Format('%s remove %d..%d out of range 0..%d',[ClassName,AIndexStart,AIndexStart + ARemoveCount -1, FNextElementIndex-1]))
     else raise EAbstractMemTList.Create(Format('%s remove %d..%d out of range (NO ELEMENTS)',[ClassName,AIndexStart,AIndexStart + ARemoveCount -1]))
   end;
 
   if (UseCacheData(True)) then begin
-    if (AIndexStart+ARemoveCount < FNextElementPosition) then begin
-      Move(FCacheData[(AIndexStart + ARemoveCount) *4],
-           FCacheData[(AIndexStart) *4],
-           FCacheDataUsedBytes-((AIndexStart + ARemoveCount)*4));
+    if (AIndexStart+ARemoveCount < FNextElementIndex) then begin
+      Move(FCacheData[(AIndexStart + ARemoveCount) *FAbstractMem.SizeOfAbstractMemPosition],
+           FCacheData[(AIndexStart) *FAbstractMem.SizeOfAbstractMemPosition],
+           FCacheDataUsedBytes-((AIndexStart + ARemoveCount)*FAbstractMem.SizeOfAbstractMemPosition));
     end;
-    Dec(FCacheDataUsedBytes,(ARemoveCount*4));
+    Dec(FCacheDataUsedBytes,(ARemoveCount*FAbstractMem.SizeOfAbstractMemPosition));
     FCacheUpdated := True;
-    Dec(FNextElementPosition,ARemoveCount);
+    Dec(FNextElementIndex,ARemoveCount);
     Exit;
   end;
 
@@ -553,37 +561,37 @@ begin
     GetPointerTo(i,False,LPreviousBlockPointer,LBlockPointer,LIndexInBlock);
     // Move from LIndexInBlock to FElementsOfEachBlock-1 in this block
     j := FElementsOfEachBlock - (LIndexInBlock);
-    if ((n+j)*4>Length(LElements)) then j := (Length(LElements) DIV 4)-n;
-    FAbstractMem.Write( LBlockPointer + (LIndexInBlock*4), LElements[ n*4 ], j*4 );
+    if ((n+j)*FAbstractMem.SizeOfAbstractMemPosition>Length(LElements)) then j := (Length(LElements) DIV FAbstractMem.SizeOfAbstractMemPosition)-n;
+    FAbstractMem.Write( LBlockPointer + (LIndexInBlock*FAbstractMem.SizeOfAbstractMemPosition), LElements[ n*FAbstractMem.SizeOfAbstractMemPosition ], j*FAbstractMem.SizeOfAbstractMemPosition );
     inc(n,j);
     inc(i,j);
-  until (i >= FNextElementPosition - ARemoveCount);// or (j=0);
+  until (i >= FNextElementIndex - ARemoveCount);// or (j=0);
 
-  LBlocksBefore := ((FNextElementPosition DIV FElementsOfEachBlock)+1);
-  LBlocksAfter := (((FNextElementPosition-ARemoveCount) DIV FElementsOfEachBlock)+1);
+  LBlocksBefore := ((FNextElementIndex DIV FElementsOfEachBlock)+1);
+  LBlocksAfter := (((FNextElementIndex-ARemoveCount) DIV FElementsOfEachBlock)+1);
 
   if (LBlocksBefore<LBlocksAfter) then begin
-    GetPointerTo(FNextElementPosition-ARemoveCount,False,LPreviousBlockPointer,LBlockPointer,LIndexInBlock);
+    GetPointerTo(FNextElementIndex-ARemoveCount,False,LPreviousBlockPointer,LBlockPointer,LIndexInBlock);
     while (LBlockPointer>0) do begin
-      FAbstractMem.Read( LBlockPointer + (FElementsOfEachBlock * 4), LNext, 4);
+      FAbstractMem.Read( LBlockPointer + (FElementsOfEachBlock * FAbstractMem.SizeOfAbstractMemPosition), LNext, FAbstractMem.SizeOfAbstractMemPosition);
       FAbstractMem.Dispose(LBlockPointer);
       LBlockPointer := LNext;
       //
       if LPreviousBlockPointer>0 then begin
         LNext := 0;
-        FAbstractMem.Write( LPreviousBlockPointer + (FElementsOfEachBlock * 4), LNext, 4);
+        FAbstractMem.Write( LPreviousBlockPointer + (FElementsOfEachBlock * FAbstractMem.SizeOfAbstractMemPosition), LNext, FAbstractMem.SizeOfAbstractMemPosition);
       end else begin
         // This is first block pointer
         FFirstBlockPointer := 0;
-        FAbstractMem.Write( FInitialZone.position + 12, FFirstBlockPointer, 4 );
+        FAbstractMem.Write( FInitialZone.position + 12, FFirstBlockPointer, FAbstractMem.SizeOfAbstractMemPosition );
       end;
     end;
 
   end;
 
   // Save to header
-  Dec(FNextElementPosition,ARemoveCount);
-  FAbstractMem.Write( FInitialZone.position + 8, FNextElementPosition, 4 );
+  Dec(FNextElementIndex,ARemoveCount);
+  FAbstractMem.Write( FInitialZone.position + 8, FNextElementIndex, 4 );
   finally
     FAbstractMemTListLock.Release;
   end;
@@ -596,11 +604,11 @@ begin
   FAbstractMemTListLock.Acquire;
   try
   if (UseCacheData(True)) then begin
-    Move( Value, FCacheData[AIndex*4], 4);
+    Move( Value, FCacheData[AIndex*FAbstractMem.SizeOfAbstractMemPosition], FAbstractMem.SizeOfAbstractMemPosition);
     FCacheUpdated := True;
   end else begin
     GetPointerTo(AIndex,False,LPreviousBlockPointer,LBlockPointer,LIndexInBlock);
-    FAbstractMem.Write( LBlockPointer + (LIndexInBlock*4), Value, 4);
+    FAbstractMem.Write( LBlockPointer + (LIndexInBlock*FAbstractMem.SizeOfAbstractMemPosition), Value, FAbstractMem.SizeOfAbstractMemPosition);
   end;
   finally
     FAbstractMemTListLock.Release;

+ 3 - 2
src/libraries/abstractmem/tests/AbstractMem.Tests.dpr

@@ -17,8 +17,7 @@ uses
   Classes,
   {$ELSE}
   Interfaces,
-  Forms,
-  GUITestRunner,
+  Forms, GuiTestRunner,
   {$ENDIF }
   {$ELSE}
   Forms,
@@ -39,6 +38,7 @@ uses
   UAbstractMem.Tests in 'src\UAbstractMem.Tests.pas',
   UAbstractBTree.Tests in 'src\UAbstractBTree.Tests.pas',
   UAbstractMemBTree.Tests in 'src\UAbstractMemBTree.Tests.pas',
+  UAbstractMemTList.Tests in 'src\UAbstractMemTList.Tests.pas',
   UFileMem.Tests in 'src\UFileMem.Tests.pas';
 
 {$IF Defined(FPC) and (Defined(CONSOLE_TESTRUNNER))}
@@ -59,6 +59,7 @@ begin
   Application := TFreePascalConsoleRunner.Create(nil);
   {$ENDIF}
 
+  Application.Title:='Test';
   Application.Initialize;
   {$IFDEF FPC}
   {$IF Not Defined(CONSOLE_TESTRUNNER)}

+ 8 - 3
src/libraries/abstractmem/tests/AbstractMem.Tests.lpi

@@ -32,7 +32,7 @@
         <PackageName Value="FCL"/>
       </Item3>
     </RequiredPackages>
-    <Units Count="15">
+    <Units Count="16">
       <Unit0>
         <Filename Value="AbstractMem.Tests.dpr"/>
         <IsPartOfProject Value="True"/>
@@ -93,19 +93,24 @@
         <Filename Value="src\UFileMem.Tests.pas"/>
         <IsPartOfProject Value="True"/>
       </Unit14>
+      <Unit15>
+        <Filename Value="src\UAbstractMemTList.Tests.pas"/>
+        <IsPartOfProject Value="True"/>
+      </Unit15>
     </Units>
   </ProjectOptions>
   <CompilerOptions>
     <Version Value="11"/>
     <PathDelim Value="\"/>
     <SearchPaths>
-      <IncludeFiles Value="..;src"/>
+      <IncludeFiles Value="..;src;$(ProjOutDir)"/>
       <OtherUnitFiles Value="..;src"/>
       <UnitOutputDirectory Value="lib\$(TargetCPU)-$(TargetOS)"/>
     </SearchPaths>
     <Parsing>
       <SyntaxOptions>
-        <SyntaxMode Value="delphi"/>
+        <SyntaxMode Value="Delphi"/>
+        <IncludeAssertionCode Value="True"/>
       </SyntaxOptions>
     </Parsing>
     <Linking>

+ 1 - 1
src/libraries/abstractmem/tests/src/UAbstractBTree.Tests.pas

@@ -21,7 +21,7 @@ type
   private
   protected
   public
-    constructor Create(AAllowDuplicates : Boolean; AOrder : Integer);
+    constructor Create(AAllowDuplicates : Boolean; AOrder: Integer);
     function NodeDataToString(const AData : Integer) : String; override;
   End;
 

+ 35 - 45
src/libraries/abstractmem/tests/src/UAbstractMemBTree.Tests.pas

@@ -39,9 +39,9 @@ type
    public
      procedure SetUp; override;
      procedure TearDown; override;
-     procedure TestInfinite_Integer(AOrder : Integer; AAllowDuplicates : Boolean);
-     procedure TestInfinite_String(AOrder : Integer; AAllowDuplicates : Boolean);
-     procedure TestInfinite(AOrder : Integer);
+     procedure TestInfinite_Integer(AOrder : Integer; AAllowDuplicates : Boolean; A64Bytes : Boolean);
+     procedure TestInfinite_String(AOrder : Integer; AAllowDuplicates : Boolean; A64Bytes : Boolean);
+     procedure TestInfinite(AOrder : Integer; A64Bytes : Boolean);
      procedure DoCheckAbstractMem(AAbstractMem : TAbstractMem; AUsedBytes : Integer);
    published
      procedure TestInfiniteOrder_3;
@@ -126,17 +126,17 @@ procedure TestTAbstractMemBTree.TearDown;
 begin
 end;
 
-procedure TestTAbstractMemBTree.TestInfinite(AOrder: Integer);
+procedure TestTAbstractMemBTree.TestInfinite(AOrder: Integer; A64Bytes : Boolean);
 begin
-  TestInfinite_Integer(AOrder,(AOrder MOD 2)=0);
-  TestInfinite_String(AOrder,(AOrder MOD 2)=0);
+  TestInfinite_Integer(AOrder,(AOrder MOD 2)=0,A64Bytes);
+  TestInfinite_String(AOrder,(AOrder MOD 2)=0,A64Bytes);
 end;
 
-procedure TestTAbstractMemBTree.TestInfinite_Integer(AOrder : Integer; AAllowDuplicates : Boolean);
+procedure TestTAbstractMemBTree.TestInfinite_Integer(AOrder : Integer; AAllowDuplicates : Boolean; A64Bytes : Boolean);
 var Lbt : TAbstractMemBTreeExampleInteger;
   Lbts : TAbstractMemBTreeExampleString;
   Lzone : TAMZone;
-  intValue, nRounds, nAdds, nDeletes, i : Integer;
+  intValue, nRounds, nAdds, nDeletes, i, intAux : Integer;
   j : TAbstractMemPosition;
   Lnode : TAbstractMemBTreeExampleInteger.TAbstractBTreeNode;
   Lmem : TAbstractMem;
@@ -144,15 +144,12 @@ var Lbt : TAbstractMemBTreeExampleInteger;
 begin
   Lmem := TMem.Create(0,False);
   Try
-    {$IFDEF FPC}
-    Randomize;
-    {$ELSE}
-    RandomizeProc(0);
-    {$ENDIF}
+    RandSeed := 0;
+    LMem.Initialize(A64Bytes,Random(64)+4);
     nRounds := 0;
     nAdds := 0;
     nDeletes := 0;
-    Lzone := Lmem.New(TAbstractMemBTree.MinAbstractMemInitialPositionSize);
+    Lzone := Lmem.New(TAbstractMemBTree.MinAbstractMemInitialPositionSize(Lmem));
     try
     Lbt := TAbstractMemBTreeExampleInteger.Create(Lmem,Lzone,AAllowDuplicates,AOrder);
     try
@@ -168,10 +165,7 @@ begin
             inc(nDeletes);
           end;
         end;
-        if Random(100)=0 then begin
-          Lbt.CheckConsistency;
-        end;
-      until (nRounds>=AOrder * 10000);
+      until (nRounds>=AOrder * 1000);
       Lbt.CheckConsistency;
       // Delete mode
       while Lbt.Count>0 do begin
@@ -180,19 +174,19 @@ begin
           Lnode := Lbt.GetNode(Lnode.childs[Random(Lnode.Count)+1]);
         end;
         If Not Lbt.Delete(Lnode.data[Random(Lnode.Count)]) then raise Exception.Create('Not Found to delete!');
-        if Random(100)=0 then begin
-          Lbt.CheckConsistency;
-        end;
       end;
       Lbt.CheckConsistency;
       // Try to re-use
-      for i := 1 to AOrder do begin
+      i := 0;
+      repeat
         intValue := Random(AOrder * 100);
-        Assert(Lbt.Add(intValue),Format('Cannot re-use %d/%d and add %d',[i,AOrder,intValue]));
-        Lbt.CheckConsistency;
-        Assert(Lbt.FindIndex(i-1,j),Format('Cannot find %d on index %d on order %d',[intValue,i-1,AOrder]));
-        Assert(Not Lbt.FindIndex(i,j),Format('Found %d on index %d on order %d',[j,i-1,AOrder]));
-      end;
+        if (not Lbt.Find(intValue,Lnode,intAux)) or (AAllowDuplicates) then begin
+          inc(i);
+          Assert(Lbt.Add(intValue),Format('Cannot re-use %d/%d and add %d',[i,AOrder,intValue]));
+          Assert(Lbt.FindIndex(i-1,j),Format('Cannot find %d on index %d on order %d',[intValue,i-1,AOrder]));
+          Assert(Not Lbt.FindIndex(i,j),Format('Found %d on index %d on order %d',[j,i-1,AOrder]));
+        end;
+      until Lbt.Count>(AOrder * 10);
     finally
       Lbt.Free;
     end;
@@ -213,7 +207,7 @@ begin
   End;
 end;
 
-procedure TestTAbstractMemBTree.TestInfinite_String(AOrder: Integer; AAllowDuplicates : Boolean);
+procedure TestTAbstractMemBTree.TestInfinite_String(AOrder: Integer; AAllowDuplicates : Boolean; A64Bytes : Boolean);
 var Lbt : TAbstractMemBTreeExampleString;
   Lzone : TAMZone;
   intValue, nRounds, nAdds, nDeletes, i : Integer;
@@ -224,15 +218,12 @@ var Lbt : TAbstractMemBTreeExampleString;
 begin
   Lmem := TMem.Create(0,False);
   Try
-    {$IFDEF FPC}
-    Randomize;
-    {$ELSE}
-    RandomizeProc(0);
-    {$ENDIF}
+    RandSeed := 0;
+    Lmem.Initialize(A64Bytes,Random(64)+4);
     nRounds := 0;
     nAdds := 0;
     nDeletes := 0;
-    Lzone := Lmem.New(TAbstractMemBTree.MinAbstractMemInitialPositionSize);
+    Lzone := Lmem.New(TAbstractMemBTree.MinAbstractMemInitialPositionSize(Lmem));
     try
     Lbt := TAbstractMemBTreeExampleString.Create(Lmem,Lzone,AAllowDuplicates,AOrder,TComparison_String);
     try
@@ -248,9 +239,6 @@ begin
             inc(nDeletes);
           end;
         end;
-        if Random(100)=0 then begin
-          Lbt.CheckConsistency;
-        end;
       until (nRounds>=AOrder * 10000);
       Lbt.CheckConsistency;
       // Delete mode
@@ -261,9 +249,6 @@ begin
         end;
         LCurrData := Lbt.LoadData(Lnode.data[Random(Lnode.Count)]);
         if Not Lbt.DeleteData(LCurrData) then raise EAbstractMemBTree.Create('Not found to delete!');
-        if Random(100)=0 then begin
-          Lbt.CheckConsistency;
-        end;
       end;
       Lbt.CheckConsistency;
       // Try to re-use
@@ -319,27 +304,32 @@ end;
 
 procedure TestTAbstractMemBTree.TestInfiniteOrder_3;
 begin
-  TestInfinite(3);
+//  TestInfinite(3,False);
+  TestInfinite(3,True);
 end;
 
 procedure TestTAbstractMemBTree.TestInfiniteOrder_4;
 begin
-  TestInfinite(4);
+  TestInfinite(4,False);
+  TestInfinite(4,True);
 end;
 
 procedure TestTAbstractMemBTree.TestInfiniteOrder_5;
 begin
-  TestInfinite(5);
+  TestInfinite(5,False);
+  TestInfinite(5,True);
 end;
 
 procedure TestTAbstractMemBTree.TestInfiniteOrder_6;
 begin
-  TestInfinite(6);
+  TestInfinite(6,False);
+  TestInfinite(6,True);
 end;
 
 procedure TestTAbstractMemBTree.TestInfiniteOrder_7;
 begin
-  TestInfinite(7);
+  TestInfinite(7,False);
+  TestInfinite(7,True);
 end;
 
 initialization

+ 120 - 0
src/libraries/abstractmem/tests/src/UAbstractMemTList.Tests.pas

@@ -0,0 +1,120 @@
+unit UAbstractMemTList.Tests;
+
+{$IFDEF FPC}
+  {$MODE Delphi}
+{$ENDIF}
+
+interface
+
+uses
+   SysUtils,
+   {$IFDEF FPC}
+   fpcunit, testutils, testregistry,
+   {$ELSE}
+   TestFramework,
+   {$ENDIF}
+   {$IFNDEF FPC}System.Generics.Collections,System.Generics.Defaults,{$ELSE}Generics.Collections,Generics.Defaults,{$ENDIF}
+   UAbstractMem,
+   UAbstractMemTList;
+
+type
+   TestTAbstractMemTList = class(TTestCase)
+   strict private
+   public
+     procedure SetUp; override;
+     procedure TearDown; override;
+     procedure TestInfinite(A64Bytes : Boolean; AUseCache, AUseCacheAuto : Boolean; AElementsPerBlock : Integer);
+   published
+     procedure Test_32b_NoCache;
+     procedure Test_32b_Cache;
+     procedure Test_64b_NoCache;
+     procedure Test_64b_Cache;
+   end;
+
+implementation
+
+
+{ TestTAbstractMemTList }
+
+procedure TestTAbstractMemTList.SetUp;
+begin
+  inherited;
+end;
+
+procedure TestTAbstractMemTList.TearDown;
+begin
+  inherited;
+end;
+
+procedure TestTAbstractMemTList.TestInfinite(A64Bytes, AUseCache,
+  AUseCacheAuto: Boolean; AElementsPerBlock: Integer);
+var LMem : TMem;
+  LAMList : TAbstractMemTList;
+  LAMZone : TAMZone;
+  i : Integer;
+begin
+  RandSeed:=0;
+  LMem := TMem.Create(0,False);
+  Try
+    LMem.Initialize(A64Bytes,4);
+    LAMZone := LMem.New(TAbstractMemTList.MinAbstractMemTListHeaderSize(LMem));
+    LAMList := TAbstractMemTList.Create(LMem,LAMZone,AElementsPerBlock,AUseCache);
+    Try
+      LAMList.UseCacheAuto := AUseCacheAuto;
+      // Start process
+      repeat
+        LAMList.Add(LMem.New((Random(50)+1)*4).position);
+        if (Random(5)=0) and (LAMList.Count>0) then begin
+          i := Random(LAMList.Count);
+          LAMZone.position := LAMList.Position[i];
+          LAMList.Delete(i);
+          LMem.Dispose(LAMZone.position);
+        end;
+        if Random(100)=0 then
+          LAMList.FlushCache;
+      until LAMList.Count>(AElementsPerBlock*200);
+      //
+      LAMList.FlushCache;
+      //
+      while (LAMList.Count>0) do begin
+        i := Random(LAMList.Count);
+        LAMZone.position := LAMList.Position[i];
+        LAMList.Delete(i);
+        LMem.Dispose(LAMZone.position);
+        if Random(100)=0 then
+          LAMList.FlushCache;
+      end;
+      LAMList.FlushCache;
+      LMem.CheckConsistency();
+      //
+    Finally
+      LAMList.Free;
+    End;
+  Finally
+    LMem.Free;
+  End;
+end;
+
+procedure TestTAbstractMemTList.Test_32b_Cache;
+begin
+  TestInfinite(False,True,True,10);
+end;
+
+procedure TestTAbstractMemTList.Test_32b_NoCache;
+begin
+  TestInfinite(False,False,False,10);
+end;
+
+procedure TestTAbstractMemTList.Test_64b_Cache;
+begin
+  TestInfinite(True,True,True,10);
+end;
+
+procedure TestTAbstractMemTList.Test_64b_NoCache;
+begin
+  TestInfinite(True,False,False,10);
+end;
+
+initialization
+  RegisterTest(TestTAbstractMemTList{$IFNDEF FPC}.Suite{$ENDIF});
+end.