惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

T
The Blog of Author Tim Ferriss
Hugging Face - Blog
Hugging Face - Blog
F
Fortinet All Blogs
B
Blog
Cyber Security Advisories - MS-ISAC
Cyber Security Advisories - MS-ISAC
Microsoft Security Blog
Microsoft Security Blog
Blog — PlanetScale
Blog — PlanetScale
月光博客
月光博客
腾讯CDC
小众软件
小众软件
G
Google Developers Blog
V
Visual Studio Blog
罗磊的独立博客
GbyAI
GbyAI
V
V2EX
大猫的无限游戏
大猫的无限游戏
H
Help Net Security
L
LangChain Blog
Engineering at Meta
Engineering at Meta
量子位
The GitHub Blog
The GitHub Blog
博客园 - 司徒正美
WordPress大学
WordPress大学
B
Blog RSS Feed

博客园 - delphi中间件

postgresql建库建表脚本 ubuntu配置postgresql远程访问 ubuntu安装postgresql数据库 delphi 面向模型编程 array of TVarRec core.recordModel.pas 使用泛型序列结构体 DDD建模指导 rabbitMQ VS mqtt redis流的应用场景 redis消费者组 redis流的操作命令 领域服务与领域事件 业务规则和模型 限界上下文与统一语言 领域驱动 mqtt即时通讯 ActiveRecord ORM RAD(速成应用开发) unigui插件框架 工厂流水线式自动生产UNIGUI WEB软件 delphi cs\web一种统一的界面风格 - delphi中间件 - 博客园 动态生成unidbgrid 单据工厂 用json元数据填充模板 mormot2 ORM rest vs jsonrpc SSE技术详解:使用 HTTP 做服务端数据推送应用的技术 http持久连接 json-rpc 2.0
core.binary.pas
delphi中间件 · 2026-01-30 · via 博客园 - delphi中间件
unit core.binary;
// binary key-value pairs serialization
// Need support delphi6/7, The latest grammar cannot be used.
// cxg 2026
{$ifdef fpc}
{$mode delphi}{$H+}
{$endif}

interface

uses Variants, SysUtils, Classes, SyncObjs;

{$IFNDEF fpc}
{$IF CompilerVersion < 18}

// before delphi 2007
type
  TBytes = array of byte;
{$IFEND}
{$IFNDEF UNICODE}

type
  RawByteString = AnsiString;
  PRawByteString = ^RawByteString;
{$ENDIF}
{$ENDIF}

type
  str = RawByteString;
  Pstr = PRawByteString;
  int = integer;
  Pint = PInteger;
  bool = Boolean;
  Pbool = PBoolean;

  TMemPool = class
  private
    FList: TList;
    CS: TCriticalSection;
    FPoolSize: Integer;
  private
    procedure Init;
    function NewObject: TMemoryStream;
  public
    constructor Create(APoolSize: Integer);
    destructor Destroy; override;
  public
    //get a object from pool
    function Lock: TMemoryStream; virtual;
    //return a object to the pool
    procedure Unlock(AValue: TMemoryStream); virtual;
  end;

  TData = class
  private
    FKey: str; // The key must be unique
    FValue: TBytes; // value
  private
    FList: TList;
  private
    function Path(const AKey: str): TData;
    function GetByteCount: int;
  private
    function GetByte(const AKey: str): byte;
    procedure SetByte(const AKey: str; const AValue: byte);
    function GetWord(const AKey: str): Word;
    procedure SetWord(const AKey: str; const AValue: Word);
    function GetCardinal(const AKey: str): Cardinal;
    procedure SetCardinal(const AKey: str; const AValue: Cardinal);
    function GetI(const AKey: str): int;
    procedure SetI(const AKey: str; const AValue: int);
    function GetI64(const AKey: str): Int64;
    procedure SetI64(const AKey: str; const AValue: Int64);
    function GetB(const AKey: str): bool;
    procedure SetB(const AKey: str; const AValue: bool);
    function GetD(const AKey: str): Double;
    procedure SetD(const AKey: str; const AValue: Double);
    function GetDT(const AKey: str): TDateTime;
    procedure SetDT(const AKey: str; const AValue: TDateTime);
    function GetC(const AKey: str): Currency;
    procedure SetC(const AKey: str; const AValue: Currency);
    function GetS(const AKey: str): str;
    procedure SetS(const AKey, AValue: str);
    function GetV(const AKey: str): Variant;
    procedure SetV(const AKey: str; const AValue: Variant);
    function GetST(const AKey: str): TStream;
    procedure SetST(const AKey: str; const AValue: TStream);
    function GetBT(const AKey: str): TBytes;
    procedure SetBT(const AKey: str; const AValue: TBytes);
  public
    property byte[const key: str]: byte read GetByte write SetByte;
    property Word[const key: str]: Word read GetWord write SetWord;
    property Cardinal[const key: str]: Cardinal read GetCardinal
      write SetCardinal;
    property I[const key: str]: int read GetI write SetI;
    property I64[const key: str]: Int64 read GetI64 write SetI64;
    property B[const key: str]: bool read GetB write SetB;
    property C[const key: str]: Currency read GetC write SetC;
    property D[const key: str]: Double read GetD write SetD;
    property DateTime[const key: str]: TDateTime read GetDT write SetDT;
    property S[const key: str]: str read GetS write SetS;
    property V[const key: str]: Variant read GetV write SetV;
    // TClientDataset's data and delta
    property Stream[const key: str]: TStream read GetST write SetST;
    property Bytes[const key: str]: TBytes read GetBT write SetBT;
  public // marshal
    procedure ToStream(AStream: TStream);
    function ToRaw: str;
    function ToBytes: TBytes;
  public // unmarshal
    procedure FromStream(AStream: TStream);
    procedure FromRaw(const AValue: str);
    procedure FromBytes(const AValue: TBytes);
  public
    constructor Create;
    destructor Destroy; override;
    procedure Clear; // clear list;
  end;

var MemPool: TMemPool;

implementation

procedure TData.Clear;
begin
  while FList.Count > 0 do
  begin
    TData(FList[0]).free;
    FList.Delete(0);
  end;
end;

constructor TData.Create;
begin
  FList := TList.Create;
end;

destructor TData.Destroy;
begin
  Clear;
  FreeAndNil(FList);
end;

function TData.Path(const AKey: str): TData;
var
  I: int;
  LFound: bool;
begin
  Result := nil;
  LFound := False;
  for I := 0 to FList.Count - 1 do
  begin
    if AKey = TData(FList[I]).FKey then
    begin
      Result := TData(FList[I]);
      exit;
    end;
  end;
  if not LFound then
  begin
    Result := TData.Create;
    Result.FKey := AKey;
    FList.Add(Result);
  end;
end;

procedure TData.FromBytes(const AValue: TBytes);
var
  LData: TData;
  LPos, LLen: int;
  LKey: str;
begin
  LPos := 0;
  while LPos < length(AValue) do
  begin
    Move(AValue[LPos], LLen, SizeOf(int));
    LPos := LPos + SizeOf(int);
    SetLength(LKey, LLen);
    Move(AValue[LPos], Pstr(LKey)^, LLen);
    LPos := LPos + LLen;
    Move(AValue[LPos], LLen, SizeOf(int));
    LPos := LPos + SizeOf(int);
    LData := TData.Create;
    SetLength(LData.FValue, LLen);
    Move(AValue[LPos], pbyte(LData.FValue)^, LLen);
    LPos := LPos + LLen;
    LData.FKey := LKey;
    FList.Add(LData);
  end;
end;

procedure TData.FromRaw(const AValue: str);
var
  LData: TData;
  LPos, LLen: int;
  LKey: str;
begin
  LPos := 1;
  while LPos < length(AValue) do
  begin
    Move(AValue[LPos], LLen, SizeOf(int));
    LPos := LPos + SizeOf(int);
    SetLength(LKey, LLen);
    Move(AValue[LPos], Pstr(LKey)^, LLen);
    LPos := LPos + LLen;
    Move(AValue[LPos], LLen, SizeOf(int));
    LPos := LPos + SizeOf(int);
    LData := TData.Create;
    SetLength(LData.FValue, LLen);
    Move(AValue[LPos], pbyte(LData.FValue)^, LLen);
    LPos := LPos + LLen;
    LData.FKey := LKey;
    FList.Add(LData);
  end;
end;

procedure TData.FromStream(AStream: TStream);
var
  LLen: int;
  LKey: str;
  LData: TData;
begin
  AStream.Position := 0;
  while AStream.Position < AStream.size do
  begin
    AStream.Read(LLen, SizeOf(int));
    SetLength(LKey, LLen);
    AStream.Read(Pstr(LKey)^, LLen);
    AStream.Read(LLen, SizeOf(int));
    LData := TData.Create;
    SetLength(LData.FValue, LLen);
    AStream.Read(pbyte(LData.FValue)^, LLen);
    LData.FKey := LKey;
    FList.Add(LData);
  end;
end;

function TData.GetB(const AKey: str): bool;
var
  LData: TData;
begin
  LData := Path(AKey);
  Result := Pbool(LData.FValue)^;
end;

function TData.GetBT(const AKey: str): TBytes;
var
  LData: TData;
  LLen: int;
begin
  LData := Path(AKey);
  LLen := length(LData.FValue);
  SetLength(Result, LLen);
  Move(pbyte(LData.FValue)^, pbyte(Result)^, LLen);
end;

function TData.GetD(const AKey: str): Double;
var
  LData: TData;
begin
  LData := Path(AKey);
  Result := PDouble(LData.FValue)^;
end;

function TData.GetDT(const AKey: str): TDateTime;
var
  LData: TData;
begin
  LData := Path(AKey);
  Result := PDateTime(LData.FValue)^;
end;

function TData.GetI(const AKey: str): int;
var
  LData: TData;
begin
  LData := Path(AKey);
  Result := Pint(LData.FValue)^;
end;

function TData.GetI64(const AKey: str): Int64;
var
  LData: TData;
begin
  LData := Path(AKey);
  Result := PInt64(LData.FValue)^;
end;

function TData.GetS(const AKey: str): str;
var
  LData: TData;
  LLen: int;
begin
  LData := Path(AKey);
  LLen := length(LData.FValue);
  if LLen = 0 then
    Result := ''
  else
  begin
    SetLength(Result, LLen);
    Move(pbyte(LData.FValue)^, Pstr(Result)^, LLen);
  end;
end;

function TData.GetByte(const AKey: str): byte;
var
  LData: TData;
begin
  LData := Path(AKey);
  Result := pbyte(LData.FValue)^;
end;

function TData.GetByteCount: int;
var
  I: int;
begin
  Result := 0;
  for I := 0 to FList.Count - 1 do
    Result := Result + SizeOf(int) * 2 + length(TData(FList[I]).FKey) +
      length(TData(FList[I]).FValue);
end;

function TData.GetC(const AKey: str): Currency;
var
  LData: TData;
begin
  LData := Path(AKey);
  Result := PCurrency(LData.FValue)^;
end;

function TData.GetCardinal(const AKey: str): Cardinal;
var
  LData: TData;
begin
  LData := Path(AKey);
  Result := PCardinal(LData.FValue)^;
end;

function TData.GetST(const AKey: str): TStream;
var
  LData: TData;
  LLen: int;
begin
  LData := Path(AKey);
  LLen := length(LData.FValue);
  Result := MemPool.Lock;
  Result.size := LLen;
  Result.Write(pbyte(LData.FValue)^, LLen);
  Result.Position := 0;
end;

function TData.GetV(const AKey: str): Variant;
var
  LPByte: pbyte;
  LLen: int;
  LData: TData;
begin
  LData := Path(AKey);
  LLen := length(LData.FValue);
  Result := VarArrayCreate([0, LLen - 1], varByte);
  LPByte := VarArrayLock(Result);
  try
    Move(pbyte(LData.FValue)^, LPByte^, LLen);
  finally
    VarArrayUnlock(Result);
  end;
end;

function TData.GetWord(const AKey: str): Word;
var
  LData: TData;
begin
  LData := Path(AKey);
  Result := pbyte(LData.FValue)^;
end;

procedure TData.SetB(const AKey: str; const AValue: bool);
var
  LData: TData;
begin
  LData := Path(AKey);
  SetLength(LData.FValue, SizeOf(bool));
  Pbool(LData.FValue)^ := AValue;
end;

procedure TData.SetBT(const AKey: str; const AValue: TBytes);
var
  LData: TData;
  LLen: int;
begin
  LLen := length(AValue);
  LData := Path(AKey);
  SetLength(LData.FValue, LLen);
  Move(pbyte(AValue)^, pbyte(LData.FValue)^, LLen);
end;

procedure TData.SetByte(const AKey: str; const AValue: byte);
var
  LData: TData;
begin
  LData := Path(AKey);
  SetLength(LData.FValue, 1);
  pbyte(LData.FValue)^ := AValue;
end;

procedure TData.SetC(const AKey: str; const AValue: Currency);
var
  LData: TData;
begin
  LData := Path(AKey);
  SetLength(LData.FValue, SizeOf(Currency));
  PCurrency(LData.FValue)^ := AValue;
end;

procedure TData.SetCardinal(const AKey: str; const AValue: Cardinal);
var
  LData: TData;
begin
  LData := Path(AKey);
  SetLength(LData.FValue, 4);
  PCardinal(LData.FValue)^ := AValue;
end;

procedure TData.SetD(const AKey: str; const AValue: Double);
var
  LData: TData;
begin
  LData := Path(AKey);
  SetLength(LData.FValue, SizeOf(Double));
  PDouble(LData.FValue)^ := AValue;
end;

procedure TData.SetDT(const AKey: str; const AValue: TDateTime);
var
  LData: TData;
begin
  LData := Path(AKey);
  SetLength(LData.FValue, SizeOf(TDateTime));
  PDateTime(LData.FValue)^ := AValue;
end;

procedure TData.SetI(const AKey: str; const AValue: integer);
var
  LData: TData;
begin
  LData := Path(AKey);
  SetLength(LData.FValue, SizeOf(int));
  PInteger(LData.FValue)^ := AValue;
end;

procedure TData.SetI64(const AKey: str; const AValue: Int64);
var
  LData: TData;
begin
  LData := Path(AKey);
  SetLength(LData.FValue, SizeOf(Int64));
  PInt64(LData.FValue)^ := AValue;
end;

procedure TData.SetS(const AKey, AValue: str);
var
  LLen: int;
  LData: TData;
begin
  LData := Path(AKey);
  LLen := length(AValue);
  SetLength(LData.FValue, LLen);
  if LLen > 0 then
    Move(Pstr(AValue)^, pbyte(LData.FValue)^, LLen);
end;

procedure TData.SetST(const AKey: str; const AValue: TStream);
var
  LData: TData;
begin
  LData := Path(AKey);
  SetLength(LData.FValue, AValue.size);
  AValue.Position := 0;
  AValue.Read(pbyte(LData.FValue)^, AValue.size);
  AValue.Position := 0;
end;

procedure TData.SetV(const AKey: str; const AValue: Variant);
var
  LPByte: pbyte;
  LLen: int;
  LData: TData;
begin
  LData := Path(AKey);
  LLen := VarArrayHighBound(AValue, 1) - VarArrayLowBound(AValue, 1) + 1;
  LPByte := VarArrayLock(AValue);
  try
    SetLength(LData.FValue, LLen);
    Move(LPByte^, pbyte(LData.FValue)^, LLen);
  finally
    VarArrayUnlock(AValue);
  end;
end;

procedure TData.SetWord(const AKey: str; const AValue: Word);
var
  LData: TData;
begin
  LData := Path(AKey);
  SetLength(LData.FValue, 2);
  PWord(LData.FValue)^ := AValue;
end;

function TData.ToBytes: TBytes;
var
  I, LLen, LPos: int;
begin
  SetLength(Result, GetByteCount);
  LPos := 0;
  for I := 0 to FList.Count - 1 do
  begin
    LLen := length(TData(FList[I]).FKey);
    Move(LLen, Result[LPos], SizeOf(int));
    LPos := LPos + SizeOf(int);
    Move(Pstr(TData(FList[I]).FKey)^, Result[LPos], LLen);
    LPos := LPos + LLen;
    LLen := length(TData(FList[I]).FValue);
    Move(LLen, Result[LPos], SizeOf(int));
    LPos := LPos + SizeOf(int);
    Move(pbyte(TData(FList[I]).FValue)^, Result[LPos], LLen);
    LPos := LPos + LLen;
  end;
end;

function TData.ToRaw: str;
var
  I, LLen, LPos: int;
begin
  SetLength(Result, GetByteCount);
  LPos := 1;
  for I := 0 to FList.Count - 1 do
  begin
    LLen := length(TData(FList[I]).FKey);
    Move(LLen, Result[LPos], SizeOf(int));
    LPos := LPos + SizeOf(int);
    Move(Pstr(TData(FList[I]).FKey)^, Result[LPos], LLen);
    LPos := LPos + LLen;
    LLen := length(TData(FList[I]).FValue);
    Move(LLen, Result[LPos], SizeOf(int));
    LPos := LPos + SizeOf(int);
    Move(pbyte(TData(FList[I]).FValue)^, Result[LPos], LLen);
    LPos := LPos + LLen;
  end;
end;

procedure TData.ToStream(AStream: TStream);
var
  I, LLen: int;
begin
  AStream.Position := 0;
  for I := 0 to FList.Count - 1 do
  begin
    LLen := length(TData(FList[I]).FKey);
    AStream.Write(LLen, SizeOf(int));
    AStream.Write(Pstr(TData(FList[I]).FKey)^, LLen);
    LLen := length(TData(FList[I]).FValue);
    AStream.Write(LLen, SizeOf(int));
    AStream.Write(pbyte(TData(FList[I]).FValue)^, LLen);
  end;
  AStream.Position := 0;
end;

{ TMemPool }

constructor TMemPool.Create(APoolSize: Integer);
begin
  FList := TList.Create;
  CS := TCriticalSection.Create;
  Self.FPoolSize := APoolSize;
  Self.Init;
end;

destructor TMemPool.Destroy;
begin
  FList.Clear;
  FreeAndNil(FList);
  FreeAndNil(CS);
  inherited Destroy;
end;

procedure TMemPool.Init;
begin
  while FList.Count < Self.FPoolSize do
    FList.Add(NewObject);
end;

function TMemPool.Lock: TMemoryStream;
begin
  CS.Enter;
  try
    if FList.Count > 0 then
    begin
      Result := TMemoryStream(FList.First);
      FList.Remove(Result);
    end
    else
    begin
      FList.Add(NewObject);
      Result := TMemoryStream(FList.First);
      FList.Remove(Result);
    end;
  finally
    cs.Leave;
  end;
end;

function TMemPool.NewObject: TMemoryStream;
begin
  Result := TMemoryStream.Create;
end;

procedure TMemPool.Unlock(AValue: TMemoryStream);
begin
  AValue.Clear;   //free memory
  FList.Add(AValue);
end;

initialization
  MemPool := TMemPool.Create(1000);

end.