CnPack Forum


 
Subject: 对一个CNPack编码单元的改进.速度提升了十几倍.也就是1000%
wr960204
新警察
Rank: 1



UID 1667
Digest Posts 0
Credits 32
Posts 14
点点分 32
Reading Access 10
Registered 2006-1-14
Status Offline
Post at 2006-1-14 18:16  Profile | Blog | P.M. 
对一个CNPack编码单元的改进.速度提升了十几倍.也就是1000%

CNBase64.pas
编码单元.
改进解码也是查表.速度会提高.
另外原来的单元编码解码过滤都是用字符串相加的方式,会导致一次次内存的销毁和创建.改成了进算长度一次性分配的方式.
经过测试:旧的编码要1110毫秒的数据改进后只要125毫秒.
         旧的解码要6455毫秒的数据改进后只要210毫秒


改进后的单元如下:
unit CnBase64;

interface

uses
  SysUtils;




  function Base64Encode(InputData:string;var OutputData:string):Byte;

  function Base64Decode(InputData:string;var OutputData:string):Byte;

const
  BASE64_OK       = 0; // 转换成功
  BASE64_ERROR    = 1; // 转换错误(未知错误) (e.g. can't encode octet in input stream) -> error in implementation
  BASE64_INVALID  = 2; // 输入的字符串中有非法字符 (在 FilterDecodeInput=False 时可能出现)
  BASE64_LENGTH   = 3; // 数据长度非法
  BASE64_DATALEFT = 4; // too much input data left (receveived 'end of encoded data' but not end of input string)
  BASE64_PADDING  = 5; // 输入的数据未能以正确的填充字符结束

implementation

const
//------------------------------------------------------------------------------
// 编码的参考表
//------------------------------------------------------------------------------
  EnCodeTab: array[0..64] of Char =
  (
    'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H',
    'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P',
    'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X',
    'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f',
    'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n',
    'o', 'p', 'q', 'r', 's', 't', 'u', 'v',
    'w', 'x', 'y', 'z', '0', '1', '2', '3',
    '4', '5', '6', '7', '8', '9', '+', '/',
    '=');
//------------------------------------------------------------------------------
//解码的参考表
//------------------------------------------------------------------------------
  {不包含在Base64里面的字符直接给零,反正也取不到}
  DecodeTable: array[#0..#127] of Byte =
  (
    Byte('='), 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00,
    00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00,
    00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 62, 00, 00, 00, 63,
    52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 00, 00, 00, 00, 00, 00,
    00, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14,
    15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 00, 00, 00, 00, 00,
    00, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40,
    41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 00, 00, 00, 00, 00
    );

var
  FilterDecodeInput:Boolean=True;

function Base64Encode(InputData:string;var OutputData:string):Byte;
var
  Times, SrcLen, i: integer;
  x1, x2, x3, x4: char;
  xt: byte;
begin
  SrcLen := length(InputData);
  if SrcLen mod 3 = 0 then
    Times := SrcLen div 3
  else
    Times := SrcLen div 3 + 1;
  SetLength(OutputData, Times * 4);   //一次分配整块内存,避免一次次字符串相加,一次次释放分配内存
  for i := 0 to times - 1 do
  begin
    if SrcLen >= (3 + i * 3) then
    begin
      x1 := EnCodeTab[(ord(InputData[1 + i * 3]) shr 2)];
      xt := (ord(InputData[1 + i * 3]) shl 4) and 48;
      xt := xt or (ord(InputData[2 + i * 3]) shr 4);
      x2 := EnCodeTab[xt];
      xt := (Ord(InputData[2 + i * 3]) shl 2) and 60;
      xt := xt or (ord(InputData[3 + i * 3]) shr 6);
      x3 := EnCodeTab[xt];
      xt := (ord(InputData[3 + i * 3]) and 63);
      x4 := EnCodeTab[xt];
    end
    else if SrcLen >= (2 + i * 3) then
    begin
      x1 := EnCodeTab[(ord(InputData[1 + i * 3]) shr 2) ];
      xt := (ord(InputData[1 + i * 3]) shl 4) and 48;
      xt := xt or (ord(InputData[2 + i * 3]) shr 4);
      x2 := EnCodeTab[xt];
      xt := (ord(InputData[2 + i * 3]) shl 2) and 60;
      x3 := EnCodeTab[xt ];
      x4 := '=';
    end
    else
    begin
      x1 := EnCodeTab[(ord(InputData[1 + i * 3]) shr 2)];
      xt := (ord(InputData[1 + i * 3]) shl 4) and 48;
      x2 := EnCodeTab[xt];
      x3 := '=';
      x4 := '=';
    end;
    OutputData[I shl 2 + 1] := X1;
    OutputData[I shl 2 + 2] := X2;
    OutputData[I shl 2 + 3] := X3;
    OutputData[I shl 2 + 4] := X4;
  end;
  result:=BASE64_OK;
end;

function Base64Decode(InputData:string;var OutputData:string):Byte;
var
  SrcLen, Times, i: integer;
  x1, x2, x3, x4, xt: byte;
  C: Integer;
  function FilterLine(Source:String): string;
  var
    P, PP: PChar;
    I: Integer;
  begin
    SrcLen := Length(Source);
    GetMem(P, Srclen);                   //一次分配整块内存,避免一次次字符串相加,一次次释放分配内存
    PP := P;
    FillChar(P^, Srclen, 0);
    for I := 1 to SrcLen do
    begin
      if Source[I] in ['0'..'9', 'A'..'Z', 'a'..'z', '+', '/', '='] then
      begin
        PP^ := Source[I];
        Inc(PP);
      end;
    end;
    SetString(Result, P, PP - P);        //截取有效部分
    FreeMem(P, SrcLen);
  end;
begin
  if (InputData='') then
  begin
    result:=BASE64_OK;
    exit;
  end;
  OutPutData:='';

  if FilterDecodeInput then
    InputData:=FilterLine(InputData);

  SrcLen := Length(InputData);
  SetLength(OutputData, (SrcLen * 3 div 4));  //一次分配整块内存,避免一次次字符串相加,一次次释放分配内存
  Times := SrcLen div 4;
  C := 1;
  for i := 0 to Times - 1 do
  begin
    x1 := DecodeTable[InputData[1 + i shl 2]];
    x2 := DecodeTable[InputData[2 + i shl 2]];
    x3 := DecodeTable[InputData[3 + i shl 2]];
    x4 := DecodeTable[InputData[4 + i shl 2]];
    x1 := x1 shl 2;
    xt := x2 shr 4;
    x1 := x1 or xt;
    x2 := x2 shl 4;
    OutputData[C] := Chr(x1);
    Inc(C);
    if x3 = 64 then
      break;
    xt := x3 shr 2;
    x2 := x2 or xt;
    x3 := x3 shl 6;
    OutputData[C] := Chr(x2);
    Inc(C);
    if x4 = 64 then
      break;
    x3 := x3 or x4;
    OutputData[C] := Chr(x3);
    Inc(C);
  end;

  result:=BASE64_OK;
end;

end.
Top
flamingo
新警察
Rank: 1



UID 179
Digest Posts 0
Credits 39
Posts 39
点点分 39
Reading Access 10
Registered 2003-10-12
Status Offline
Post at 2006-1-15 11:56  Profile | Blog | P.M. 
了不起。问个问题,为什么不把
function Base64Encode(InputData:string;var OutputData:string):Byte;
设计成:
function Base64Encode(InputData:TStream;var OutputData:string):Byte;
Top
wr960204
新警察
Rank: 1



UID 1667
Digest Posts 0
Credits 32
Posts 14
点点分 32
Reading Access 10
Registered 2006-1-14
Status Offline
Post at 2006-1-16 11:18  Profile | Blog | P.M. 
我自己改造的版本有重载Stream的。不过这里我完全适用的是原来CNBase64声明的函数。为了和CNPack的兼容阿
Top
flamingo
新警察
Rank: 1



UID 179
Digest Posts 0
Credits 39
Posts 39
点点分 39
Reading Access 10
Registered 2003-10-12
Status Offline
Post at 2006-1-16 19:03  Profile | Blog | P.M. 
谢谢 wr960204 的回复,有了你最初的原型,overload是否也可以象下面那样做?

function Base64Encode(InputData:string;var OutputData:string):Byte;overload;
begin
// 这里的代码见 wr960204 帖子 ......
end;

function Base64Encode(InputData:TStream;var OutputData:string):Byte;overload;
var
Str:TStringStream;
begin
Str:=TStringStream.Create('');
Str.CopyFrom(InputData,InputData.Size);
Result:=Base64Encode(Str.DataString,OutputData);
Str.Free;
end;
Top
天地弦
新警察
Rank: 1



UID 631
Digest Posts 0
Credits 47
Posts 47
点点分 47
Reading Access 10
Registered 2005-1-5
Status Offline
Post at 2006-2-10 15:24  Profile | Site | Blog | P.M. 
wr960204,是A3么?呵呵
Top
fwjindream
新警察
Rank: 1



UID 1448
Digest Posts 0
Credits 8
Posts 8
点点分 8
Reading Access 10
Registered 2005-12-8
Status Offline
Post at 2006-3-17 10:57  Profile | Blog | P.M. 
LZ写的那个东东,
那真是相当的好用啊.
顶一下.表示敬意.
Top
takaya
新警察
Rank: 1



UID 2262
Digest Posts 0
Credits 16
Posts 13
点点分 16
Reading Access 10
Registered 2006-6-14
Status Offline
Post at 2006-6-14 10:37  Profile | Blog | P.M. 
不知道在现在的版本中改进没有.
Top
Passion (LiuXiao)
管理员
Rank: 9Rank: 9Rank: 9


UID 359
Digest Posts 19
Credits 6812
Posts 3579
点点分 6812
Reading Access 102
Registered 2004-3-28
Status Offline
Post at 2006-10-25 21:23  Profile | Blog | P.M. 
现在采纳了wr960204的优化方案,改进了。
Top
 




All times are GMT++8, the time now is 2024-9-20 06:05

    本论坛支付平台由支付宝提供
携手打造安全诚信的交易社区 Powered by Discuz! 5.0.0  © 2001-2006 Comsenz Inc.
Processed in 0.009390 second(s), 8 queries , Gzip enabled

Clear Cookies - Contact Us - CnPack Website - Archiver - WAP