Browse Source

auto commit

pull/19/MERGE
yitter 1 year ago
parent
commit
f57d9f1de6
18 changed files with 2315 additions and 2 deletions
  1. +70
    -0
      Delphi/README.md
  2. +5
    -0
      Delphi/source/.gitignore
  3. +3
    -0
      Delphi/source/BakClear.bat
  4. +16
    -0
      Delphi/source/Contract/uIIdGenerator.pas
  5. +13
    -0
      Delphi/source/Contract/uISnowWorker.pas
  6. +97
    -0
      Delphi/source/Contract/uIdGeneratorOptions.pas
  7. +61
    -0
      Delphi/source/Contract/uTOverCostActionArg.pas
  8. +404
    -0
      Delphi/source/Core/uSnowWorkerM1.pas
  9. +75
    -0
      Delphi/source/Core/uSnowWorkerM2.pas
  10. +91
    -0
      Delphi/source/Core/uSnowWorkerM3.pas
  11. +25
    -0
      Delphi/source/IdGenTest.dpr
  12. +987
    -0
      Delphi/source/IdGenTest.dproj
  13. BIN
      Delphi/source/IdGenTest.res
  14. +137
    -0
      Delphi/source/uDefaultIdGenerator.pas
  15. +80
    -0
      Delphi/source/uTest.dfm
  16. +197
    -0
      Delphi/source/uTest.pas
  17. +51
    -0
      Delphi/source/uYitIdHelper.pas
  18. +3
    -2
      README.md

+ 70
- 0
Delphi/README.md View File

@@ -0,0 +1,70 @@
# ❄ idgenerator-Delphi
## 编译环境、运行环境
Delphi XE10.3.3
## 调用示例(Delphi)
第1步,**全局**初始化(创建只执行一次):
```objectpascal
// 添加引用
uses uIdGeneratorOptions, uIIdGenerator, uDefaultIdGenerator, uYitIdHelper;
// 声明IdGeneratorOptions、YitIdHelper对象为全局变量
var
IdGeneratorOption: TIdGeneratorOptions;
YitIdHelper: TYitIdHelper;
// 创建并配置雪花算法参数:
begin
IdGeneratorOption := TIdGeneratorOptions.Create;
// 参数参考IdGeneratorOptions定义。
with IdGeneratorOptiondo
begin
//以下全部为默认参数
Method := 1;
// BaseTime := DateTime.Now.AddYears(-10);
WorkerId := 1;
WorkerIdBitLength := 6;
SeqBitLength := 6;
MaxSeqNumber := 0;
MinSeqNumber := 5;
TopOverCostCount := 2000;
DataCenterId := 0;
DataCenterIdBitLength := 0;
TimestampType := 0;
end;
YitIdHelper := TYitIdHelper.Create;
// 保存参数(务必调用,否则参数设置不生效):
YitIdHelper.SetIdGenerator(options);
// 以上过程只需全局一次,且应在生成Id之前完成。
end;
```
第2步,生成ID:
```objectpascal
// 初始化后,在任何需要生成Id的地方,调用以下方法:
var Id: Int64 := YitIdHelper.NextId();
```
第3步,释放内存(销毁只执行一次):
```objectpascal
YitIdHelper.Free;
IdGeneratorOption.Free;
```
## 代码贡献者
塵封追憶(Delphi-asdf, 82257695)

+ 5
- 0
Delphi/source/.gitignore View File

@@ -0,0 +1,5 @@
Win32/
*.exe
*.dproj.local
*.identcache
__*

+ 3
- 0
Delphi/source/BakClear.bat View File

@@ -0,0 +1,3 @@
DEL /S *.~*
DEL /S *.DCU
DEL /S *.DDP

+ 16
- 0
Delphi/source/Contract/uIIdGenerator.pas View File

@@ -0,0 +1,16 @@
unit uIIdGenerator;
interface
type
IIdGenerator = interface
['{C4E773E0-6E3E-410D-9F01-0826BA57BFF0}']
/// <summary>
/// 生成新的Int64型Id
/// </summary>
function NewLong(): Int64;
end;
implementation
end.

+ 13
- 0
Delphi/source/Contract/uISnowWorker.pas View File

@@ -0,0 +1,13 @@
unit uISnowWorker;
interface
type
ISnowWorker = interface
['{AB5DCE35-5745-417F-9217-9094CA651A8C}']
function NextId(): Int64;
end;
implementation
end.

+ 97
- 0
Delphi/source/Contract/uIdGeneratorOptions.pas View File

@@ -0,0 +1,97 @@
unit uIdGeneratorOptions;
interface
uses
System.DateUtils, System.SysUtils;
type
TIdGeneratorOptions = class
private
FMethod: SmallInt;
// FBaseTime: TDateTime;
FBaseTime: Int64;
FWorkerId: Word;
FWorkerIdBitLength: Byte;
FSeqBitLength: Byte;
FMaxSeqNumber: Integer;
FMinSeqNumber: Word;
FTopOverCostCount: Integer;
FDataCenterId: Cardinal;
FDataCenterIdBitLength: Byte;
FTimestampType: Byte;
public
/// <summary>
/// 雪花计算方法
/// (1-漂移算法|2-传统算法),默认1
/// </summary>
property Method: SmallInt read FMethod write FMethod default 1;
/// <summary>
/// 基础时间(UTC格式)
/// 不能超过当前系统时间
/// </summary>
// property BaseTime: TDateTime read FBaseTime write FBaseTime;
property BaseTime: Int64 read FBaseTime write FBaseTime;
/// <summary>
/// 机器码
/// 必须由外部设定,最大值 2^WorkerIdBitLength-1
/// </summary>
property WorkerId: Word read FWorkerId write FWorkerId default 0;
/// <summary>
/// 机器码位长
/// 默认值6,取值范围 [1, 15](要求:序列数位长+机器码位长不超过22)
/// </summary>
property WorkerIdBitLength: Byte read FWorkerIdBitLength write FWorkerIdBitLength default 6; // 10;
/// <summary>
/// 序列数位长
/// 默认值6,取值范围 [3, 21](要求:序列数位长+机器码位长不超过22)
/// </summary>
property SeqBitLength: Byte read FSeqBitLength write FSeqBitLength default 6; // 10;
/// <summary>
/// 最大序列数(含)
/// 设置范围 [MinSeqNumber, 2^SeqBitLength-1],默认值0,表示最大序列数取最大值(2^SeqBitLength-1])
/// </summary>
property MaxSeqNumber: Integer read FMaxSeqNumber write FMaxSeqNumber default 0;
/// <summary>
/// 最小序列数(含)
/// 默认值5,取值范围 [5, MaxSeqNumber],每毫秒的前5个序列数对应编号0-4是保留位,其中1-4是时间回拨相应预留位,0是手工新值预留位
/// </summary>
property MinSeqNumber: Word read FMinSeqNumber write FMinSeqNumber default 5;
/// <summary>
/// 最大漂移次数(含),
/// 默认2000,推荐范围500-10000(与计算能力有关)
/// </summary>
property TopOverCostCount: Integer read FTopOverCostCount write FTopOverCostCount default 2000;
/// <summary>
/// 数据中心ID(默认0)
/// </summary>
property DataCenterId: Cardinal read FDataCenterId write FDataCenterId default 0;
/// <summary>
/// 数据中心ID长度(默认0)
/// </summary>
property DataCenterIdBitLength: Byte read FDataCenterIdBitLength write FDataCenterIdBitLength default 0;
/// <summary>
/// 时间戳类型(0-毫秒,1-秒),默认0
/// </summary>
property TimestampType: Byte read FTimestampType write FTimestampType default 0;
constructor Create(); overload;
constructor Create(WorkerId: Word); overload;
end;
implementation
{ TIdGeneratorOptions }
constructor TIdGeneratorOptions.Create(WorkerId: Word);
begin
FBaseTime := 1582136402000; // EncodeDateTime(2020, 2, 20, 2, 20, 2, 20);
FWorkerId := WorkerId;
end;
constructor TIdGeneratorOptions.Create();
begin
FBaseTime := 1582136402000; // EncodeDateTime(2020, 2, 20, 2, 20, 2, 20);
end;
end.

+ 61
- 0
Delphi/source/Contract/uTOverCostActionArg.pas View File

@@ -0,0 +1,61 @@
unit uTOverCostActionArg;
interface
type
TOverCostActionArg = class
private
FActionType: Integer;
FTimeTick: Int64;
FWorkerId: Word;
FOverCostCountInOneTerm: Integer;
FGenCountInOneTerm: Integer;
FTermIndex: Integer;
public
/// <summary>
/// 事件类型
/// 1-开始,2-结束,8-漂移
/// </summary>
property ActionType: Integer read FActionType write FActionType default 0;
/// <summary>
/// 时间戳
/// </summary>
property TimeTick: Int64 read FTimeTick write FTimeTick;
/// <summary>
/// 机器码
/// </summary>
property WorkerId: Word read FWorkerId write FWorkerId;
/// <summary>
/// 漂移计算次数
/// </summary>
property OverCostCountInOneTerm: Integer read FOverCostCountInOneTerm write FOverCostCountInOneTerm default 0;
/// <summary>
/// 漂移期间生产ID个数
/// </summary>
property GenCountInOneTerm: Integer read FGenCountInOneTerm write FGenCountInOneTerm default 0;
/// <summary>
/// 漂移周期
/// </summary>
property TermIndex: Integer read FTermIndex write FTermIndex default 0;
constructor Create(const WorkerId: Word; const TimeTick: Int64; const ActionType: Integer = 0;
const OverCostCountInOneTerm: Integer = 0; const GenCountWhenOverCost: Integer = 0;
const Index: Integer = 0); overload;
end;
implementation
{ TOverCostActionArg }
constructor TOverCostActionArg.Create(const WorkerId: Word; const TimeTick: Int64; const ActionType: Integer;
const OverCostCountInOneTerm: Integer; const GenCountWhenOverCost: Integer; const Index: Integer);
begin
FWorkerId := WorkerId;
FTimeTick := TimeTick;
FActionType := ActionType;
FOverCostCountInOneTerm := OverCostCountInOneTerm;
FGenCountInOneTerm := GenCountWhenOverCost;
FTermIndex := Index;
end;
end.

+ 404
- 0
Delphi/source/Core/uSnowWorkerM1.pas View File

@@ -0,0 +1,404 @@
unit uSnowWorkerM1;
interface
uses
uISnowWorker, uIdGeneratorOptions, System.SyncObjs, uTOverCostActionArg, System.DateUtils, System.SysUtils;
/// <summary>
/// 雪花漂移算法
/// </summary>
type
TSnowWorkerM1 = class(TInterfacedObject, ISnowWorker)
private
// private static long _StartTimeTick = 0;
// private static long _BaseTimeTick = 0;
protected
SyncLock: TCriticalSection;
protected
// FBaseTime: TDateTime;
FBaseTime: Int64;
FWorkerId: Word;
FWorkerIdBitLength: Byte;
FSeqBitLength: Byte;
FMaxSeqNumber: Integer;
FMinSeqNumber: Word;
FTopOverCostCount: Integer;
//
FTimestampShift: Byte;
FCurrentSeqNumber: Word;
FLastTimeTick: Int64;
FTurnBackTimeTick: Int64;
FTurnBackIndex: Byte;
FIsOverCost: Boolean;
FOverCostCountInOneTerm: Integer;
//
FGenCountInOneTerm: Integer;
FTermIndex: Integer;
protected
/// <summary>
/// 基础时间
/// </summary>
// property BaseTime: TDateTime read FBaseTime write FBaseTime;
property BaseTime: Int64 read FBaseTime;
/// <summary>
/// 机器码
/// </summary>
property WorkerId: Word read FWorkerId default 0;
/// <summary>
/// 机器码位长
/// </summary>
property WorkerIdBitLength: Byte read FWorkerIdBitLength default 0;
/// <summary>
/// 自增序列数位长
/// </summary>
property SeqBitLength: Byte read FSeqBitLength default 0;
/// <summary>
/// 最大序列数(含)
/// </summary>
property MaxSeqNumber: Integer read FMaxSeqNumber default 0;
/// <summary>
/// 最小序列数(含)
/// </summary>
property MinSeqNumber: Word read FMinSeqNumber default 0;
/// <summary>
/// 最大漂移次数(含)
/// </summary>
property TopOverCostCount: Integer read FTopOverCostCount write FTopOverCostCount default 0;
//
property TimestampShift: Byte read FTimestampShift write FTimestampShift default 0;
//
property CurrentSeqNumber: Word read FCurrentSeqNumber write FCurrentSeqNumber;
property LastTimeTick: Int64 read FLastTimeTick write FLastTimeTick default 0; // -1L
property TurnBackTimeTick: Int64 read FTurnBackTimeTick write FTurnBackTimeTick default 0; // -1L;
property TurnBackIndex: Byte read FTurnBackIndex write FTurnBackIndex default 0;
property IsOverCost: Boolean read FIsOverCost write FIsOverCost default False;
property OverCostCountInOneTerm: Integer read FOverCostCountInOneTerm write FOverCostCountInOneTerm default 0;
{$IFDEF DEBUG}
property GenCountInOneTerm: Integer read FGenCountInOneTerm write FGenCountInOneTerm default 0;
property TermIndex: Integer read FTermIndex write FTermIndex default 0;
{$ENDIF}
protected
{$IFDEF DEBUG}
procedure DoGenIdAction(arg: TOverCostActionArg);
procedure BeginOverCostAction(UseTimeTick: Int64);
procedure EndOverCostAction(UseTimeTick: Int64);
procedure BeginTurnBackAction(UseTimeTick: Int64);
procedure EndTurnBackAction(UseTimeTick: Int64);
{$ENDIF}
//
function GetSecondTimeStamp(): Int64;
function GetMillisecondTimeStamp(): Int64;
//
function CalcId(UseTimeTick: Int64): Int64; virtual;
function CalcTurnBackId(UseTimeTick: Int64): Int64; virtual;
function NextOverCostId(): Int64;
function GetCurrentTimeTick(): Int64; virtual;
function GetNextTimeTick(): Int64;
public
// Action<OverCostActionArg> GenAction { get; set; }
function NextId(): Int64;
function NextNormalId(): Int64;
constructor Create(options: TIdGeneratorOptions); overload;
destructor Destroy(); override;
end;
implementation
{ TSnowWorkerM1 }
function TSnowWorkerM1.GetSecondTimeStamp(): Int64;
var
ST: TDateTime;
begin
ST := EncodeDateTime(1970, 1, 1, 0, 0, 0, 0);
Result := MilliSecondsBetween(Now(), ST) - 28800; // 8*60*60;
end;
function TSnowWorkerM1.GetMillisecondTimeStamp(): Int64;
var
ST: TDateTime;
begin
ST := EncodeDateTime(1970, 1, 1, 0, 0, 0, 0);
Result := MilliSecondsBetween(Now(), ST) - 28800000; // 8*60*60*1000;
end;
constructor TSnowWorkerM1.Create(options: TIdGeneratorOptions);
begin
SyncLock := TCriticalSection.Create;
// 1.BaseTime
if (options.BaseTime <> 0) then
FBaseTime := options.BaseTime;
// 2.WorkerIdBitLength
if (options.WorkerIdBitLength <> 0) then
begin
FWorkerIdBitLength := 6;
end
else
begin
FWorkerIdBitLength := options.WorkerIdBitLength;
end;
// 3.WorkerId
FWorkerId := options.WorkerId;
// 4.SeqBitLength
if (options.SeqBitLength = 0) then
begin
FSeqBitLength := 6;
end
else
begin
FSeqBitLength := options.SeqBitLength;
end;
// 5.MaxSeqNumber
if (MaxSeqNumber = 0) then
begin
FMaxSeqNumber := (1 shl SeqBitLength) - 1;
end
else
begin
FMaxSeqNumber := options.MaxSeqNumber;
end;
// 6.MinSeqNumber
FMinSeqNumber := options.MinSeqNumber;
// 7.Others
FTopOverCostCount := options.TopOverCostCount;
// if (TopOverCostCount = 0) then
// begin
// FTopOverCostCount := 2000;
// end;
FTimestampShift := Byte(WorkerIdBitLength + SeqBitLength);
FCurrentSeqNumber := options.MinSeqNumber;
// FBaseTimeTick = BaseTime.Ticks;
// FStartTimeTick = (long)(DateTime.UtcNow.Subtract(BaseTime).TotalMilliseconds) - Environment.TickCount;
end;
destructor TSnowWorkerM1.Destroy();
begin
SyncLock.Free;
inherited;
end;
{$IFDEF DEBUG}
procedure TSnowWorkerM1.DoGenIdAction(arg: TOverCostActionArg);
begin
// //return;
// Task.Run(() =>
// {
// GenAction(arg);
// });
end;
procedure TSnowWorkerM1.BeginOverCostAction(UseTimeTick: Int64);
begin
end;
procedure TSnowWorkerM1.EndOverCostAction(UseTimeTick: Int64);
begin
end;
procedure TSnowWorkerM1.BeginTurnBackAction(UseTimeTick: Int64);
begin
end;
procedure TSnowWorkerM1.EndTurnBackAction(UseTimeTick: Int64);
begin
end;
{$ENDIF}
function TSnowWorkerM1.NextOverCostId(): Int64;
var
CurrentTimeTick: Int64;
begin
CurrentTimeTick := GetCurrentTimeTick();
if (CurrentTimeTick > FLastTimeTick) then
begin
{$IFDEF DEBUG}
EndOverCostAction(CurrentTimeTick);
FGenCountInOneTerm := 0;
{$ENDIF}
FLastTimeTick := CurrentTimeTick;
FCurrentSeqNumber := FMinSeqNumber;
FIsOverCost := False;
FOverCostCountInOneTerm := 0;
Result := CalcId(FLastTimeTick);
Exit;
end;
if (FOverCostCountInOneTerm >= FTopOverCostCount) then
begin
{$IFDEF DEBUG}
EndOverCostAction(CurrentTimeTick);
FGenCountInOneTerm := 0;
{$ENDIF}
// TODO: 在漂移终止,等待时间对齐时,如果发生时间回拨较长,则此处可能等待较长时间。
// 可优化为:在漂移终止时增加时间回拨应对逻辑。(该情况发生概率低,暂不处理)
FLastTimeTick := GetNextTimeTick();
FCurrentSeqNumber := FMinSeqNumber;
FIsOverCost := False;
FOverCostCountInOneTerm := 0;
Result := CalcId(FLastTimeTick);
Exit;
end;
if (FCurrentSeqNumber > FMaxSeqNumber) then
begin
{$IFDEF DEBUG}
Inc(FGenCountInOneTerm);
{$ENDIF}
Inc(FLastTimeTick);
FCurrentSeqNumber := FMinSeqNumber;
FIsOverCost := True;
Inc(FOverCostCountInOneTerm);
Result := CalcId(FLastTimeTick);
Exit;
end;
{$IFDEF DEBUG}
Inc(FGenCountInOneTerm);
{$ENDIF}
Result := CalcId(FLastTimeTick);
end;
function TSnowWorkerM1.NextNormalId: Int64;
var
CurrentTimeTick: Int64;
begin
CurrentTimeTick := GetCurrentTimeTick();
if (CurrentTimeTick < FLastTimeTick) then
begin
if (FTurnBackTimeTick < 1) then
begin
FTurnBackTimeTick := FLastTimeTick - 1;
Inc(FTurnBackIndex);
// 每毫秒序列数的前5位是预留位,0用于手工新值,1-4是时间回拨次序
// 支持4次回拨次序(避免回拨重叠导致ID重复),可无限次回拨(次序循环使用)。
if (FTurnBackIndex > 4) then
begin
FTurnBackIndex := 1;
end;
{$IFDEF DEBUG}
BeginTurnBackAction(FTurnBackTimeTick);
{$ENDIF}
end;
// Sleep(1);
Result := CalcTurnBackId(FTurnBackTimeTick);
Exit;
end;
// 时间追平时,_TurnBackTimeTick清零
if (FTurnBackTimeTick > 0) then
begin
{$IFDEF DEBUG}
EndTurnBackAction(FTurnBackTimeTick);
{$ENDIF}
FTurnBackTimeTick := 0;
end;
if (CurrentTimeTick > FLastTimeTick) then
begin
FLastTimeTick := CurrentTimeTick;
FCurrentSeqNumber := FMinSeqNumber;
Result := CalcId(FLastTimeTick);
Exit;
end;
if (FCurrentSeqNumber > FMaxSeqNumber) then
begin
{$IFDEF DEBUG}
BeginOverCostAction(CurrentTimeTick);
Inc(FTermIndex);
FGenCountInOneTerm := 1;
{$ENDIF}
FOverCostCountInOneTerm := 1;
Inc(FLastTimeTick);
FCurrentSeqNumber := FMinSeqNumber;
FIsOverCost := True;
Result := CalcId(FLastTimeTick);
Exit;
end;
Result := CalcId(FLastTimeTick);
end;
function TSnowWorkerM1.CalcId(UseTimeTick: Int64): Int64;
begin
Result := ((UseTimeTick shl FTimestampShift) + (Int64(FWorkerId) shl FSeqBitLength) + Cardinal(FCurrentSeqNumber));
Inc(FCurrentSeqNumber);
end;
function TSnowWorkerM1.CalcTurnBackId(UseTimeTick: Int64): Int64;
begin
Result := ((UseTimeTick shl FTimestampShift) + (Int64(FWorkerId) shl FSeqBitLength) + FTurnBackIndex);
Dec(FTurnBackTimeTick);
end;
function TSnowWorkerM1.GetCurrentTimeTick(): Int64;
var
Millis: Int64;
begin
// Millis := DateTimeToUnix(Now(), False);
Millis := GetMillisecondTimeStamp();
Result := Millis - FBaseTime;
end;
function TSnowWorkerM1.GetNextTimeTick(): Int64;
var
TempTimeTicker: Int64;
begin
TempTimeTicker := GetCurrentTimeTick();
while (TempTimeTicker <= FLastTimeTick) do
begin
// Sleep(1);
TSpinWait.SpinUntil(
function(): Boolean
begin
Result := False;
end, 1);
TempTimeTicker := GetCurrentTimeTick();
end;
Result := TempTimeTicker;
end;
function TSnowWorkerM1.NextId(): Int64;
begin
SyncLock.Enter;
try
if FIsOverCost then
Result := NextOverCostId()
else
Result := NextNormalId();
finally
SyncLock.Leave;
end;
end;
end.

+ 75
- 0
Delphi/source/Core/uSnowWorkerM2.pas View File

@@ -0,0 +1,75 @@
unit uSnowWorkerM2;
interface
uses System.SysUtils, uSnowWorkerM1, uIdGeneratorOptions, System.SyncObjs;
/// <summary>
/// ³£¹æÑ©»¨Ëã·¨
/// </summary>
type
TSnowWorkerM2 = class(TSnowWorkerM1)
public
function NextId(): Int64;
constructor Create(options: TIdGeneratorOptions); overload;
end;
implementation
{ TSnowWorkerM2 }
function IncX(var x: Integer): Integer; inline;
begin
Result := x;
Inc(x);
end;
constructor TSnowWorkerM2.Create(options: TIdGeneratorOptions);
begin
inherited Create(options);
end;
function TSnowWorkerM2.NextId(): Int64;
var
CurrentTimeTick: Int64;
begin
SyncLock.Enter;
try
CurrentTimeTick := GetCurrentTimeTick();
if (FLastTimeTick = CurrentTimeTick) then
begin
// if (IncX(FCurrentSeqNumber) > FMaxSeqNumber) then
// begin
// FCurrentSeqNumber := FMinSeqNumber;
// CurrentTimeTick := GetNextTimeTick();
// end;
if ((FCurrentSeqNumber) > FMaxSeqNumber) then
begin
FCurrentSeqNumber := FMinSeqNumber;
CurrentTimeTick := GetNextTimeTick();
end
else
begin
Inc(FCurrentSeqNumber);
end;
end
else
begin
FCurrentSeqNumber := FMinSeqNumber;
end;
if (CurrentTimeTick < FLastTimeTick) then
begin
raise Exception.Create(Format('Time error for %d milliseconds', [FLastTimeTick - CurrentTimeTick]));
end;
FLastTimeTick := CurrentTimeTick;
Result := ((CurrentTimeTick shl FTimestampShift) + (Int64(FWorkerId) shl FSeqBitLength) +
Cardinal(FCurrentSeqNumber));
finally
SyncLock.Leave;
end;
end;
end.

+ 91
- 0
Delphi/source/Core/uSnowWorkerM3.pas View File

@@ -0,0 +1,91 @@
unit uSnowWorkerM3;
interface
uses System.SysUtils, System.DateUtils, uSnowWorkerM1, uIdGeneratorOptions, System.SyncObjs;
/// <summary>
/// 雪花漂移算法(支持数据中心ID和秒级时间戳)
/// </summary>
type
TSnowWorkerM3 = class(TSnowWorkerM1)
protected
FDataCenterId: Cardinal;
FDataCenterIdBitLength: Byte;
FTimestampType: Byte;
protected
/// <summary>
/// 数据中心ID(默认0)
/// </summary>
property DataCenterId: Cardinal read FDataCenterId default 0;
/// <summary>
/// 数据中心ID长度(默认0)
/// </summary>
property DataCenterIdBitLength: Byte read FDataCenterIdBitLength default 0;
/// <summary>
/// 时间戳类型(0-毫秒,1-秒),默认0
/// </summary>
property TimestampType: Byte read FTimestampType default 0;
protected
function CalcId(UseTimeTick: Int64): Int64; override;
function CalcTurnBackId(UseTimeTick: Int64): Int64; override;
function GetCurrentTimeTick(): Int64; override;
public
constructor Create(options: TIdGeneratorOptions); overload;
end;
implementation
{ TSnowWorkerM3 }
constructor TSnowWorkerM3.Create(options: TIdGeneratorOptions);
begin
// 秒级时间戳类型
FTimestampType := options.TimestampType;
// DataCenter相关
FDataCenterId := options.DataCenterId;
FDataCenterIdBitLength := options.DataCenterIdBitLength;
if (FTimestampType = 1) then
begin
FTopOverCostCount := 0;
end;
FTimestampShift := Byte(DataCenterIdBitLength + WorkerIdBitLength + SeqBitLength);
inherited Create(options);
end;
function TSnowWorkerM3.CalcId(UseTimeTick: Int64): Int64;
begin
Result := ((UseTimeTick shl FTimestampShift) + (Int64(DataCenterId) shl DataCenterIdBitLength) +
(Int64(WorkerId) shl SeqBitLength) + Int64(FCurrentSeqNumber));
Inc(FCurrentSeqNumber);
end;
function TSnowWorkerM3.CalcTurnBackId(UseTimeTick: Int64): Int64;
begin
Result := ((UseTimeTick shl FTimestampShift) + (Int64(DataCenterId) shl DataCenterIdBitLength) +
(Int64(WorkerId) shl SeqBitLength) + FTurnBackIndex);
Dec(FTurnBackTimeTick);
end;
function TSnowWorkerM3.GetCurrentTimeTick: Int64;
var
Millis: Int64;
begin
if (TimestampType = 0) then
begin
Millis := GetMillisecondTimeStamp();
Result := Millis - FBaseTime;
end
else
begin
Millis := GetSecondTimeStamp();
Result := Millis - FBaseTime;
end;
end;
end.

+ 25
- 0
Delphi/source/IdGenTest.dpr View File

@@ -0,0 +1,25 @@
program IdGenTest;
uses
Vcl.Forms,
uTest in 'uTest.pas' {fTest} ,
uISnowWorker in 'Contract\uISnowWorker.pas',
uIIdGenerator in 'Contract\uIIdGenerator.pas',
uTOverCostActionArg in 'Contract\uTOverCostActionArg.pas',
uIdGeneratorOptions in 'Contract\uIdGeneratorOptions.pas',
uSnowWorkerM1 in 'Core\uSnowWorkerM1.pas',
uSnowWorkerM2 in 'Core\uSnowWorkerM2.pas',
uSnowWorkerM3 in 'Core\uSnowWorkerM3.pas',
uDefaultIdGenerator in 'uDefaultIdGenerator.pas',
uYitIdHelper in 'uYitIdHelper.pas';
{$R *.res}
begin
Application.Initialize;
Application.MainFormOnTaskbar := True;
ReportMemoryLeaksOnShutdown := (DebugHook <> 0);
Application.CreateForm(TfTest, fTest);
Application.Run;
end.

+ 987
- 0
Delphi/source/IdGenTest.dproj View File

@@ -0,0 +1,987 @@
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<ProjectGuid>{9237743A-F2B2-49BE-941B-C151799790AF}</ProjectGuid>
<ProjectVersion>18.8</ProjectVersion>
<FrameworkType>VCL</FrameworkType>
<MainSource>IdGenTest.dpr</MainSource>
<Base>True</Base>
<Config Condition="'$(Config)'==''">Release</Config>
<Platform Condition="'$(Platform)'==''">Win32</Platform>
<TargetedPlatforms>1</TargetedPlatforms>
<AppType>Application</AppType>
</PropertyGroup>
<PropertyGroup Condition="'$(Config)'=='Base' or '$(Base)'!=''">
<Base>true</Base>
</PropertyGroup>
<PropertyGroup Condition="('$(Platform)'=='Win32' and '$(Base)'=='true') or '$(Base_Win32)'!=''">
<Base_Win32>true</Base_Win32>
<CfgParent>Base</CfgParent>
<Base>true</Base>
</PropertyGroup>
<PropertyGroup Condition="('$(Platform)'=='Win64' and '$(Base)'=='true') or '$(Base_Win64)'!=''">
<Base_Win64>true</Base_Win64>
<CfgParent>Base</CfgParent>
<Base>true</Base>
</PropertyGroup>
<PropertyGroup Condition="'$(Config)'=='Debug' or '$(Cfg_1)'!=''">
<Cfg_1>true</Cfg_1>
<CfgParent>Base</CfgParent>
<Base>true</Base>
</PropertyGroup>
<PropertyGroup Condition="('$(Platform)'=='Win32' and '$(Cfg_1)'=='true') or '$(Cfg_1_Win32)'!=''">
<Cfg_1_Win32>true</Cfg_1_Win32>
<CfgParent>Cfg_1</CfgParent>
<Cfg_1>true</Cfg_1>
<Base>true</Base>
</PropertyGroup>
<PropertyGroup Condition="'$(Config)'=='Release' or '$(Cfg_2)'!=''">
<Cfg_2>true</Cfg_2>
<CfgParent>Base</CfgParent>
<Base>true</Base>
</PropertyGroup>
<PropertyGroup Condition="('$(Platform)'=='Win32' and '$(Cfg_2)'=='true') or '$(Cfg_2_Win32)'!=''">
<Cfg_2_Win32>true</Cfg_2_Win32>
<CfgParent>Cfg_2</CfgParent>
<Cfg_2>true</Cfg_2>
<Base>true</Base>
</PropertyGroup>
<PropertyGroup Condition="'$(Base)'!=''">
<DCC_DcuOutput>.\$(Platform)\$(Config)</DCC_DcuOutput>
<DCC_ExeOutput>.\$(Platform)\$(Config)</DCC_ExeOutput>
<DCC_E>false</DCC_E>
<DCC_N>false</DCC_N>
<DCC_S>false</DCC_S>
<DCC_F>false</DCC_F>
<DCC_K>false</DCC_K>
<DCC_Namespace>System;Xml;Data;Datasnap;Web;Soap;Vcl;Vcl.Imaging;Vcl.Touch;Vcl.Samples;Vcl.Shell;$(DCC_Namespace)</DCC_Namespace>
<Icon_MainIcon>$(BDS)\bin\delphi_PROJECTICON.ico</Icon_MainIcon>
<UWP_DelphiLogo44>$(BDS)\bin\Artwork\Windows\UWP\delphi_UwpDefault_44.png</UWP_DelphiLogo44>
<UWP_DelphiLogo150>$(BDS)\bin\Artwork\Windows\UWP\delphi_UwpDefault_150.png</UWP_DelphiLogo150>
<SanitizedProjectName>IdGenTest</SanitizedProjectName>
</PropertyGroup>
<PropertyGroup Condition="'$(Base_Win32)'!=''">
<DCC_UsePackage>DBXSqliteDriver;dxFlowChartRS26;dxPSdxMapControlLnkRS26;DBXDb2Driver;vclactnband;dxBarRS26;vclFireDAC;dxFireDACEMFRS26;tethering;KRCommon;dxSpreadSheetInplaceRichEditRS26;FireDACADSDriver;dxRichEditCoreRS26;dxPSdxSpreadSheetLnkRS26;FireDACMSSQLDriver;vcltouch;vcldb;svn;dxPSTeeChartRS26;dxGDIPlusRS26;dxPSdxFCLnkRS26;vclib;frxTee26;dxCloudServiceLibraryRS26;dxPSLnksRS26;FireDACDBXDriver;cxGridRS26;dxPsPrVwAdvRS26;dxPDFViewerRS26;vclx;dxPScxTLLnkRS26;RESTBackendComponents;VCLRESTComponents;fsTee26;vclie;bindengine;CloudService;dxmdsRS26;FireDACMySQLDriver;fsIBX26;frx26;dxdborRS26;DataSnapClient;dxFireDACServerModeRS26;bindcompdbx;fsFD26;DBXSybaseASEDriver;IndyIPServer;cxPivotGridRS26;IndySystem;frxDBX26;fsADO26;CnPack_D103R;cxTreeListdxBarPopupMenuRS26;dsnapcon;cxTreeListRS26;dxPScxPivotGridLnkRS26;cxSchedulerRibbonStyleEventEditorRS26;dxPSCoreRS26;inetwinsockets;FireDACMSAccDriver;FireDACInfxDriver;fmxFireDAC;vclimg;dxSpreadSheetRS26;dxBarExtItemsRS26;dxPSdxGaugeControlLnkRS26;emshosting;DBXOdbcDriver;FireDACTDataDriver;FMXTee;dxdbtrRS26;dxRichEditControlCoreRS26;soaprtl;DbxCommonDriver;dxFlowChartAdvancedCustomizeFormRS26;dxDockingRS26;KRWeb;xmlrtl;DataSnapNativeClient;soapmidas;fmxobj;cxLibraryRS26;rtl;emsserverresource;DbxClientDriver;DBXSybaseASADriver;dxPScxSchedulerLnkRS26;dxSpreadSheetConditionalFormattingDialogsRS26;appanalytics;dxRibbonCustomizationFormRS26;cxSchedulerGridRS26;KRFile;IndyIPClient;bindcompvcl;dxFlowChartLayoutsRS26;TeeUI;dxADOEMFRS26;VclSmp;FireDACODBCDriver;dxRibbonRS26;DataSnapIndy10ServerTransport;dxPScxCommonRS26;dxRichEditDocumentModelRS26;DataSnapProviderClient;FireDACMongoDBDriver;dxFlowChartDesignerRS26;dxPScxGridLnkRS26;dxSpreadSheetCoreRS26;DataSnapServerMidas;RESTComponents;DBXInterBaseDriver;sgcWebSocketsD10_3;dxPScxExtCommonRS26;emsclientfiredac;DataSnapFireDAC;svnui;frxFD26;DBXMSSQLDriver;dxRichEditControlRS26;DatasnapConnectorsFreePascal;dxGaugeControlRS26;dxorgcRS26;dxPScxVGridLnkRS26;bindcompfmx;DBXOracleDriver;inetdb;dxBarDBNavRS26;dxDBXServerModeRS26;SPCOMM;RaizeComponentsVcl;FmxTeeUI;emsedge;RaizeComponentsVclDb;FireDACIBDriver;fmx;fmxdae;dxServerModeRS26;dxWizardControlRS26;dxTabbedMDIRS26;fs26;dxEMFRS26;dbexpress;IndyCore;dxComnRS26;KRGraphics;frxIntIO26;dsnap;DataSnapCommon;emsclient;FireDACCommon;frxcs26;DataSnapConnectors;cxSchedulerTreeBrowserRS26;dxADOServerModeRS26;soapserver;cxPivotGridOLAPRS26;cxVerticalGridRS26;dxtrmdRS26;FireDACOracleDriver;DBXMySQLDriver;cxSchedulerRS26;cxSchedulerWebServiceStorageRS26;dxPSdxLCLnkRS26;DBXFirebirdDriver;FireDACCommonODBC;FireDACCommonDriver;dxMapControlRS26;frxIntIOIndy26;inet;dxSpellCheckerRS26;IndyIPCommon;dxSpreadSheetCoreConditionalFormattingDialogsRS26;vcl;dxPSdxDBOCLnkRS26;EhLib260;frxDB26;FireDACDb2Driver;dxSpreadSheetReportDesignerRS26;dxPScxPCProdRS26;dxNavBarRS26;fsDB26;dxCoreRS26;cxExportRS26;TeeDB;FireDAC;dxHttpIndyRequestRS26;dxPSPrVwRibbonRS26;frxe26;FireDACSqliteDriver;FireDACPgDriver;ibmonitor;FireDACASADriver;dxPSRichEditControlLnkRS26;cxPivotGridChartRS26;frxIBX26;dxPSDBTeeChartRS26;ibxpress;Tee;DataSnapServer;ibxbindings;dxPSdxDBTVLnkRS26;FireDACDSDriver;vclwinx;frxADO26;dxTileControlRS26;KRAutomation;dxSkinsCoreRS26;CustomIPTransport;vcldsnap;bindcomp;dxPSdxOCLnkRS26;DBXInformixDriver;dbxcds;adortl;dxSpreadSheetCoreDialogsRS26;dxBarExtDBItemsRS26;dsnapxml;dbrtl;IndyProtocols;inetdbxpress;dxPSdxPDFViewerLnkRS26;dxRichEditInplaceRS26;fmxase;$(DCC_UsePackage)</DCC_UsePackage>
<DCC_Namespace>Winapi;System.Win;Data.Win;Datasnap.Win;Web.Win;Soap.Win;Xml.Win;Bde;$(DCC_Namespace)</DCC_Namespace>
<BT_BuildType>Debug</BT_BuildType>
<VerInfo_IncludeVerInfo>true</VerInfo_IncludeVerInfo>
<VerInfo_Keys>CompanyName=;FileDescription=$(MSBuildProjectName);FileVersion=1.0.0.0;InternalName=;LegalCopyright=;LegalTrademarks=;OriginalFilename=;ProgramID=com.embarcadero.$(MSBuildProjectName);ProductName=$(MSBuildProjectName);ProductVersion=1.0.0.0;Comments=</VerInfo_Keys>
<VerInfo_Locale>1033</VerInfo_Locale>
<Manifest_File>$(BDS)\bin\default_app.manifest</Manifest_File>
<DCC_ExeOutput>.\</DCC_ExeOutput>
</PropertyGroup>
<PropertyGroup Condition="'$(Base_Win64)'!=''">
<DCC_UsePackage>DBXSqliteDriver;dxFlowChartRS26;dxPSdxMapControlLnkRS26;DBXDb2Driver;vclactnband;dxBarRS26;vclFireDAC;dxFireDACEMFRS26;tethering;dxSpreadSheetInplaceRichEditRS26;FireDACADSDriver;dxRichEditCoreRS26;dxPSdxSpreadSheetLnkRS26;FireDACMSSQLDriver;vcltouch;vcldb;dxPSTeeChartRS26;dxGDIPlusRS26;dxPSdxFCLnkRS26;vclib;dxCloudServiceLibraryRS26;dxPSLnksRS26;FireDACDBXDriver;cxGridRS26;dxPsPrVwAdvRS26;dxPDFViewerRS26;vclx;dxPScxTLLnkRS26;RESTBackendComponents;VCLRESTComponents;vclie;bindengine;CloudService;dxmdsRS26;FireDACMySQLDriver;dxdborRS26;DataSnapClient;dxFireDACServerModeRS26;bindcompdbx;DBXSybaseASEDriver;IndyIPServer;cxPivotGridRS26;IndySystem;cxTreeListdxBarPopupMenuRS26;dsnapcon;cxTreeListRS26;dxPScxPivotGridLnkRS26;cxSchedulerRibbonStyleEventEditorRS26;dxPSCoreRS26;FireDACMSAccDriver;FireDACInfxDriver;fmxFireDAC;vclimg;dxSpreadSheetRS26;dxBarExtItemsRS26;dxPSdxGaugeControlLnkRS26;emshosting;DBXOdbcDriver;FireDACTDataDriver;FMXTee;dxdbtrRS26;dxRichEditControlCoreRS26;soaprtl;DbxCommonDriver;dxFlowChartAdvancedCustomizeFormRS26;dxDockingRS26;xmlrtl;DataSnapNativeClient;soapmidas;fmxobj;cxLibraryRS26;rtl;emsserverresource;DbxClientDriver;DBXSybaseASADriver;dxPScxSchedulerLnkRS26;dxSpreadSheetConditionalFormattingDialogsRS26;appanalytics;dxRibbonCustomizationFormRS26;cxSchedulerGridRS26;IndyIPClient;bindcompvcl;dxFlowChartLayoutsRS26;TeeUI;dxADOEMFRS26;VclSmp;FireDACODBCDriver;dxRibbonRS26;DataSnapIndy10ServerTransport;dxPScxCommonRS26;dxRichEditDocumentModelRS26;DataSnapProviderClient;FireDACMongoDBDriver;dxFlowChartDesignerRS26;dxPScxGridLnkRS26;dxSpreadSheetCoreRS26;DataSnapServerMidas;RESTComponents;DBXInterBaseDriver;sgcWebSocketsD10_3;dxPScxExtCommonRS26;emsclientfiredac;DataSnapFireDAC;DBXMSSQLDriver;dxRichEditControlRS26;DatasnapConnectorsFreePascal;dxGaugeControlRS26;dxorgcRS26;dxPScxVGridLnkRS26;bindcompfmx;DBXOracleDriver;inetdb;dxBarDBNavRS26;dxDBXServerModeRS26;RaizeComponentsVcl;FmxTeeUI;emsedge;RaizeComponentsVclDb;FireDACIBDriver;fmx;fmxdae;dxServerModeRS26;dxWizardControlRS26;dxTabbedMDIRS26;dxEMFRS26;dbexpress;IndyCore;dxComnRS26;dsnap;DataSnapCommon;emsclient;FireDACCommon;DataSnapConnectors;cxSchedulerTreeBrowserRS26;dxADOServerModeRS26;soapserver;cxPivotGridOLAPRS26;cxVerticalGridRS26;dxtrmdRS26;FireDACOracleDriver;DBXMySQLDriver;cxSchedulerRS26;cxSchedulerWebServiceStorageRS26;dxPSdxLCLnkRS26;DBXFirebirdDriver;FireDACCommonODBC;FireDACCommonDriver;dxMapControlRS26;inet;dxSpellCheckerRS26;IndyIPCommon;dxSpreadSheetCoreConditionalFormattingDialogsRS26;vcl;dxPSdxDBOCLnkRS26;EhLib260;FireDACDb2Driver;dxSpreadSheetReportDesignerRS26;dxPScxPCProdRS26;dxNavBarRS26;dxCoreRS26;cxExportRS26;TeeDB;FireDAC;dxHttpIndyRequestRS26;dxPSPrVwRibbonRS26;FireDACSqliteDriver;FireDACPgDriver;ibmonitor;FireDACASADriver;dxPSRichEditControlLnkRS26;cxPivotGridChartRS26;dxPSDBTeeChartRS26;ibxpress;Tee;DataSnapServer;ibxbindings;dxPSdxDBTVLnkRS26;FireDACDSDriver;vclwinx;dxTileControlRS26;dxSkinsCoreRS26;CustomIPTransport;vcldsnap;bindcomp;dxPSdxOCLnkRS26;DBXInformixDriver;dbxcds;adortl;dxSpreadSheetCoreDialogsRS26;dxBarExtDBItemsRS26;dsnapxml;dbrtl;IndyProtocols;inetdbxpress;dxPSdxPDFViewerLnkRS26;dxRichEditInplaceRS26;fmxase;$(DCC_UsePackage)</DCC_UsePackage>
</PropertyGroup>
<PropertyGroup Condition="'$(Cfg_1)'!=''">
<DCC_Define>DEBUG;$(DCC_Define)</DCC_Define>
<DCC_DebugDCUs>true</DCC_DebugDCUs>
<DCC_Optimize>false</DCC_Optimize>
<DCC_GenerateStackFrames>true</DCC_GenerateStackFrames>
<DCC_DebugInfoInExe>true</DCC_DebugInfoInExe>
<DCC_RemoteDebug>true</DCC_RemoteDebug>
</PropertyGroup>
<PropertyGroup Condition="'$(Cfg_1_Win32)'!=''">
<DCC_RemoteDebug>false</DCC_RemoteDebug>
<AppEnableRuntimeThemes>true</AppEnableRuntimeThemes>
<AppDPIAwarenessMode>PerMonitorV2</AppDPIAwarenessMode>
</PropertyGroup>
<PropertyGroup Condition="'$(Cfg_2)'!=''">
<DCC_LocalDebugSymbols>false</DCC_LocalDebugSymbols>
<DCC_Define>RELEASE;$(DCC_Define)</DCC_Define>
<DCC_SymbolReferenceInfo>0</DCC_SymbolReferenceInfo>
<DCC_DebugInformation>0</DCC_DebugInformation>
</PropertyGroup>
<PropertyGroup Condition="'$(Cfg_2_Win32)'!=''">
<AppEnableRuntimeThemes>true</AppEnableRuntimeThemes>
<AppDPIAwarenessMode>PerMonitorV2</AppDPIAwarenessMode>
<VerInfo_IncludeVerInfo>true</VerInfo_IncludeVerInfo>
<VerInfo_Locale>1033</VerInfo_Locale>
</PropertyGroup>
<ItemGroup>
<DelphiCompile Include="$(MainSource)">
<MainSource>MainSource</MainSource>
</DelphiCompile>
<DCCReference Include="uTest.pas">
<Form>fTest</Form>
</DCCReference>
<DCCReference Include="Contract\uISnowWorker.pas"/>
<DCCReference Include="Contract\uIIdGenerator.pas"/>
<DCCReference Include="Contract\uTOverCostActionArg.pas"/>
<DCCReference Include="Contract\uIdGeneratorOptions.pas"/>
<DCCReference Include="Core\uSnowWorkerM1.pas"/>
<DCCReference Include="Core\uSnowWorkerM2.pas"/>
<DCCReference Include="Core\uSnowWorkerM3.pas"/>
<DCCReference Include="uDefaultIdGenerator.pas"/>
<DCCReference Include="uYitIdHelper.pas">
<Form>$R *.res</Form>
</DCCReference>
<BuildConfiguration Include="Release">
<Key>Cfg_2</Key>
<CfgParent>Base</CfgParent>
</BuildConfiguration>
<BuildConfiguration Include="Base">
<Key>Base</Key>
</BuildConfiguration>
<BuildConfiguration Include="Debug">
<Key>Cfg_1</Key>
<CfgParent>Base</CfgParent>
</BuildConfiguration>
</ItemGroup>
<ProjectExtensions>
<Borland.Personality>Delphi.Personality.12</Borland.Personality>
<Borland.ProjectType>Application</Borland.ProjectType>
<BorlandProject>
<Delphi.Personality>
<Source>
<Source Name="MainSource">IdGenTest.dpr</Source>
</Source>
<Excluded_Packages>
<Excluded_Packages Name="$(BDSBIN)\dcloffice2k260.bpl">Microsoft Office 2000 Sample Automation Server Wrapper Components</Excluded_Packages>
<Excluded_Packages Name="$(BDSBIN)\dclofficexp260.bpl">Microsoft Office XP Sample Automation Server Wrapper Components</Excluded_Packages>
</Excluded_Packages>
</Delphi.Personality>
<Deployment Version="3">
<DeployFile LocalName="Win32\Debug\IdGenTest.exe" Configuration="Debug" Class="ProjectOutput">
<Platform Name="Win32">
<RemoteName>IdGenTest.exe</RemoteName>
<Overwrite>true</Overwrite>
</Platform>
</DeployFile>
<DeployClass Name="AdditionalDebugSymbols">
<Platform Name="iOSSimulator">
<Operation>1</Operation>
</Platform>
<Platform Name="OSX32">
<RemoteDir>Contents\MacOS</RemoteDir>
<Operation>1</Operation>
</Platform>
<Platform Name="Win32">
<Operation>0</Operation>
</Platform>
</DeployClass>
<DeployClass Name="AndroidClassesDexFile">
<Platform Name="Android">
<RemoteDir>classes</RemoteDir>
<Operation>1</Operation>
</Platform>
<Platform Name="Android64">
<RemoteDir>classes</RemoteDir>
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="AndroidFileProvider">
<Platform Name="Android">
<RemoteDir>res\xml</RemoteDir>
<Operation>1</Operation>
</Platform>
<Platform Name="Android64">
<RemoteDir>res\xml</RemoteDir>
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="AndroidGDBServer">
<Platform Name="Android">
<RemoteDir>library\lib\armeabi-v7a</RemoteDir>
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="AndroidLibnativeArmeabiFile">
<Platform Name="Android">
<RemoteDir>library\lib\armeabi</RemoteDir>
<Operation>1</Operation>
</Platform>
<Platform Name="Android64">
<RemoteDir>library\lib\armeabi</RemoteDir>
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="AndroidLibnativeArmeabiv7aFile">
<Platform Name="Android64">
<RemoteDir>library\lib\armeabi-v7a</RemoteDir>
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="AndroidLibnativeMipsFile">
<Platform Name="Android">
<RemoteDir>library\lib\mips</RemoteDir>
<Operation>1</Operation>
</Platform>
<Platform Name="Android64">
<RemoteDir>library\lib\mips</RemoteDir>
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="AndroidServiceOutput">
<Platform Name="Android">
<RemoteDir>library\lib\armeabi-v7a</RemoteDir>
<Operation>1</Operation>
</Platform>
<Platform Name="Android64">
<RemoteDir>library\lib\arm64-v8a</RemoteDir>
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="AndroidServiceOutput_Android32">
<Platform Name="Android64">
<RemoteDir>library\lib\armeabi-v7a</RemoteDir>
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="AndroidSplashImageDef">
<Platform Name="Android">
<RemoteDir>res\drawable</RemoteDir>
<Operation>1</Operation>
</Platform>
<Platform Name="Android64">
<RemoteDir>res\drawable</RemoteDir>
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="AndroidSplashStyles">
<Platform Name="Android">
<RemoteDir>res\values</RemoteDir>
<Operation>1</Operation>
</Platform>
<Platform Name="Android64">
<RemoteDir>res\values</RemoteDir>
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="AndroidSplashStylesV21">
<Platform Name="Android">
<RemoteDir>res\values-v21</RemoteDir>
<Operation>1</Operation>
</Platform>
<Platform Name="Android64">
<RemoteDir>res\values-v21</RemoteDir>
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="Android_Colors">
<Platform Name="Android">
<RemoteDir>res\values</RemoteDir>
<Operation>1</Operation>
</Platform>
<Platform Name="Android64">
<RemoteDir>res\values</RemoteDir>
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="Android_DefaultAppIcon">
<Platform Name="Android">
<RemoteDir>res\drawable</RemoteDir>
<Operation>1</Operation>
</Platform>
<Platform Name="Android64">
<RemoteDir>res\drawable</RemoteDir>
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="Android_LauncherIcon144">
<Platform Name="Android">
<RemoteDir>res\drawable-xxhdpi</RemoteDir>
<Operation>1</Operation>
</Platform>
<Platform Name="Android64">
<RemoteDir>res\drawable-xxhdpi</RemoteDir>
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="Android_LauncherIcon36">
<Platform Name="Android">
<RemoteDir>res\drawable-ldpi</RemoteDir>
<Operation>1</Operation>
</Platform>
<Platform Name="Android64">
<RemoteDir>res\drawable-ldpi</RemoteDir>
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="Android_LauncherIcon48">
<Platform Name="Android">
<RemoteDir>res\drawable-mdpi</RemoteDir>
<Operation>1</Operation>
</Platform>
<Platform Name="Android64">
<RemoteDir>res\drawable-mdpi</RemoteDir>
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="Android_LauncherIcon72">
<Platform Name="Android">
<RemoteDir>res\drawable-hdpi</RemoteDir>
<Operation>1</Operation>
</Platform>
<Platform Name="Android64">
<RemoteDir>res\drawable-hdpi</RemoteDir>
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="Android_LauncherIcon96">
<Platform Name="Android">
<RemoteDir>res\drawable-xhdpi</RemoteDir>
<Operation>1</Operation>
</Platform>
<Platform Name="Android64">
<RemoteDir>res\drawable-xhdpi</RemoteDir>
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="Android_NotificationIcon24">
<Platform Name="Android">
<RemoteDir>res\drawable-mdpi</RemoteDir>
<Operation>1</Operation>
</Platform>
<Platform Name="Android64">
<RemoteDir>res\drawable-mdpi</RemoteDir>
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="Android_NotificationIcon36">
<Platform Name="Android">
<RemoteDir>res\drawable-hdpi</RemoteDir>
<Operation>1</Operation>
</Platform>
<Platform Name="Android64">
<RemoteDir>res\drawable-hdpi</RemoteDir>
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="Android_NotificationIcon48">
<Platform Name="Android">
<RemoteDir>res\drawable-xhdpi</RemoteDir>
<Operation>1</Operation>
</Platform>
<Platform Name="Android64">
<RemoteDir>res\drawable-xhdpi</RemoteDir>
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="Android_NotificationIcon72">
<Platform Name="Android">
<RemoteDir>res\drawable-xxhdpi</RemoteDir>
<Operation>1</Operation>
</Platform>
<Platform Name="Android64">
<RemoteDir>res\drawable-xxhdpi</RemoteDir>
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="Android_NotificationIcon96">
<Platform Name="Android">
<RemoteDir>res\drawable-xxxhdpi</RemoteDir>
<Operation>1</Operation>
</Platform>
<Platform Name="Android64">
<RemoteDir>res\drawable-xxxhdpi</RemoteDir>
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="Android_SplashImage426">
<Platform Name="Android">
<RemoteDir>res\drawable-small</RemoteDir>
<Operation>1</Operation>
</Platform>
<Platform Name="Android64">
<RemoteDir>res\drawable-small</RemoteDir>
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="Android_SplashImage470">
<Platform Name="Android">
<RemoteDir>res\drawable-normal</RemoteDir>
<Operation>1</Operation>
</Platform>
<Platform Name="Android64">
<RemoteDir>res\drawable-normal</RemoteDir>
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="Android_SplashImage640">
<Platform Name="Android">
<RemoteDir>res\drawable-large</RemoteDir>
<Operation>1</Operation>
</Platform>
<Platform Name="Android64">
<RemoteDir>res\drawable-large</RemoteDir>
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="Android_SplashImage960">
<Platform Name="Android">
<RemoteDir>res\drawable-xlarge</RemoteDir>
<Operation>1</Operation>
</Platform>
<Platform Name="Android64">
<RemoteDir>res\drawable-xlarge</RemoteDir>
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="Android_Strings">
<Platform Name="Android">
<RemoteDir>res\values</RemoteDir>
<Operation>1</Operation>
</Platform>
<Platform Name="Android64">
<RemoteDir>res\values</RemoteDir>
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="DebugSymbols">
<Platform Name="iOSSimulator">
<Operation>1</Operation>
</Platform>
<Platform Name="OSX32">
<RemoteDir>Contents\MacOS</RemoteDir>
<Operation>1</Operation>
</Platform>
<Platform Name="Win32">
<Operation>0</Operation>
</Platform>
</DeployClass>
<DeployClass Name="DependencyFramework">
<Platform Name="OSX32">
<RemoteDir>Contents\MacOS</RemoteDir>
<Operation>1</Operation>
<Extensions>.framework</Extensions>
</Platform>
<Platform Name="OSX64">
<RemoteDir>Contents\MacOS</RemoteDir>
<Operation>1</Operation>
<Extensions>.framework</Extensions>
</Platform>
<Platform Name="Win32">
<Operation>0</Operation>
</Platform>
</DeployClass>
<DeployClass Name="DependencyModule">
<Platform Name="iOSDevice32">
<Operation>1</Operation>
<Extensions>.dylib</Extensions>
</Platform>
<Platform Name="iOSDevice64">
<Operation>1</Operation>
<Extensions>.dylib</Extensions>
</Platform>
<Platform Name="iOSSimulator">
<Operation>1</Operation>
<Extensions>.dylib</Extensions>
</Platform>
<Platform Name="OSX32">
<RemoteDir>Contents\MacOS</RemoteDir>
<Operation>1</Operation>
<Extensions>.dylib</Extensions>
</Platform>
<Platform Name="OSX64">
<RemoteDir>Contents\MacOS</RemoteDir>
<Operation>1</Operation>
<Extensions>.dylib</Extensions>
</Platform>
<Platform Name="Win32">
<Operation>0</Operation>
<Extensions>.dll;.bpl</Extensions>
</Platform>
</DeployClass>
<DeployClass Required="true" Name="DependencyPackage">
<Platform Name="iOSDevice32">
<Operation>1</Operation>
<Extensions>.dylib</Extensions>
</Platform>
<Platform Name="iOSDevice64">
<Operation>1</Operation>
<Extensions>.dylib</Extensions>
</Platform>
<Platform Name="iOSSimulator">
<Operation>1</Operation>
<Extensions>.dylib</Extensions>
</Platform>
<Platform Name="OSX32">
<RemoteDir>Contents\MacOS</RemoteDir>
<Operation>1</Operation>
<Extensions>.dylib</Extensions>
</Platform>
<Platform Name="OSX64">
<RemoteDir>Contents\MacOS</RemoteDir>
<Operation>1</Operation>
<Extensions>.dylib</Extensions>
</Platform>
<Platform Name="Win32">
<Operation>0</Operation>
<Extensions>.bpl</Extensions>
</Platform>
</DeployClass>
<DeployClass Name="File">
<Platform Name="Android">
<Operation>0</Operation>
</Platform>
<Platform Name="Android64">
<Operation>0</Operation>
</Platform>
<Platform Name="iOSDevice32">
<Operation>0</Operation>
</Platform>
<Platform Name="iOSDevice64">
<Operation>0</Operation>
</Platform>
<Platform Name="iOSSimulator">
<Operation>0</Operation>
</Platform>
<Platform Name="OSX32">
<RemoteDir>Contents\Resources\StartUp\</RemoteDir>
<Operation>0</Operation>
</Platform>
<Platform Name="OSX64">
<RemoteDir>Contents\Resources\StartUp\</RemoteDir>
<Operation>0</Operation>
</Platform>
<Platform Name="Win32">
<Operation>0</Operation>
</Platform>
</DeployClass>
<DeployClass Name="iPad_Launch1024x768">
<Platform Name="iOSDevice32">
<Operation>1</Operation>
</Platform>
<Platform Name="iOSDevice64">
<Operation>1</Operation>
</Platform>
<Platform Name="iOSSimulator">
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="iPad_Launch1536x2048">
<Platform Name="iOSDevice32">
<Operation>1</Operation>
</Platform>
<Platform Name="iOSDevice64">
<Operation>1</Operation>
</Platform>
<Platform Name="iOSSimulator">
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="iPad_Launch1668">
<Platform Name="iOSDevice32">
<Operation>1</Operation>
</Platform>
<Platform Name="iOSDevice64">
<Operation>1</Operation>
</Platform>
<Platform Name="iOSSimulator">
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="iPad_Launch1668x2388">
<Platform Name="iOSDevice32">
<Operation>1</Operation>
</Platform>
<Platform Name="iOSDevice64">
<Operation>1</Operation>
</Platform>
<Platform Name="iOSSimulator">
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="iPad_Launch2048x1536">
<Platform Name="iOSDevice32">
<Operation>1</Operation>
</Platform>
<Platform Name="iOSDevice64">
<Operation>1</Operation>
</Platform>
<Platform Name="iOSSimulator">
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="iPad_Launch2048x2732">
<Platform Name="iOSDevice32">
<Operation>1</Operation>
</Platform>
<Platform Name="iOSDevice64">
<Operation>1</Operation>
</Platform>
<Platform Name="iOSSimulator">
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="iPad_Launch2224">
<Platform Name="iOSDevice32">
<Operation>1</Operation>
</Platform>
<Platform Name="iOSDevice64">
<Operation>1</Operation>
</Platform>
<Platform Name="iOSSimulator">
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="iPad_Launch2388x1668">
<Platform Name="iOSDevice32">
<Operation>1</Operation>
</Platform>
<Platform Name="iOSDevice64">
<Operation>1</Operation>
</Platform>
<Platform Name="iOSSimulator">
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="iPad_Launch2732x2048">
<Platform Name="iOSDevice32">
<Operation>1</Operation>
</Platform>
<Platform Name="iOSDevice64">
<Operation>1</Operation>
</Platform>
<Platform Name="iOSSimulator">
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="iPad_Launch768x1024">
<Platform Name="iOSDevice32">
<Operation>1</Operation>
</Platform>
<Platform Name="iOSDevice64">
<Operation>1</Operation>
</Platform>
<Platform Name="iOSSimulator">
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="iPhone_Launch1125">
<Platform Name="iOSDevice32">
<Operation>1</Operation>
</Platform>
<Platform Name="iOSDevice64">
<Operation>1</Operation>
</Platform>
<Platform Name="iOSSimulator">
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="iPhone_Launch1136x640">
<Platform Name="iOSDevice32">
<Operation>1</Operation>
</Platform>
<Platform Name="iOSDevice64">
<Operation>1</Operation>
</Platform>
<Platform Name="iOSSimulator">
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="iPhone_Launch1242">
<Platform Name="iOSDevice32">
<Operation>1</Operation>
</Platform>
<Platform Name="iOSDevice64">
<Operation>1</Operation>
</Platform>
<Platform Name="iOSSimulator">
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="iPhone_Launch1242x2688">
<Platform Name="iOSDevice32">
<Operation>1</Operation>
</Platform>
<Platform Name="iOSDevice64">
<Operation>1</Operation>
</Platform>
<Platform Name="iOSSimulator">
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="iPhone_Launch1334">
<Platform Name="iOSDevice32">
<Operation>1</Operation>
</Platform>
<Platform Name="iOSDevice64">
<Operation>1</Operation>
</Platform>
<Platform Name="iOSSimulator">
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="iPhone_Launch1792">
<Platform Name="iOSDevice32">
<Operation>1</Operation>
</Platform>
<Platform Name="iOSDevice64">
<Operation>1</Operation>
</Platform>
<Platform Name="iOSSimulator">
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="iPhone_Launch2208">
<Platform Name="iOSDevice32">
<Operation>1</Operation>
</Platform>
<Platform Name="iOSDevice64">
<Operation>1</Operation>
</Platform>
<Platform Name="iOSSimulator">
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="iPhone_Launch2436">
<Platform Name="iOSDevice32">
<Operation>1</Operation>
</Platform>
<Platform Name="iOSDevice64">
<Operation>1</Operation>
</Platform>
<Platform Name="iOSSimulator">
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="iPhone_Launch2688x1242">
<Platform Name="iOSDevice32">
<Operation>1</Operation>
</Platform>
<Platform Name="iOSDevice64">
<Operation>1</Operation>
</Platform>
<Platform Name="iOSSimulator">
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="iPhone_Launch320">
<Platform Name="iOSDevice32">
<Operation>1</Operation>
</Platform>
<Platform Name="iOSDevice64">
<Operation>1</Operation>
</Platform>
<Platform Name="iOSSimulator">
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="iPhone_Launch640">
<Platform Name="iOSDevice32">
<Operation>1</Operation>
</Platform>
<Platform Name="iOSDevice64">
<Operation>1</Operation>
</Platform>
<Platform Name="iOSSimulator">
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="iPhone_Launch640x1136">
<Platform Name="iOSDevice32">
<Operation>1</Operation>
</Platform>
<Platform Name="iOSDevice64">
<Operation>1</Operation>
</Platform>
<Platform Name="iOSSimulator">
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="iPhone_Launch750">
<Platform Name="iOSDevice32">
<Operation>1</Operation>
</Platform>
<Platform Name="iOSDevice64">
<Operation>1</Operation>
</Platform>
<Platform Name="iOSSimulator">
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="iPhone_Launch828">
<Platform Name="iOSDevice32">
<Operation>1</Operation>
</Platform>
<Platform Name="iOSDevice64">
<Operation>1</Operation>
</Platform>
<Platform Name="iOSSimulator">
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="ProjectAndroidManifest">
<Platform Name="Android">
<Operation>1</Operation>
</Platform>
<Platform Name="Android64">
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="ProjectiOSDeviceDebug">
<Platform Name="iOSDevice32">
<RemoteDir>..\$(PROJECTNAME).app.dSYM\Contents\Resources\DWARF</RemoteDir>
<Operation>1</Operation>
</Platform>
<Platform Name="iOSDevice64">
<RemoteDir>..\$(PROJECTNAME).app.dSYM\Contents\Resources\DWARF</RemoteDir>
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="ProjectiOSDeviceResourceRules">
<Platform Name="iOSDevice32">
<Operation>1</Operation>
</Platform>
<Platform Name="iOSDevice64">
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="ProjectiOSEntitlements">
<Platform Name="iOSDevice32">
<RemoteDir>..\</RemoteDir>
<Operation>1</Operation>
</Platform>
<Platform Name="iOSDevice64">
<RemoteDir>..\</RemoteDir>
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="ProjectiOSInfoPList">
<Platform Name="iOSDevice32">
<Operation>1</Operation>
</Platform>
<Platform Name="iOSDevice64">
<Operation>1</Operation>
</Platform>
<Platform Name="iOSSimulator">
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="ProjectiOSResource">
<Platform Name="iOSDevice32">
<Operation>1</Operation>
</Platform>
<Platform Name="iOSDevice64">
<Operation>1</Operation>
</Platform>
<Platform Name="iOSSimulator">
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="ProjectOSXDebug">
<Platform Name="OSX64">
<RemoteDir>..\$(PROJECTNAME).app.dSYM\Contents\Resources\DWARF</RemoteDir>
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="ProjectOSXEntitlements">
<Platform Name="OSX32">
<RemoteDir>..\</RemoteDir>
<Operation>1</Operation>
</Platform>
<Platform Name="OSX64">
<RemoteDir>..\</RemoteDir>
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="ProjectOSXInfoPList">
<Platform Name="OSX32">
<RemoteDir>Contents</RemoteDir>
<Operation>1</Operation>
</Platform>
<Platform Name="OSX64">
<RemoteDir>Contents</RemoteDir>
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="ProjectOSXResource">
<Platform Name="OSX32">
<RemoteDir>Contents\Resources</RemoteDir>
<Operation>1</Operation>
</Platform>
<Platform Name="OSX64">
<RemoteDir>Contents\Resources</RemoteDir>
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Required="true" Name="ProjectOutput">
<Platform Name="Android">
<RemoteDir>library\lib\armeabi-v7a</RemoteDir>
<Operation>1</Operation>
</Platform>
<Platform Name="Android64">
<RemoteDir>library\lib\arm64-v8a</RemoteDir>
<Operation>1</Operation>
</Platform>
<Platform Name="iOSDevice32">
<Operation>1</Operation>
</Platform>
<Platform Name="iOSDevice64">
<Operation>1</Operation>
</Platform>
<Platform Name="iOSSimulator">
<Operation>1</Operation>
</Platform>
<Platform Name="Linux64">
<Operation>1</Operation>
</Platform>
<Platform Name="OSX32">
<RemoteDir>Contents\MacOS</RemoteDir>
<Operation>1</Operation>
</Platform>
<Platform Name="OSX64">
<RemoteDir>Contents\MacOS</RemoteDir>
<Operation>1</Operation>
</Platform>
<Platform Name="Win32">
<Operation>0</Operation>
</Platform>
</DeployClass>
<DeployClass Name="ProjectOutput_Android32">
<Platform Name="Android64">
<RemoteDir>library\lib\armeabi-v7a</RemoteDir>
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="ProjectUWPManifest">
<Platform Name="Win32">
<Operation>1</Operation>
</Platform>
<Platform Name="Win64">
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="UWP_DelphiLogo150">
<Platform Name="Win32">
<RemoteDir>Assets</RemoteDir>
<Operation>1</Operation>
</Platform>
<Platform Name="Win64">
<RemoteDir>Assets</RemoteDir>
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="UWP_DelphiLogo44">
<Platform Name="Win32">
<RemoteDir>Assets</RemoteDir>
<Operation>1</Operation>
</Platform>
<Platform Name="Win64">
<RemoteDir>Assets</RemoteDir>
<Operation>1</Operation>
</Platform>
</DeployClass>
<ProjectRoot Platform="iOSDevice64" Name="$(PROJECTNAME).app"/>
<ProjectRoot Platform="Win64" Name="$(PROJECTNAME)"/>
<ProjectRoot Platform="iOSDevice32" Name="$(PROJECTNAME).app"/>
<ProjectRoot Platform="Linux64" Name="$(PROJECTNAME)"/>
<ProjectRoot Platform="Win32" Name="$(PROJECTNAME)"/>
<ProjectRoot Platform="OSX32" Name="$(PROJECTNAME).app"/>
<ProjectRoot Platform="Android" Name="$(PROJECTNAME)"/>
<ProjectRoot Platform="OSX64" Name="$(PROJECTNAME).app"/>
<ProjectRoot Platform="iOSSimulator" Name="$(PROJECTNAME).app"/>
<ProjectRoot Platform="Android64" Name="$(PROJECTNAME)"/>
</Deployment>
<Platforms>
<Platform value="Win32">True</Platform>
<Platform value="Win64">False</Platform>
</Platforms>
</BorlandProject>
<ProjectFileVersion>12</ProjectFileVersion>
</ProjectExtensions>
<Import Project="$(BDS)\Bin\CodeGear.Delphi.Targets" Condition="Exists('$(BDS)\Bin\CodeGear.Delphi.Targets')"/>
<Import Project="$(APPDATA)\Embarcadero\$(BDSAPPDATABASEDIR)\$(PRODUCTVERSION)\UserTools.proj" Condition="Exists('$(APPDATA)\Embarcadero\$(BDSAPPDATABASEDIR)\$(PRODUCTVERSION)\UserTools.proj')"/>
<Import Project="$(MSBuildProjectName).deployproj" Condition="Exists('$(MSBuildProjectName).deployproj')"/>
</Project>

BIN
Delphi/source/IdGenTest.res View File


+ 137
- 0
Delphi/source/uDefaultIdGenerator.pas View File

@@ -0,0 +1,137 @@
unit uDefaultIdGenerator;
interface
uses
uIIdGenerator, uISnowWorker, uIdGeneratorOptions, System.DateUtils, System.SysUtils;
type
TDefaultIdGenerator = class(TInterfacedObject, IIdGenerator)
private
SnowWorker: ISnowWorker;
public
constructor Create(options: TIdGeneratorOptions); overload;
function NewLong(): Int64;
end;
implementation
uses
uSnowWorkerM1, uSnowWorkerM2, uSnowWorkerM3;
{ TDefaultIdGenerator }
function GetMillisecondTimeStamp(ET: TDateTime): Int64;
var
ST: TDateTime;
begin
ST := EncodeDateTime(1970, 1, 1, 0, 0, 0, 0);
Result := MilliSecondsBetween(ET, ST) - 28800000; // 8*60*60*1000;
end;
constructor TDefaultIdGenerator.Create(options: TIdGeneratorOptions);
var
MaxLength, MaxWorkerIdNumber, MaxDataCenterIdNumber, MaxSeqNumber: Integer;
begin
if (options = nil) then
begin
raise Exception.Create('options error.');
end;
// 1.BaseTime
if (options.BaseTime < GetMillisecondTimeStamp(IncYear(Now(), -50))) or
(options.BaseTime > GetMillisecondTimeStamp(Now())) then
begin
raise Exception.Create('BaseTime error.');
end;
// 2.WorkerIdBitLength
if (options.TimestampType = 0) then
MaxLength := 22
else
MaxLength := 31; // (秒级时间戳时放大到31位)
if (options.WorkerIdBitLength <= 0) then
begin
raise Exception.Create('WorkerIdBitLength error.(range:[1, 21])');
end;
if (options.DataCenterIdBitLength + options.WorkerIdBitLength + options.SeqBitLength > MaxLength) then
begin
raise Exception.Create('error:DataCenterIdBitLength + WorkerIdBitLength + SeqBitLength <= ' + IntToStr(MaxLength));
end;
// 3.WorkerId
MaxWorkerIdNumber := (1 shl options.WorkerIdBitLength) - 1;
if (MaxWorkerIdNumber = 0) then
begin
MaxWorkerIdNumber := 63;
end;
if ((options.WorkerId < 0) or (options.WorkerId > MaxWorkerIdNumber)) then
begin
raise Exception.Create('WorkerId error. (range:[0, ' + IntToStr(MaxWorkerIdNumber) + ']');
end;
MaxDataCenterIdNumber := (1 shl options.DataCenterIdBitLength) - 1;
if (options.DataCenterId < 0) or (options.DataCenterId > MaxDataCenterIdNumber) then
begin
raise Exception.Create('DataCenterId error. (range:[0, ' + IntToStr(MaxDataCenterIdNumber) + ']');
end;
// 4.SeqBitLength
if ((options.SeqBitLength < 2) or (options.SeqBitLength > 21)) then
begin
raise Exception.Create('SeqBitLength error. (range:[2, 21])');
end;
// 5.MaxSeqNumber
MaxSeqNumber := (1 shl options.SeqBitLength) - 1;
if (MaxSeqNumber = 0) then
begin
MaxSeqNumber := 63;
end;
if ((options.MaxSeqNumber < 0) or (options.MaxSeqNumber > MaxSeqNumber)) then
begin
raise Exception.Create('MaxSeqNumber error. (range:[1, ' + IntToStr(MaxSeqNumber) + ']');
end;
// 6.MinSeqNumber
if ((options.MinSeqNumber < 5) or (options.MinSeqNumber > MaxSeqNumber)) then
begin
raise Exception.Create('MinSeqNumber error. (range:[5, ' + IntToStr(MaxSeqNumber) + ']');
end;
// 7.TopOverCostCount
if ((options.TopOverCostCount < 0) or (options.TopOverCostCount > 10000)) then
begin
raise Exception.Create('TopOverCostCount error. (range:[0, 10000]');
end;
case (options.Method) of
2:
begin
SnowWorker := TSnowWorkerM2.Create(options);
end;
else
begin
if ((options.DataCenterIdBitLength = 0) and (options.TimestampType = 0)) then
begin
SnowWorker := TSnowWorkerM1.Create(options);
end
else
begin
SnowWorker := TSnowWorkerM3.Create(options);
end;
end;
end;
if (options.Method <> 2) then
begin
Sleep(500);
end;
end;
function TDefaultIdGenerator.NewLong(): Int64;
begin
Result := SnowWorker.NextId();
end;
end.

+ 80
- 0
Delphi/source/uTest.dfm View File

@@ -0,0 +1,80 @@
object fTest: TfTest
Left = 0
Top = 0
Caption = #38634#33457#31639#27861#27979#35797
ClientHeight = 509
ClientWidth = 668
Color = clBtnFace
Font.Charset = ANSI_CHARSET
Font.Color = clWindowText
Font.Height = -15
Font.Name = 'Microsoft YaHei UI'
Font.Style = []
OldCreateOrder = False
Position = poDesktopCenter
OnClose = FormClose
OnCreate = FormCreate
PixelsPerInch = 96
TextHeight = 20
object mmo1: TMemo
Left = 0
Top = 100
Width = 668
Height = 409
Align = alClient
ReadOnly = True
ScrollBars = ssVertical
TabOrder = 1
end
object Panel1: TPanel
Left = 0
Top = 0
Width = 668
Height = 100
Align = alTop
Caption = 'Panel1'
ShowCaption = False
TabOrder = 0
object Button1: TButton
Left = 32
Top = 62
Width = 90
Height = 30
Caption = #29983#25104'100'#20010
TabOrder = 1
OnClick = Button1Click
end
object btnTimeStamp: TButton
Left = 568
Top = 62
Width = 90
Height = 30
Caption = #27979#35797#26102#38388#25139
TabOrder = 3
OnClick = btnTimeStampClick
end
object Button2: TButton
Left = 168
Top = 62
Width = 90
Height = 30
Caption = '500W'#26102#38388
TabOrder = 2
OnClick = Button2Click
end
object rgSelect: TRadioGroup
Left = 1
Top = 1
Width = 666
Height = 55
Align = alTop
Caption = #38634#33457#31639#27861
Columns = 3
ItemIndex = 0
Items.Strings = (
#28418#31227#31639#27861
#20256#32479#31639#27861)
TabOrder = 0
end
end
end

+ 197
- 0
Delphi/source/uTest.pas View File

@@ -0,0 +1,197 @@
unit uTest;
interface
uses
Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics, System.DateUtils,
Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.ComCtrls, Vcl.StdCtrls, Vcl.ExtCtrls, uIdGeneratorOptions, uIIdGenerator,
uDefaultIdGenerator, uYitIdHelper;
type
TfTest = class(TForm)
mmo1: TMemo;
Panel1: TPanel;
Button1: TButton;
btnTimeStamp: TButton;
Button2: TButton;
rgSelect: TRadioGroup;
procedure Button1Click(Sender: TObject);
procedure btnTimeStampClick(Sender: TObject);
procedure Button2Click(Sender: TObject);
procedure FormCreate(Sender: TObject);
procedure FormClose(Sender: TObject; var Action: TCloseAction);
private
{ Private declarations }
IdGeneratorOption: TIdGeneratorOptions;
YitIdHelper: TYitIdHelper;
public
{ Public declarations }
end;
var
fTest: TfTest;
implementation
{$R *.dfm}
function GetMillisecondTimeStamp(): Int64;
var
ST: TDateTime;
begin
ST := EncodeDateTime(1970, 1, 1, 0, 0, 0, 0);
Result := MilliSecondsBetween(Now(), ST) - 28800000; // 8*60*60*1000;
end;
procedure TfTest.btnTimeStampClick(Sender: TObject);
const
T1 = 28800000;
var
SysTime: TSystemTime;
Time1, Time2: TDateTime;
T2, T3: Int64;
begin
// 秒级
// mmo1.Lines.Add(IntToStr(DateTimeToUnix(EncodeDateTime(2020, 2, 20, 2, 20, 2, 20), False)));
// mmo1.Lines.Add(IntToStr(DateTimeToUnix(EncodeDateTime(2020, 2, 20, 2, 20, 2, 20), True)));
// mmo1.Lines.Add(FormatDateTime('yyyy-MM-dd HH:mm:ss.zzz',
// UnixToDateTime(DateTimeToUnix(EncodeDateTime(2020, 2, 20, 2, 20, 2, 20), False), False)));
mmo1.Lines.Add('处理时区后转为UTC时间:' + IntToStr(DateTimeToUnix(Now(), False)));
mmo1.Lines.Add('直接取UTC时间:' + IntToStr(DateTimeToUnix(Now(), True)));
// mmo1.Lines.Add(FormatDateTime('yyyy-MM-dd HH:mm:ss.zzz', UnixToDateTime(DateTimeToUnix(Now(), False), False)));
// mmo1.Lines.Add(FormatDateTime('yyyy-MM-dd HH:mm:ss.zzz', UnixToDateTime(DateTimeToUnix(Now(), True), True)));
// 毫秒级
Time2 := EncodeDateTime(1970, 1, 1, 0, 0, 0, 0);
// 未处理时区
GetLocalTime(SysTime);
Time1 := SystemTimeToDateTime(SysTime);
T2 := MilliSecondsBetween(Time1, Time2);
T3 := T2 - T1;
mmo1.Lines.Add('LocalTime:' + IntToStr(T3));
// 处理了时区
GetSystemTime(SysTime);
Time1 := SystemTimeToDateTime(SysTime);
T2 := MilliSecondsBetween(Time1, Time2);
T3 := T2 - T1;
mmo1.Lines.Add('SystemTime:' + IntToStr(T3));
// 未处理时区
Time1 := Now();
T2 := MilliSecondsBetween(Time1, Time2);
T3 := T2 - T1;
mmo1.Lines.Add('Now:' + IntToStr(T3));
end;
procedure TfTest.Button1Click(Sender: TObject);
var
options: TIdGeneratorOptions;
IdGen: IIdGenerator;
i, j: Integer;
begin
// 使用方式一:直接使用
options := TIdGeneratorOptions.Create;
try
with options do
begin
Method := rgSelect.ItemIndex + 1;
// BaseTime := DateTime.Now.AddYears(-10);
WorkerId := 2;
WorkerIdBitLength := 6;
SeqBitLength := 6;
MaxSeqNumber := 0;
MinSeqNumber := 5;
TopOverCostCount := 2000;
DataCenterId := 0;
DataCenterIdBitLength := 0;
TimestampType := 0;
end;
IdGen := TDefaultIdGenerator.Create(options);
j := 100;
Screen.Cursor := crHourGlass;
mmo1.Lines.BeginUpdate();
try
for i := 1 to j do
begin
mmo1.Lines.Add(FormatFloat('000', i) + ':' + IntToStr(IdGen.NewLong()));
end;
mmo1.Perform(WM_VSCROLL, SB_BOTTOM, 0)
finally
mmo1.Lines.EndUpdate();
Screen.Cursor := crDefault;
end;
finally
options.Free;
end;
end;
procedure TfTest.Button2Click(Sender: TObject);
const
Total = 5000000;
var
i: Integer;
Id: Int64;
ST, ET, Elapse: Cardinal;
begin
Screen.Cursor := crHourGlass;
try
ST := GetTickCount();
for i := 1 to Total do
begin
Id := YitIdHelper.NextId();
end;
ET := GetTickCount();
finally
Screen.Cursor := crDefault;
end;
Elapse := ET - ST;
mmo1.Lines.Add(Format('生成500万个时间:%d毫秒,平均每秒%d个。', [Elapse, Trunc((Total / Elapse) * 1000)]));
end;
procedure TfTest.FormClose(Sender: TObject; var Action: TCloseAction);
begin
YitIdHelper.Free;
IdGeneratorOption.Free;
end;
procedure TfTest.FormCreate(Sender: TObject);
begin
IdGeneratorOption := TIdGeneratorOptions.Create;
// 默认参数
with IdGeneratorOption do
begin
Method := rgSelect.ItemIndex + 1;
// BaseTime := DateTime.Now.AddYears(-10);
WorkerId := 2;
WorkerIdBitLength := 6;
SeqBitLength := 6;
MaxSeqNumber := 0;
MinSeqNumber := 5;
TopOverCostCount := 2000;
DataCenterId := 0;
DataCenterIdBitLength := 0;
TimestampType := 0;
end;
// 使用方式二:封装类使用
YitIdHelper := TYitIdHelper.Create;
YitIdHelper.SetIdGenerator(IdGeneratorOption);
end;
end.

+ 51
- 0
Delphi/source/uYitIdHelper.pas View File

@@ -0,0 +1,51 @@
unit uYitIdHelper;
interface
uses System.SysUtils, uIIdGenerator, uIdGeneratorOptions;
type
TYitIdHelper = class
private
IdGenInstance: IIdGenerator;
public
function GetIdGenInstance(): IIdGenerator;
/// <summary>
/// 设置参数,建议程序初始化时执行一次
/// </summary>
/// <param name="options"></param>
procedure SetIdGenerator(options: TIdGeneratorOptions);
/// <summary>
/// 生成新的Id
/// 调用本方法前,请确保调用了 SetIdGenerator 方法做初始化。
/// </summary>
/// <returns></returns>
function NextId(): Int64;
end;
implementation
uses
uDefaultIdGenerator;
{ TYitIdHelper }
function TYitIdHelper.GetIdGenInstance: IIdGenerator;
begin
Result := IdGenInstance;
end;
procedure TYitIdHelper.SetIdGenerator(options: TIdGeneratorOptions);
begin
IdGenInstance := TDefaultIdGenerator.Create(options);
end;
function TYitIdHelper.NextId(): Int64;
begin
if (IdGenInstance = nil) then
raise Exception.Create('Please initialize Yitter.IdGeneratorOptions first.');
Result := IdGenInstance.NewLong();
end;
end.

+ 3
- 2
README.md View File

@@ -250,6 +250,7 @@ extern GoInt32 Validate(GoInt32 workerId);
| 🌲 Python | [查看示例][10] |
| 🌲 C | [查看示例][5] |
| 🌲 C (PHP扩展) | [查看示例][7] |
| 🌲 Pascal | [查看示例][6] |
| 🌲 JavaScript | [查看示例][8] |
| 🌲 TypeScript | [查看示例][9] |
| 🌲 V | [查看示例][6] |
@@ -278,7 +279,7 @@ QQ群:646049993
[3]: https://github.com/yitter/idgenerator/tree/master/Go
[4]: https://github.com/yitter/idgenerator/tree/master/Rust
[5]: https://github.com/yitter/idgenerator/tree/master/C
[6]: https://github.com/yitter/idgenerator/tree/master/zzz-OtherLanguages/V
[6]: https://github.com/yitter/idgenerator/tree/master/Pascal
[7]: https://github.com/yitter/idgenerator/tree/master/PHP
[8]: https://github.com/yitter/IdGenerator/tree/master/JavaScript
[9]: https://github.com/yitter/IdGenerator/tree/master/TypeScript
@@ -289,7 +290,7 @@ QQ群:646049993
[31]: https://github.com/yitter/idgenerator/tree/master/Go
[41]: https://github.com/yitter/idgenerator/tree/master/Rust
[51]: https://github.com/yitter/idgenerator/tree/master/C
[61]: https://github.com/yitter/idgenerator/tree/master/zzz-OtherLanguages/V
[61]: https://github.com/yitter/idgenerator/tree/master/Pascal
[71]: https://github.com/yitter/idgenerator/tree/master/PHP
[72]: https://github.com/yitter/idgenerator/tree/master/zzz-OtherLanguages/D


Loading…
Cancel
Save