Recent

Author Topic: Does exists a component TMemoryStream base that has managed memory handling ?  (Read 1401 times)

jamie

  • Hero Member
  • *****
  • Posts: 6091
I would like to know this.?

I want it to expand memory when needed and keep it expanded when reduced but report back the actual memory in use as it does now.

 It would also need an added method, "Compact" so that I can reduce it at any time when I want to.
The only true wisdom is knowing you know nothing

ASerge

  • Hero Member
  • *****
  • Posts: 2223
It would also need an added method, "Compact" so that I can reduce it at any time when I want to.
Capacity := Size

jamie

  • Hero Member
  • *****
  • Posts: 6091
That isn't in the Tmemorystream class however, at least not with the install I have..
The only true wisdom is knowing you know nothing

ASerge

  • Hero Member
  • *****
  • Posts: 2223
That isn't in the Tmemorystream class however, at least not with the install I have..
OK
Code: Pascal  [Select][+][-]
  1. {$APPTYPE CONSOLE}
  2. {$MODE OBJFPC}
  3.  
  4. uses Classes;
  5.  
  6. type
  7.   TCompactingMemStream = class(TMemoryStream)
  8.     procedure Compact;
  9.   end;
  10.  
  11. procedure TCompactingMemStream.Compact;
  12.  
  13.   procedure PropertyHack(constref OldCapacity, NewCapacity: PtrInt);
  14.   begin
  15.     PPtrInt(@OldCapacity)^ := NewCapacity;
  16.   end;
  17.  
  18. var
  19.   P: Pointer;
  20.   LSize: Int64;
  21. begin
  22.   LSize := Size;
  23.   if LSize < Capacity then
  24.   begin
  25.     P := Memory;
  26.     ReAllocMem(P, LSize);
  27.     SetPointer(P, LSize);
  28.     PropertyHack(Capacity, LSize);
  29.   end;
  30. end;
  31.  
  32. var
  33.   M: TCompactingMemStream;
  34. begin
  35.   M := TCompactingMemStream.Create;
  36.   try
  37.     M.Size := 9999;
  38.     Writeln('Size:', M.Size, ', Capacity:', M.Capacity);
  39.     M.Compact;
  40.     Writeln('Size:', M.Size, ', Capacity:', M.Capacity);
  41.   finally
  42.     M.Free;
  43.   end;
  44.   Readln;
  45. end.
Or make class helper.

jamie

  • Hero Member
  • *****
  • Posts: 6091
I can create a class that does this, I just don't want to reinvent the wheel  8-)
The only true wisdom is knowing you know nothing

jamie

  • Hero Member
  • *****
  • Posts: 6091
yes I suppose I could do that... ;)

I'll look into it, thanks.
The only true wisdom is knowing you know nothing

ASerge

  • Hero Member
  • *****
  • Posts: 2223
I can create a class that does this, I just don't want to reinvent the wheel  8-)
Not understand you. You want and at the same time don't want to. If you do not like the new class, then make class helper, as I indicated earlier.

jamie

  • Hero Member
  • *****
  • Posts: 6091
I'll try it, that looks to be what I want. I still want the SIZE property to return the actual lower quantity..

 The idea is when I am shrinking the demand of the memory I don't to reallocate the real memory until later on so I can set a behavior flag to auto compact or manual compact etc..

 Also the streaming part of it still needs to adhere to the originals of the Tmemoeystream where it does not play with the capacity unless it needs to be enlarged, otherwise if a stream is used at the beginning of the memory the size property should be set but the capacity should be higher or where ever it was before the stream operation.

 In other words, if set for manual compact operation the streaming system should only increase capacity when needed but not decrease it when changing the SIZE property or calling SetSize method but only increase it incases where there isn't enough for the request.

 I'll play with the code you gave here.


The only true wisdom is knowing you know nothing

ASerge

  • Hero Member
  • *****
  • Posts: 2223
Again I didn't understand. It seems that everything you want is done here.

jamie

  • Hero Member
  • *****
  • Posts: 6091
This is what I ended up..
Code: Pascal  [Select][+][-]
  1.   TCompactingMemStream = class(TMemoryStream)
  2.     Protected
  3.     fManualCompacting:Boolean;
  4.     fThisSize :Int64; //
  5.     procedure SetSize(Const NewSize :Int64) override;
  6.     Function  GetSize:Int64;override;
  7.     Public
  8.     Function GetCapacity:Int64;
  9.     procedure Compact;
  10.     property ManualCompacting :Boolean Read fManualCompacting write fManualCompacting;
  11.   end;
  12.  
  13. implementation
  14.  
  15. Function TCompactingMemStream.GetCapacity:Int64;
  16. begin
  17.   Result := Capacity;
  18. end;
  19. Procedure TCompactingMemStream.SetSize(Const NewSize:Int64);
  20. begin
  21.   if (not fManualCompacting)or(NewSize > Capacity) Then
  22.    Inherited SetSize(newSize);
  23.   fThisSize := NewSize;
  24. end;
  25. Function TCompactingMemStream.GetSize:Int64;
  26. begin
  27.   Result := fThisSize;
  28. end;
  29.  
  30. procedure TCompactingMemStream.Compact;
  31.  
  32.   procedure PropertyHack(constref OldCapacity, NewCapacity: PtrInt);
  33.   begin
  34.     PPtrInt(@OldCapacity)^ := NewCapacity;
  35.   end;
  36.  
  37. var
  38.   P: Pointer;
  39.   LSize: Int64;
  40. begin
  41.   LSize := Size;
  42.   if LSize < Capacity then
  43.   begin
  44.     P := Memory;
  45.     ReAllocMem(P, LSize);
  46.     SetPointer(P, LSize);
  47.     PropertyHack(Capacity, LSize);
  48.   end;
  49. end;
  50.  

I am sure there is something I missed..

I noticed there is a 32 bit version of SetSize that is virtual, does that internally call the 64 bit version or do I need to override that too ?
The only true wisdom is knowing you know nothing

jamie

  • Hero Member
  • *****
  • Posts: 6091
I will need to abandon this idea for now, there are a few things wrong with the TStream class.

One of them is the fact that the procedure WRITE is not virtual and you can not properly overload it so that WriteBuffer will call the proper overload for example, I would have to also overload that too to fix this.

  Also when WRITE is executed it is not calling the SetSize method which is virtual so that I can update examine the size and log it.

  My old Delphi help file tells me WRITE is virtual and all other write methods call this one in the end.

 Apparently this isn't what it happening here because it tells me there is no WRITE to overload.

 also the SetSIze isn't getting called when the WRITE bumps up the memory which I need.

Oh well.

EDIT ---------------------
 I think I've over come the problem, I had an Inherited tag in the wrong position for the WRITE but Its still strange how SetSize does not get called when write needs to bump up memory.

 But in any case I used the Position location in the WRITE handler to test for true size written to what I have and if larger than what I have I then update my value to match it...
This seems to work ok for the moment... I'll now see how the seek works.
« Last Edit: March 29, 2020, 10:21:54 pm by jamie »
The only true wisdom is knowing you know nothing

PascalDragon

  • Hero Member
  • *****
  • Posts: 5446
  • Compiler Developer
I think I've over come the problem, I had an Inherited tag in the wrong position for the WRITE but Its still strange how SetSize does not get called when write needs to bump up memory.

Write implicitly enlarges the stream. SetSize is only intended to preallocate large parts (e.g. files), mainly because underlying operating system functionality for writing files does that as well (and SetSize might not be implemented for everything, e.g. pipes). It's simply unnecessary and leads to performance impacts.

 

TinyPortal © 2005-2018