Einzelnen Beitrag anzeigen

Benutzerbild von Sir Rufo
Sir Rufo

Registriert seit: 5. Jan 2005
Ort: Stadthagen
9.454 Beiträge
 
Delphi 10 Seattle Enterprise
 
#28

AW: Bit-Schiebereien

  Alt 9. Mai 2014, 16:52
Ok, hier der Code.

Durch das Verschieben sollten keine Wert mit mehr als 25bit abgerufen werden, da es sonst zu komischen Ergebnissen kommen kann

Es erfolgt keine Überprüfung der Index-Werte ... wer das möchte, der kann sich das ja noch einbauen

UPDATE
Ich habe nochmals ca. 2ms weniger (bei 1.000.000 Zugriffen) herausgekitzelt durch eine Änderung in der GetData Methode
Delphi-Quellcode:
program dp_180297;

{$APPTYPE CONSOLE}
{$R *.res}

uses
  System.Generics.Collections,
  System.Classes,
  System.SysUtils,
  System.Diagnostics,
  BaseData in 'BaseData.pas',
  BaseDataFactory in 'BaseDataFactory.pas';

type
  TData1 = class( TBaseData )
  public
    property Value1 : Integer index $000604 read GetData; // Offset 6 Bit-Width 4
    property Value2 : Integer index $000010 read GetData; // Offset 0 Bit-Width 16
  end;

procedure ValueCheck( AInstance : TData1 );
begin
  Assert( AInstance.Value1 = 9 );
  Assert( AInstance.Value2 = 65151 );
end;

procedure PerformanceCheck( AInstance : TData1 );
const
  C_ROUNDS = 1000000;
var
  LWatch : TStopwatch;
  LValue : Integer;
  LIdx : Integer;
begin
  LWatch := TStopwatch.StartNew;
  for LIdx := 1 to C_ROUNDS do
    begin
      LValue := AInstance.Value1;
    end;
  LWatch.Stop;

  Writeln( C_ROUNDS, ' Rounds in ', LWatch.ElapsedMilliseconds, 'ms' );
end;

procedure FactoryTest;
var
  LStream : TStream;
  LData : TBytes;
  LInstance : TBaseData;
begin
  TBaseDataFactory.RegisterType( $00, TData1 );

  LStream := TMemoryStream.Create;
  try
    LData := TBytes.Create( $00 { Type } , $02 { Size of Data } , $FE, $7F );
    LStream.Write( LData, Length( LData ) );
    LStream.Seek( 0, soFromBeginning );
    LInstance := TBaseDataFactory.CreateFromStream( LStream );
    try
      ValueCheck( LInstance as TData1 );
    finally
      LInstance.Free;
    end;
  finally
    LStream.Free;
  end;
end;

procedure Main;
var
  LData : TBytes;
  LInstance : TData1;
begin

  LData := TBytes.Create( $FE, $7F );
  // 1111111001111111
  // ......====......
  // Value1 ^ = 1001(bin) = 9(decimal)

  LInstance := TData1.Create( LData );
  try
    ValueCheck( LInstance );
    PerformanceCheck( LInstance );
  finally
    LInstance.Free;
  end;
end;

begin
  ReportMemoryLeaksOnShutdown := True;

  try
    Main;
    FactoryTest;
  except
    on E : Exception do
      Writeln( E.ClassName, ': ', E.Message );
  end;

  ReadLn;

end.
Delphi-Quellcode:
unit BaseData;

interface

uses
  System.SysUtils;

type
  TBaseData = class
  private
    FData : TBytes;
  protected
    function GetData( const Index : integer ) : integer;
  public
    constructor Create( AData : TBytes );
  end;

implementation

{ TBaseData }

constructor TBaseData.Create( AData : TBytes );
begin
  inherited Create;
  FData := AData;
end;

function TBaseData.GetData( const Index : integer ) : integer;
var
  LBitCount : integer;
  LBitOffset : integer;
  LByteOffset : integer;
  LByteIdx : PByte;
  LMask : Byte;
begin
  LBitCount := index and $FF;
  LBitOffset := ( index shr 8 ) and $FFFF;
  LByteOffset := LBitOffset div 8;
  LBitOffset := LBitOffset - LByteOffset * 8;

  LByteIdx := @FData[LByteOffset];

  LMask := ( 1 shl ( 8 - LBitOffset ) ) - 1;
  Result := ( LByteIdx^ and LMask );
  LBitCount := LBitCount - ( 8 - LBitOffset );

  while LBitCount > 0 do
    begin
      Inc( LByteIdx );
      Result := Result shl 8;
      Result := Result or LByteIdx^;
      LBitCount := LBitCount - 8;
    end;

  if LBitCount < 0
  then
    Result := Result shr ( -LBitCount );

end;

end.
Delphi-Quellcode:
unit BaseDataFactory;

interface

uses
  System.Generics.Collections,
  System.Classes,
  System.SysUtils,
  BaseData;

type
  TBaseDataClass = class of TBaseData;

  TBaseDataFactory = class
  private
    class var _Types : TDictionary<Byte, TBaseDataClass>;
  protected
    class constructor Create;
    class destructor Destroy;
  public
    class function CreateFromStream( AStream : TStream ) : TBaseData;
    class procedure RegisterType( AType : Byte; AClass : TBaseDataClass );
  end;

implementation

{ TBaseDataFactory }

class constructor TBaseDataFactory.Create;
begin
  _Types := TDictionary<Byte, TBaseDataClass>.Create;
end;

class function TBaseDataFactory.CreateFromStream( AStream : TStream ) : TBaseData;
var
  LType : Byte;
  LSize : Byte;
  LData : TBytes;
  LClass : TBaseDataClass;
begin
  AStream.Read( LType, SizeOf( LType ) );
  AStream.Read( LSize, SizeOf( LSize ) );
  SetLength( LData, LSize );
  AStream.Read( LData, LSize );

  LClass := _Types[LType]; // Bei einem unbekannten Typen wird hier eine Exception geworfen
  Result := LClass.Create( LData );
end;

class destructor TBaseDataFactory.Destroy;
begin
  _Types.Free;
end;

class procedure TBaseDataFactory.RegisterType( AType : Byte; AClass : TBaseDataClass );
begin
  _Types.AddOrSetValue( AType, AClass );
end;

end.
Kaum macht man's richtig - schon funktioniert's
Zertifikat: Sir Rufo (Fingerprint: ‎ea 0a 4c 14 0d b6 3a a4 c1 c5 b9 dc 90 9d f0 e9 de 13 da 60)

Geändert von Sir Rufo ( 9. Mai 2014 um 17:58 Uhr)
  Mit Zitat antworten Zitat