среда, 27 августа 2014 г.

Черновик. Написать о том как использование "шаблонов" и "примесей" избавляет от "косвенности" и лишнего распределения памяти

Написать о том как использование "шаблонов" и "примесей" избавляет от "косвенности" и лишнего распределения памяти.

На примере Tm3HeaderStream.

Можно ведь так:

type
 TA = class
  private
   fData : Pointer;
  private
   procedure AllocData;
  protected
   function DataSize: Integer; virtual; abstract;
 end;//TA

...

 TC = record
  ...
 end;//TC

 TB = class(TA)
  protected
   function DataSize: Integer; override;
 end;//TB

...

procedure TA.AllocData;
begin
 GetMem(fData, DataSize);
end;
...

function TB.DataSize: Integer; override;
begin
 Result := SizeOf(TC);
end;

А можно так:

type
 TA<T> = class
  private
   fData : T;
 end;/TA

...

 TC = record
  ...
 end;/TC

 TB = class(TA<TC>)
 end;//TB

Мне кажется, что второй вариант - "вкуснее".

Смежные темы:

Абстрактные контейнеры
Абстрактные контейнеры. Часть 2
Пояснение про контейнеры
Выводим конкретные атомарные контейнеры из абстрактных
Конкретные контейнеры. Часть 2
Стандартная библиотека шаблонов
Коротко. САМОЕ удивительное знание, которое я вынес из книг о программировании
ToDo. Написать про массивы, списки и итераторы
Про скрипты, итераторы и обработку исключений. Черновик

Старый код Tm3HeaderStream:
type
        Tm3CustomHeaderStream=    class(Tm3CustomStream)
         {* Поток с заголовком-идентификатором. }
         private


          _Status:                LongWord;


                function          InitProc00000001    (const ABitMask: LongWord
                                                      ): LongWord;

                procedure         DoneProc00000001    (
                                                      );


                function          InitProc00000002    (const ABitMask: LongWord
                                                      ): LongWord;

                procedure         DoneProc00000002    (
                                                      );


                function          InitProc00000004    (const ABitMask: LongWord
                                                      ): LongWord;

                procedure         DoneProc00000004    (
                                                      );


                function          InitProc00000008    (const ABitMask: LongWord
                                                      ): LongWord;

                procedure         DoneProc00000008    (
                                                      );


                function          InitProc00000010    (const ABitMask: LongWord
                                                      ): LongWord;

                procedure         DoneProc00000010    (
                                                      );


         protected


                procedure         CreateContext       (
                                                      ); override;


         private
          FHeaderData:            Pointer;
          FHeaderDataCompare:     Pointer;
          FHeaderDataSize:        LongInt;

          FHeaderFullSize:        LongInt;

          FHeaderSize:            LongInt;

          FHeaderLoaded:          LongInt;
          FHeaderLocked:          LongInt;


         protected
           procedure Cleanup;
                  override;
                  {-}


                property          _HeaderData: Pointer read FHeaderData;


                function          InitHeaderData      (
                                                      ): Pointer; virtual; abstract;

                function          InitHeaderDataSize  (
                                                      ): LongInt; virtual; abstract;

                function          InitHeaderFullSize  (
                                                      ): LongInt; virtual; abstract;


                procedure         DefaultInitAction   (
                                                      ); virtual;

                procedure         DefaultDoneAction   (
                                                      ); virtual;


                procedure         Read                (ABuff: Pointer;
                                                       ASize: LongInt;
                                                       var   AResult: LongInt;
                                                       var   AReturn: HRESULT
                                                      ); override;

                procedure         Write               (ABuff: Pointer;
                                                       ASize: LongInt;
                                                       var   AResult: LongInt;
                                                       var   AReturn: HRESULT
                                                      ); override;


                procedure         Seek                (AOffset       : Int64;
                                                       AOrigin       : TSeekOrigin;
                                                       var   AResult : Int64;
                                                       var   AReturn : HRESULT
                                                      ); override;


                procedure         SetSize             (ASize: Int64;
                                                       var   AReturn: HRESULT
                                                      ); override;


                procedure         LockRegion          (AOffset: Int64;
                                                       ASize: Int64;
                                                       ALockType: LongInt;
                                                       var   AReturn: HRESULT
                                                      ); override;

                procedure         UnlockRegion        (AOffset: Int64;
                                                       ASize: Int64;
                                                       ALockType: LongInt;
                                                       var   AReturn: HRESULT
                                                      ); override;


          function pm_GetSize: Int64;
            override;
            {-}

      function pm_GetLocksSupported: Longint;
        override;
        {-}
      procedure StatStgName(var   AResult : PWideChar;
                            var   AReturn : HRESULT);
        override;
        {-}

         public


          class function          HeaderID            (
                                                      ): TCLSID; virtual; abstract;


                constructor       Create              (const AStream: IStream;
                                                       const AAccess: LongInt
                                                      );
                  {* - создает поток c заголовком вокруг потока aStream. }                                    

                procedure         LoadHeader          (
                                                      );
                  {* - загружает заголовок в память. }                                    

                procedure         SaveHeader          (const AForcedSave: LongBool = False
                                                      );
                  {* - сохраняет заголовок. }


                procedure         LockHeader          (
                                                      );
                  {* - закрывает заголовок. }                                    

                procedure         UnlockHeader        (
                                                      );
                  {* - открывает заголовок. }                                    


         end;//Tm3CustomHeaderStream
...
// start class Tm3CustomHeaderStream

function Tm3CustomHeaderStream.InitProc00000001(const ABitMask: LongWord): LongWord;
begin
 {$IfDef m3UseL3Memory}
 m3HeaderBuffers^.AllocItem(FHeaderData, FHeaderFullSize, InitHeaderData, FHeaderDataSize);
 {$Else  m3UseL3Memory}
 m2MEMAllocBuff(FHeaderData,FHeaderFullSize,InitHeaderData,FHeaderDataSize);
 {$EndIf m3UseL3Memory}
 Result:=ABitMask;
end;

procedure Tm3CustomHeaderStream.DoneProc00000001;
begin
 {$IfDef m3UseL3Memory}
 m3HeaderBuffers^.FreeItem(FHeaderData);
 {$Else  m3UseL3Memory}
 m2MEMFree(FHeaderData);
 {$EndIf m3UseL3Memory}
end;

function Tm3CustomHeaderStream.InitProc00000002(const ABitMask: LongWord): LongWord;
begin
 if not ReadOnly then
 {$IfDef m3UseL3Memory}
  m3HeaderBuffers^.AllocItem(FHeaderDataCompare, FHeaderFullSize, InitHeaderData, FHeaderDataSize);
 {$Else  m3UseL3Memory}
  m2MEMAllocBuff(FHeaderDataCompare,FHeaderFullSize,InitHeaderData,FHeaderDataSize);
 {$EndIf m3UseL3Memory}
 Result:=ABitMask;
end;

procedure Tm3CustomHeaderStream.DoneProc00000002;
begin
 {$IfDef m3UseL3Memory}
 m3HeaderBuffers^.FreeItem(FHeaderDataCompare);
 {$Else  m3UseL3Memory}
 m2MEMFree(FHeaderDataCompare);
 {$EndIf m3UseL3Memory}
end;

function Tm3CustomHeaderStream.InitProc00000004(const ABitMask: LongWord): LongWord;
begin
 {$IFDEF _m3AUTOCREATEHEADER1}
 if (_Stream <> nil) then begin
  LockHeader;
  try
   if (m2COMGetSize(_Stream) = 0) then begin
    Assert(m2COMCheckAccess(m2COMModeAccess(m2COMGetStatStgMode(_Stream)),STGM_WRITE));
    FHeaderLoaded:=1;
    SaveHeader(True);
   end;//m2COMGetSize(_Stream) = 0
  finally
   UnlockHeader;
  end;
 end;//_Stream <> nil
 {$ENDIF}
 Result:=ABitMask;
end;

procedure Tm3CustomHeaderStream.DoneProc00000004;
begin
end;

function Tm3CustomHeaderStream.InitProc00000008(const ABitMask: LongWord): LongWord;
begin
 DefaultInitAction;
 Result:=ABitMask;
end;

procedure Tm3CustomHeaderStream.DoneProc00000008(
                                                  );
begin
 DefaultDoneAction;
end;

function Tm3CustomHeaderStream.InitProc00000010(const ABitMask: LongWord): LongWord;
begin
 if (_Stream <> nil) AND (m2COMGetStatStgMode(_Stream) AND STGM_WRITE = 0) then
  m2COMSetPosition(Int64(FHeaderSize),_Stream);
 Result:=ABitMask;
end;

procedure Tm3CustomHeaderStream.DoneProc00000010;
begin
end;

procedure Tm3CustomHeaderStream.CreateContext;
begin
 inherited;
 FHeaderDataSize:=InitHeaderDataSize;
 FHeaderFullSize:=InitHeaderFullSize;
 FHeaderSize:=CAnyGUIDLength+SizeOf(LongInt)+SizeOf(FHeaderFullSize)+FHeaderFullSize;
end;

procedure Tm3CustomHeaderStream.DefaultInitAction;
begin
 LoadHeader;
end;

procedure   Tm3CustomHeaderStream.DefaultDoneAction;
begin
 SaveHeader;
end;

procedure   Tm3CustomHeaderStream.Read(ABuff: Pointer;
                                       ASize: LongInt;
                                       var   AResult: LongInt;
                                       var   AReturn: HRESULT
                                      );
begin
 if SUCCEEDED(AReturn) then
  AReturn:=_Stream.Read(ABuff,ASize,@AResult);
end;

procedure   Tm3CustomHeaderStream.Write(ABuff: Pointer;
                                        ASize: LongInt;
                                        var   AResult: LongInt;
                                        var   AReturn: HRESULT
                                       );
begin
 if SUCCEEDED(AReturn) then
  AReturn:=_Stream.Write(ABuff,ASize,@AResult);
end;

procedure Tm3CustomHeaderStream.Seek(AOffset     : Int64;
                                     AOrigin     : TSeekOrigin;
                                     var AResult : Int64;
                                     var AReturn : HRESULT);
var
 LOffset : Int64;
begin
 if SUCCEEDED(AReturn) then
 begin
  if (AOrigin = soBeginning) then
   LOffset:=AOffset+Int64(FHeaderSize)
  else
  if (AOrigin = soEnd) then
  begin
   Assert(false, 'Если это всплывёт, то можно этот Assert временно закомментирровать');
   LOffset := AOffset;
  end//AOrigin = soEnd
  else
   LOffset := AOffset;
  AResult:=m2COMSeek(_Stream,LOffset,Ord(AOrigin))-Int64(FHeaderSize);
 end;//SUCCEEDED(AReturn)
end;

procedure Tm3CustomHeaderStream.SetSize(ASize: Int64;
                                        var   AReturn: HRESULT);
begin
 if SUCCEEDED(AReturn) then
  AReturn:=_Stream.SetSize(ASize+Int64(FHeaderSize));
end;

procedure Tm3CustomHeaderStream.LockRegion(AOffset: Int64;
                                           ASize: Int64;
                                           ALockType: LongInt;
                                           var   AReturn: HRESULT);
begin
 if SUCCEEDED(AReturn) then
  AReturn:=_Stream.LockRegion(Int64(FHeaderSize)+AOffset,ASize,ALockType);
end;

procedure Tm3CustomHeaderStream.UnlockRegion(AOffset: Int64;
                                             ASize: Int64;
                                             ALockType: LongInt;
                                             var   AReturn: HRESULT);
begin
 if SUCCEEDED(AReturn) then
  AReturn:=_Stream.UnlockRegion(Int64(FHeaderSize)+AOffset,ASize,ALockType);
end;

function Tm3CustomHeaderStream.pm_GetSize: Int64;
  //override;
  {-}
begin
 Result:=m2COMGetStatStgSize(_Stream)-Int64(FHeaderSize);
end;

function Tm3CustomHeaderStream.pm_GetLocksSupported: Longint;
  //override;
  {-}
begin
 Result:=m2COMGetStatStgLocks(_Stream);
end;

procedure Tm3CustomHeaderStream.StatStgName(var   AResult : PWideChar;
                                            var   AReturn : HRESULT);
  //override;
  {-}
begin
 if SUCCEEDED(AReturn) then
  try
   aResult := m2COMGetStatStgName(_Stream);
  except
   on E: EOleSysError do aReturn := E.ErrorCode;
  end;//try..except
end;

constructor Tm3CustomHeaderStream.Create(const AStream: IStream;
                                         const AAccess: LongInt);
begin
 inherited;
 m2InitOperation(_Status,InitProc00000001($00000001));
 m2InitOperation(_Status,InitProc00000002($00000002));
 m2InitOperation(_Status,InitProc00000004($00000004));
 m2InitOperation(_Status,InitProc00000008($00000008));
 m2InitOperation(_Status,InitProc00000010($00000010));
end;

procedure Tm3CustomHeaderStream.Cleanup;
begin
 m2DoneOperation(_Status,$00000010,DoneProc00000010);
 m2DoneOperation(_Status,$00000008,DoneProc00000008);
 m2DoneOperation(_Status,$00000004,DoneProc00000004);
 m2DoneOperation(_Status,$00000002,DoneProc00000002);
 m2DoneOperation(_Status,$00000001,DoneProc00000001);
 inherited;
 FHeaderData := nil;//            Pointer;
 FHeaderDataCompare := nil;//     Pointer;
 FHeaderDataSize := 0;//        LongInt;

 FHeaderFullSize := 0;//        LongInt;

 FHeaderSize := 0;//            LongInt;

 FHeaderLoaded := 0;//          LongInt;
 FHeaderLocked := 0;//         LongInt;
 _Status := 0;
end;

procedure Tm3CustomHeaderStream.LoadHeader(
                                            );
var
 LBodyCRC        : LongInt;
 LHeaderID       : AnsiString;
 LHeaderFullSize : LongInt;
 LPosition       : Int64;
begin
 if (FHeaderLoaded = 0) then
 begin
  if (_Stream <> nil) AND (m2COMGetStatStgMode(_Stream) AND STGM_WRITE = 0) then
  begin
   // - мы не можем считать Header - значит он уже должен быть у нас
   LPosition:=m2COMGetPosition(_Stream);
   try
    m2COMSetPosition(0,_Stream);

    m2COMCLSIDFromStream(_Stream,LHeaderID);
    m2COMReadBuffer(_Stream,LBodyCRC,SizeOf(LBodyCRC));

    m2COMReadBuffer(_Stream,LHeaderFullSize,SizeOf(LHeaderFullSize));
    m2CheckValue((LHeaderID = GUIDToString(HeaderID)) and
                 (LHeaderFullSize = FHeaderFullSize));

    m2COMReadBuffer(_Stream,FHeaderData^,FHeaderFullSize);
   finally
    m2COMSetPosition(LPosition,_Stream);
   end;//try..finally
   m2MEMCopy(FHeaderDataCompare,FHeaderData,FHeaderDataSize);
  end;//_Stream <> nil..
 end;//FHeaderLoaded = 0
 Inc(FHeaderLoaded);
end;

procedure Tm3CustomHeaderStream.SaveHeader(const AForcedSave: LongBool);
var
 LBodyCRC  : LongInt;
 LPosition : Int64;
 l_Fake    : Int64;
begin
 Dec(FHeaderLoaded);
 if (FHeaderLoaded = 0) AND (_Stream <> nil) AND not ReadOnly then
 begin
  if AForcedSave or
     (m2MEMCompare(FHeaderData,FHeaderDataCompare,FHeaderDataSize) <> 0) then
  begin
     m2MEMCopy(FHeaderDataCompare,FHeaderData,FHeaderDataSize);
   LPosition:=m2COMGetPosition(_Stream);
   try
    LBodyCRC := 0;
    if AForcedSave then
    begin
     if l3IFail(_Stream.Seek(0, STREAM_SEEK_SET, l_Fake)) then
      Exit;
     m2COMCLSIDToStream(_Stream,GUIDToString(HeaderID));
    end//AForcedSave
    else
    if l3IFail(_Stream.Seek(CAnyGUIDLength, STREAM_SEEK_SET, l_Fake)) then
     Exit;
    m2COMWriteBuffer(_Stream,LBodyCRC,SizeOf(LBodyCRC));
    m2COMWriteBuffer(_Stream,FHeaderFullSize,SizeOf(FHeaderFullSize));
    m2COMWriteBuffer(_Stream,FHeaderData^,FHeaderFullSize);
   finally
    _Stream.Seek(lPosition, STREAM_SEEK_SET, l_Fake);
   end;//try..finally
  end;//AForcedSave..
 end;//FHeaderLoaded = 0..
end;

procedure Tm3CustomHeaderStream.LockHeader;
begin
 if ((FHeaderLocked = 0) and m2COMIsLocksSupported(_Stream)) then
  m2COMTimeLock(_Stream,CAnyGUIDLength,Int64(FHeaderSize)-CAnyGUIDLength);
 Inc(FHeaderLocked);
end;

procedure Tm3CustomHeaderStream.UnlockHeader;
begin
 Dec(FHeaderLocked);
 if ((FHeaderLocked = 0) and m2COMIsLocksSupported(_Stream)) then
  m2COMTimeUnlock(_Stream,CAnyGUIDLength,Int64(FHeaderSize)-CAnyGUIDLength);
end;
...

Новый код, я вскоре выложу.

Он НА ПОРЯДОК - короче и читабельнее.

Вот уж как "быдло-код" становится "просто кодом" (
http://programmingmindstream.blogspot.ru/2014/08/blog-post_59.html
- http://programmingmindstream.blogspot.ru/2014/08/mindstream-firemonkey.html?showComment=1407782559954#c112802013383687686
http://programmingmindstream.blogspot.ru/2014/08/di-service-locator.html
).

Комментариев нет:

Отправить комментарий