Browse Source

Improvements on AbstractMem library 1.1

Pascal Coin 4 years ago
parent
commit
df00519553

+ 17 - 6
src/libraries/abstractmem/UAbstractMemTList.pas

@@ -60,6 +60,7 @@ type
     FCacheData : TBytes;
     FCacheUpdated : Boolean;
     FCacheDataLoaded : Boolean;
+    FCacheDataUsedBytes : Integer;
 
     function GetPosition(AIndex: Integer): TAbstractMemPosition;
     procedure SetPosition(AIndex: Integer; const Value: TAbstractMemPosition);
@@ -187,9 +188,15 @@ 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 (UseCacheData) then begin
+    if (Length(FCacheData)-FCacheDataUsedBytes)< (AInsertCount*4) then begin
+      // Increase
+      if (FElementsOfEachBlock>AInsertCount) then i := FElementsOfEachBlock
+      else i := AInsertCount;
+      SetLength(FCacheData,Length(FCacheData) + (i * 4));
+    end;
     FCacheUpdated := True;
-    SetLength(FCacheData,Length(FCacheData)+(AInsertCount*4));
-    Move(FCacheData[AIndexStart*4],FCacheData[(AIndexStart+AInsertCount)*4],Length(FCacheData)-((AIndexStart+AInsertCount)*4));
+    Inc(FCacheDataUsedBytes,(AInsertCount*4));
+    Move(FCacheData[AIndexStart*4],FCacheData[(AIndexStart+AInsertCount)*4],FCacheDataUsedBytes-((AIndexStart+AInsertCount)*4));
     Inc(FNextElementPosition,AInsertCount);
     Exit;
   end;
@@ -237,6 +244,7 @@ begin
 
   SetLength(FCacheData,0);
   FCacheUpdated := False;
+  FCacheDataUsedBytes := 0;
   Finally
     FAbstractMemTListLock.Release;
   End;
@@ -253,6 +261,7 @@ begin
   FUseCache := AUseCache;
   FCacheUpdated := False;
   FCacheDataLoaded := False;
+  FCacheDataUsedBytes := 0;
 
   FAbstractMem := AAbstractMem;
   FInitialZone.Clear;
@@ -310,7 +319,7 @@ begin
   LNext := 0;
   // Save full:
   i := 0;
-  while ((i*4) < (Length(FCacheData))) do begin
+  while ((i*4) < (FCacheDataUsedBytes)) do begin
     GetPointerTo(i,True,LPreviousBlockPointer,LBlockPointer,LIndexInBlock);
     if (i+FElementsOfEachBlock-1 >= FNextElementPosition) then begin
       LElements := FNextElementPosition - i;
@@ -522,10 +531,9 @@ begin
     if (AIndexStart+ARemoveCount < FNextElementPosition) then begin
       Move(FCacheData[(AIndexStart + ARemoveCount) *4],
            FCacheData[(AIndexStart) *4],
-           Length(FCacheData)-((AIndexStart + ARemoveCount)*4));
-
+           FCacheDataUsedBytes-((AIndexStart + ARemoveCount)*4));
     end;
-    SetLength(FCacheData,Length(FCacheData) - (ARemoveCount*4));
+    Dec(FCacheDataUsedBytes,(ARemoveCount*4));
     FCacheUpdated := True;
     Dec(FNextElementPosition,ARemoveCount);
     Exit;
@@ -601,10 +609,12 @@ begin
   if (FUseCache) then begin
     FlushCache;
     SetLength(FCacheData,0);
+    FCacheDataUsedBytes := 0;
   end else begin
     SetLength(FCacheData,0);
     FCacheDataLoaded := False;
     FCacheUpdated := False;
+    FCacheDataUsedBytes := 0;
   end;
   FUseCache := Value;
 end;
@@ -621,6 +631,7 @@ begin
     if Not FCacheDataLoaded then begin
       FCacheDataLoaded := True;
       LoadElements(0,FCacheData);
+      FCacheDataUsedBytes := Length(FCacheData);
     end;
   end else Result := False;
 end;

+ 128 - 36
src/libraries/abstractmem/UCacheMem.pas

@@ -1,4 +1,4 @@
-unit UCacheMem;
+unit UCacheMem;
 
 {
   This file is part of AbstractMem framework
@@ -108,6 +108,9 @@ type
     maxUsedCacheSize : Integer;
     reusedCacheMemDataCount : Integer;
     reusedCacheMemDataBytes : Int64;
+    deletedBlocksReused : Integer;
+    deletedBlocksSaved : Integer;
+    deletedBlocksCount : Integer;
     procedure Clear;
     function ToString : String;
   end;
@@ -135,10 +138,13 @@ type
     FMaxCacheSize: Integer;
     FMaxCacheDataBlocks: Integer;
     FDefaultCacheDataBlocksSize : Integer;
+    FGridCache : Boolean;
     function FindCacheMemDataByPosition(APosition : Integer; out APCacheMemData : PCacheMemData) : Boolean;
     procedure Delete(var APCacheMemData : PCacheMemData); overload;
     function FlushCache(const AFlushCacheList : TOrderedList<PCacheMemData>) : Boolean; overload;
     procedure CheckMaxMemUsage;
+    function LoadDataExt(var ABuffer; const AStartPos, ASize : Integer) : Boolean;
+    procedure SaveToCacheExt(const ABuffer; ASize, AStartPos : Integer; AMarkAsPendingToSave : Boolean);
   public
     Constructor Create(AOnNeedDataProc : TOnNeedDataProc; AOnSaveDataProc : TOnSaveDataProc);
     Destructor Destroy; override;
@@ -165,6 +171,7 @@ type
     property MaxCacheSize : Integer read FMaxCacheSize write FMaxCacheSize;
     property MaxCacheDataBlocks : Integer read FMaxCacheDataBlocks write FMaxCacheDataBlocks;
     property DefaultCacheDataBlocksSize : Integer read FDefaultCacheDataBlocksSize write FDefaultCacheDataBlocksSize;
+    property GridCache : Boolean read FGridCache write FGridCache;
     {$IFDEF ABSTRACTMEM_ENABLE_STATS}
     procedure ClearStats;
     property CacheMemStats : TCacheMemStats read FCacheMemStats;
@@ -321,7 +328,8 @@ begin
   FCacheDataBlocks := 0;
   FPendingToSaveBytes := 0;
   FCacheDataSize := 0;
-  FDefaultCacheDataBlocksSize := 4000;
+  FDefaultCacheDataBlocksSize := 9000;
+  FGridCache := False;
   FOnNeedDataProc := AOnNeedDataProc;
   FOnSaveDataProc := AOnSaveDataProc;
   FOldestUsed := Nil;
@@ -340,6 +348,9 @@ begin
   APCacheMemData^.UnMark(Self,APCacheMemData);
   FCacheData.Delete(APCacheMemData);
   Dec(FCacheDataBlocks);
+  {$IFDEF ABSTRACTMEM_ENABLE_STATS}
+  inc(FCacheMemStats.deletedBlocksCount);
+  {$ENDIF}
 end;
 
 destructor TCacheMem.Destroy;
@@ -512,6 +523,36 @@ begin
 end;
 
 function TCacheMem.LoadData(var ABuffer; const AStartPos, ASize: Integer): Boolean;
+Var
+  LNewStartPos, LIndex, LLoadSize, LMoveSize : Integer;
+  Lpc : PByte;
+  LData : TBytes;
+begin
+  if (FGridCache) And (FDefaultCacheDataBlocksSize>0) then begin
+    Result := True;
+    SetLength(LData,FDefaultCacheDataBlocksSize);
+    Lpc := @(ABuffer);
+    LNewStartPos := (((AStartPos-1) DIV FDefaultCacheDataBlocksSize) + 0 ) * FDefaultCacheDataBlocksSize;
+    LIndex := AStartPos - LNewStartPos;
+    while (LNewStartPos < (AStartPos + ASize)) and (Result) do begin
+      if (LNewStartPos + FDefaultCacheDataBlocksSize) > (AStartPos + ASize) then begin
+        LLoadSize := (AStartPos + ASize) - LNewStartPos;
+      end else begin
+        LLoadSize := FDefaultCacheDataBlocksSize;
+      end;
+      LMoveSize := LLoadSize-LIndex;
+      Result := LoadDataExt(LData[0],LNewStartPos,LLoadSize);
+      Move(LData[LIndex],Lpc^,LMoveSize);
+      LIndex := 0;
+      inc(LNewStartPos,FDefaultCacheDataBlocksSize);
+      inc(Lpc,LMoveSize);
+    end;
+  end else begin
+    Result := LoadDataExt(ABuffer,AStartPos,ASize);
+  end;
+end;
+
+function TCacheMem.LoadDataExt(var ABuffer; const AStartPos, ASize: Integer): Boolean;
   // Will return a Pointer to AStartPos
 
   function _CaptureDataFromOnNeedDataProc(ACapturePosStart, ACaptureSize : Integer; var ACapturedData : TBytes; out ACapturedSize : Integer) : Boolean;
@@ -546,7 +587,7 @@ begin
   if ASize=0 then Exit(True);
 
   if (FDefaultCacheDataBlocksSize>0) then begin
-    LNewStartPos := (((AStartPos-1) DIV FDefaultCacheDataBlocksSize) + 0 ) * FDefaultCacheDataBlocksSize;
+    LNewStartPos := (((AStartPos) DIV FDefaultCacheDataBlocksSize)) * FDefaultCacheDataBlocksSize;
     LSizeToStore := (((ASize-1) DIV FDefaultCacheDataBlocksSize) + 1 ) * FDefaultCacheDataBlocksSize;
     if (LNewStartPos + LSizeToStore) < (AStartPos + ASize) then begin
       inc(LSizeToStore, FDefaultCacheDataBlocksSize);
@@ -557,7 +598,7 @@ begin
   end;
 
   if (FindCacheMemDataByPosition(LNewStartPos,PCurrent)) then begin
-    if (PCurrent^.GetEndPos >= (AStartPos + ASize)) then begin
+    if (PCurrent^.GetEndPos >= (AStartPos + ASize -1)) then begin
       // PCurrent has all needed info
       Move(PCurrent^.buffer[ AStartPos-PCurrent^.startPos ],ABuffer,ASize);
       PCurrent^.MarkAsUsed(Self,PCurrent);
@@ -616,6 +657,9 @@ begin
         PToDelete := PCurrent;
         PCurrent := FCacheData.FindSuccessor(PCurrent);
         Delete( PToDelete );
+        {$IFDEF ABSTRACTMEM_ENABLE_STATS}
+        inc(FCacheMemStats.deletedBlocksReused);
+        {$ENDIF}
       end;
     end;
     if (Result) and ((LLastAddedPosition) < (LNewP^.GetEndPos)) then begin
@@ -655,35 +699,7 @@ begin
   CheckMaxMemUsage;
 end;
 
-procedure TCacheMem.SaveToCache(const ABuffer: TBytes; AStartPos: Integer; AMarkAsPendingToSave : Boolean);
-begin
-  SaveToCache(ABuffer[0],Length(ABuffer),AStartPos,AMarkAsPendingToSave);
-end;
-
-function TCacheMem.ToString: String;
-var
-  LLines : TStrings;
-  LPct : Double;
-  PCurrent : PCacheMemData;
-begin
-  LLines := TStringList.Create;
-  try
-    LLines.Add(Format('%s.ToString',[ClassName]));
-    PCurrent := FCacheData.FindLowest;
-    while (Assigned(PCurrent)) do begin
-      LLines.Add( PCurrent^.ToString );
-      PCurrent := FCacheData.FindSuccessor(PCurrent);
-    end;
-    if FCacheDataSize>0 then LPct := (FPendingToSaveBytes / FCacheDataSize)*100
-    else LPct := 0.0;
-    LLines.Add(Format('Total size %d bytes in %d blocks - Pending to Save %d bytes (%.2n%%)',[FCacheDataSize,FCacheDataBlocks,FPendingToSaveBytes,LPct]));
-    Result := LLines.Text;
-  finally
-    LLines.Free;
-  end;
-end;
-
-procedure TCacheMem.SaveToCache(const ABuffer; ASize, AStartPos: Integer; AMarkAsPendingToSave : Boolean);
+procedure TCacheMem.SaveToCacheExt(const ABuffer; ASize, AStartPos: Integer; AMarkAsPendingToSave : Boolean);
 var
   LNewP, PCurrent, PToDelete : PCacheMemData;
   LLastAddedPosition, LBytesCount : Integer;
@@ -710,11 +726,11 @@ begin
   New( LNewP );
   try
     LNewP.Clear;
-    SetLength(LNewP^.buffer, ASize);
     LNewP.startPos := AStartPos;
+    SetLength(LNewP^.buffer, ASize);
     LNewP^.pendingToSave := AMarkAsPendingToSave;
 
-    LLastAddedPosition := AStartPos - 1;
+    LLastAddedPosition := LNewP.startPos - 1;
     while (Assigned(PCurrent)) and ( (LLastAddedPosition+1) < (LNewP^.GetEndPos) ) do begin
       if (PCurrent^.GetEndPos <= LLastAddedPosition) then PCurrent := FCacheData.FindSuccessor( PCurrent )
       else if (PCurrent^.startPos > LNewP^.GetEndPos) then break
@@ -740,6 +756,9 @@ begin
         PToDelete := PCurrent;
         PCurrent := FCacheData.FindSuccessor(PCurrent);
         Delete( PToDelete );
+        {$IFDEF ABSTRACTMEM_ENABLE_STATS}
+        inc(FCacheMemStats.deletedBlocksSaved);
+        {$ENDIF}
       end;
     end;
     // At this point LNewP^.buffer startPos <= AStartPos and LNewP^.buffer Size >= ASize
@@ -765,6 +784,75 @@ begin
   CheckMaxMemUsage;
 end;
 
+procedure TCacheMem.SaveToCache(const ABuffer: TBytes; AStartPos: Integer; AMarkAsPendingToSave : Boolean);
+begin
+  SaveToCache(ABuffer[0],Length(ABuffer),AStartPos,AMarkAsPendingToSave);
+end;
+
+procedure TCacheMem.SaveToCache(const ABuffer; ASize, AStartPos: Integer; AMarkAsPendingToSave: Boolean);
+Var
+  LNewStartPos, LSizeToStore : Integer;
+  Lpc : PByte;
+  LLeftBuff : TBytes;
+begin
+  if (FDefaultCacheDataBlocksSize>0) then begin
+    Lpc := @(ABuffer);
+
+    LNewStartPos := (((AStartPos) DIV FDefaultCacheDataBlocksSize)) * FDefaultCacheDataBlocksSize;
+    // Left chunk:
+    if (LNewStartPos < AStartPos) then begin
+      if LNewStartPos + FDefaultCacheDataBlocksSize <= AStartPos+ASize then LSizeToStore := FDefaultCacheDataBlocksSize
+      else LSizeToStore := (AStartPos+ASize) - (LNewStartPos);
+      SetLength(LLeftBuff,LSizeToStore);
+      LoadDataExt(LLeftBuff[0],LNewStartPos,AStartPos - LNewStartPos);
+      Move(Lpc^,LLeftBuff[ AStartPos - LNewStartPos ],LSizeToStore - (AStartPos - LNewStartPos));
+      SaveToCacheExt(LLeftBuff[0],LSizeToStore,LNewStartPos,AMarkAsPendingToSave);
+      inc(Lpc,LSizeToStore - (AStartPos - LNewStartPos));  // LSizeToStore);
+      inc(LNewStartPos,LSizeToStore);
+    end;
+
+    while (LNewStartPos < (AStartPos + ASize)) do begin
+      LSizeToStore := FDefaultCacheDataBlocksSize;
+      if (FGridCache) then begin
+      end else begin
+        while (LNewStartPos+LSizeToStore+FDefaultCacheDataBlocksSize) <= (AStartPos + ASize) do inc(LSizeToStore,FDefaultCacheDataBlocksSize);
+      end;
+      if (LNewStartPos + LSizeToStore) > (AStartPos + ASize) then begin
+        // Right chunk does not fit on block size
+        LSizeToStore := (AStartPos + ASize) - (LNewStartPos);
+      end;
+      SaveToCacheExt(Lpc^,LSizeToStore,LNewStartPos,AMarkAsPendingToSave);
+      inc(Lpc,LSizeToStore);
+      inc(LNewStartPos,LSizeToStore);
+    end;
+  end else begin
+    SaveToCacheExt(ABuffer,ASize,AStartPos,AMarkAsPendingToSave);
+  end;
+end;
+
+function TCacheMem.ToString: String;
+var
+  LLines : TStrings;
+  LPct : Double;
+  PCurrent : PCacheMemData;
+begin
+  LLines := TStringList.Create;
+  try
+    LLines.Add(Format('%s.ToString',[ClassName]));
+    PCurrent := FCacheData.FindLowest;
+    while (Assigned(PCurrent)) do begin
+      LLines.Add( PCurrent^.ToString );
+      PCurrent := FCacheData.FindSuccessor(PCurrent);
+    end;
+    if FCacheDataSize>0 then LPct := (FPendingToSaveBytes / FCacheDataSize)*100
+    else LPct := 0.0;
+    LLines.Add(Format('Total size %d bytes in %d blocks - Pending to Save %d bytes (%.2n%%)',[FCacheDataSize,FCacheDataBlocks,FPendingToSaveBytes,LPct]));
+    Result := LLines.Text;
+  finally
+    LLines.Free;
+  end;
+end;
+
 { TCacheMemData }
 
 procedure TCacheMemData.Clear;
@@ -906,12 +994,16 @@ begin
   freememElaspedMillis := 0;
   reusedCacheMemDataCount := 0;
   reusedCacheMemDataBytes := 0;
+  deletedBlocksReused := 0;
+  deletedBlocksSaved := 0;
+  deletedBlocksCount := 0;
 end;
 
 function TCacheMemStats.ToString: String;
 begin
-  Result := Format('CacheMemStats Reused:%d (%d bytes) - Flush:%d (%d bytes) %d millis - FreeMem:%d (%d bytes) %d millis',
+  Result := Format('CacheMemStats Reused:%d (%d bytes) - Deleteds:%d (Saved:%d - reused:%d) - Flush:%d (%d bytes) %d millis - FreeMem:%d (%d bytes) %d millis',
      [Self.reusedCacheMemDataCount,Self.reusedCacheMemDataBytes,
+      Self.deletedBlocksCount,Self.deletedBlocksSaved,Self.deletedBlocksReused,
       Self.flushCount,Self.flushSize,Self.flushElapsedMillis,
       Self.freememCount,Self.freememSize,
       Self.freememElaspedMillis]);

+ 61 - 13
src/libraries/abstractmem/tests/src/UCacheMem.Tests.pas

@@ -40,7 +40,7 @@ begin
 
   for i := 0 to ASize-1 do begin
     if (ABytes[i] <> ((ALoadedStartPos+i+1) MOD 89)) then begin
-      raise ETestFailure.Create(Format('Value at pos %d (item %d) should be %d instead of %d',[ALoadedStartPos+i,i,((ALoadedStartPos+i) MOD 89),ABytes[i]]));
+      raise {$IFDEF FPC}Exception{$ELSE}ETestFailure{$ENDIF}.Create(Format('Value at pos %d (item %d) should be %d instead of %d',[ALoadedStartPos+i,i,((ALoadedStartPos+i) MOD 89),ABytes[i]]));
     end;
 
   end;
@@ -58,11 +58,11 @@ end;
 
 function TestTCacheMem.OnNeedDataProc(var ABuffer; AStartPos, ASize: Integer): Integer;
 begin
-  if (High(FCurrentMem) >= AStartPos + ASize) then begin
+  if (Length(FCurrentMem) >= AStartPos + ASize) then begin
     Result := ASize;
     Move(FCurrentMem[AStartPos],ABuffer,ASize);
   end else begin
-    Result := High(FCurrentMem) - AStartPos;
+    Result := Length(FCurrentMem) - AStartPos;
     if Result>0 then begin
       Move(FCurrentMem[AStartPos],ABuffer,Result);
     end;
@@ -71,11 +71,11 @@ end;
 
 function TestTCacheMem.OnSaveDataProc(const ABuffer; AStartPos, ASize: Integer): Integer;
 begin
-  if (High(FCurrentMem) >= AStartPos + ASize) then begin
+  if (Length(FCurrentMem) >= AStartPos + ASize) then begin
     Result := ASize;
     Move(ABuffer,FCurrentMem[AStartPos],ASize);
   end else begin
-    Result := High(FCurrentMem) - AStartPos;
+    Result := Length(FCurrentMem) - AStartPos;
     if Result>0 then begin
       Move(ABuffer,FCurrentMem[AStartPos],Result);
     end;
@@ -99,36 +99,84 @@ Var LCMem : TCacheMem;
 begin
   LCMem := TCacheMem.Create(OnNeedDataProc,OnSaveDataProc);
   Try
-    InitCurrentMem(11);
+    InitCurrentMem(22);
     SetLength(LBuff,Length(FCurrentMem));
 
-    LCMem.DefaultCacheDataBlocksSize :=10;
+    LCMem.DefaultCacheDataBlocksSize :=5;
+    LCMem.GridCache := True;
     // Check replacing initial position of buffer on Load
     LCMem.Clear;
-    LCMem.LoadData(LBuff[0],3,3);
+
+    FillChar(LBuff[0],Length(LBuff),0);
+    CheckTrue( LCMem.LoadData(LBuff[0],3,3) );
     CheckBytes(LBuff,3,3);
-    LCMem.LoadData(LBuff[0],1,9);
+
+    FillChar(LBuff[0],Length(LBuff),0);
+    CheckTrue( LCMem.LoadData(LBuff[0],1,9) );
     CheckBytes(LBuff,1,9);
+
+    FillChar(LBuff[0],Length(LBuff),0);
+    CheckTrue( LCMem.LoadData(LBuff[0],9,2) );
+    CheckBytes(LBuff,9,2);
+
+    FillChar(LBuff[0],Length(LBuff),0);
+    CheckTrue( LCMem.LoadData(LBuff[0],8,3) );
+    CheckBytes(LBuff,8,3);
+
+    // Check false and load final data
+    FillChar(LBuff[0],Length(LBuff),0);
+    CheckFalse( LCMem.LoadData(LBuff[0],Length(FCurrentMem)-3,4) );
+    CheckBytes(LBuff,Length(FCurrentMem)-3,3);
     LCMem.ConsistencyCheck;
 
+    // Load all to LBuff
+    CheckTrue( LCMem.LoadData(LBuff[0],0,Length(LBuff)) );
     // Check replacing initial position of buffer on Save
     LCMem.Clear;
     LCMem.SaveToCache(LBuff[0],3,3,True);
     LCMem.SaveToCache(LBuff[0],7,0,True);
+
+    // Check saving chunks
+    LCMem.Clear;
+    LCMem.DefaultCacheDataBlocksSize := 5;
+    LCMem.GridCache := False;
+    LCMem.SaveToCache(LBuff[2],5,2,True);
+    LCMem.SaveToCache(LBuff[1],15,1,True);
+    CheckTrue( LCMem.CacheDataBlocks=3, Format('3 Cache blocks: %d',[LCMem.CacheDataBlocks]));
+    LCMem.Clear;
+    LCMem.GridCache := True;
+    LCMem.SaveToCache(LBuff[2],5,2,True);
+    LCMem.SaveToCache(LBuff[1],15,1,True);
+    CheckTrue( LCMem.CacheDataBlocks=4, Format('4 Cache blocks: %d',[LCMem.CacheDataBlocks]));
+    LCMem.Clear;
+
+    // Clear FCurrentMem
+    LCMem.Clear;
+    FillChar(FCurrentMem[0],Length(FCurrentMem),0);
+    // Save from LBuff
+    LCMem.SaveToCache(LBuff,0,True);
+    LCMem.FlushCache;
     LCMem.ConsistencyCheck;
 
     LCMem.Clear;
-    InitCurrentMem(100000);
+    InitCurrentMem(100);
     SetLength(LBuff,Length(FCurrentMem));
 
-    CheckTrue( LCMem.LoadData(LBuff[0],0,100) );
+    // Save 3 blocks
+    LCMem.LoadData(LBuff[0],2,2*LCMem.DefaultCacheDataBlocksSize);
+    LCMem.Clear;
+    LCMem.SaveToCache(LBuff[0], 2*LCMem.DefaultCacheDataBlocksSize , 2,True);
+    CheckTrue( LCMem.CacheDataBlocks=3, '3 Cache blocks');
+
+    CheckTrue( LCMem.LoadData(LBuff[0],1,98) );
     // Incremental round
     i := 1;
     while (i+i < High(FCurrentMem)) do begin
-      CheckTrue( LCMem.LoadData(LBuff[0],i,i) );
+      CheckTrue( LCMem.LoadData(LBuff[0],i-1,i) );
+      CheckBytes(LBuff,i-1,i);
       inc(i);
     end;
-    CheckFalse( LCMem.LoadData( LBuff[0],i,i) );
+    CheckFalse( LCMem.LoadData( LBuff[0],i+1,i) );
 
     LCMem.ConsistencyCheck;
   Finally