diff --git a/Delphi/README.md b/Delphi/README.md
new file mode 100644
index 0000000..20eecc4
--- /dev/null
+++ b/Delphi/README.md
@@ -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)
+
+
diff --git a/Delphi/source/.gitignore b/Delphi/source/.gitignore
new file mode 100644
index 0000000..63788ae
--- /dev/null
+++ b/Delphi/source/.gitignore
@@ -0,0 +1,5 @@
+Win32/
+*.exe
+*.dproj.local
+*.identcache
+__*
diff --git a/Delphi/source/BakClear.bat b/Delphi/source/BakClear.bat
new file mode 100644
index 0000000..2e652cb
--- /dev/null
+++ b/Delphi/source/BakClear.bat
@@ -0,0 +1,3 @@
+DEL /S *.~*
+DEL /S *.DCU
+DEL /S *.DDP
\ No newline at end of file
diff --git a/Delphi/source/Contract/uIIdGenerator.pas b/Delphi/source/Contract/uIIdGenerator.pas
new file mode 100644
index 0000000..aa76c69
--- /dev/null
+++ b/Delphi/source/Contract/uIIdGenerator.pas
@@ -0,0 +1,16 @@
+unit uIIdGenerator;
+
+interface
+
+type
+ IIdGenerator = interface
+ ['{C4E773E0-6E3E-410D-9F01-0826BA57BFF0}']
+ ///
+ /// µInt64Id
+ ///
+ function NewLong(): Int64;
+ end;
+
+implementation
+
+end.
diff --git a/Delphi/source/Contract/uISnowWorker.pas b/Delphi/source/Contract/uISnowWorker.pas
new file mode 100644
index 0000000..66d4b5a
--- /dev/null
+++ b/Delphi/source/Contract/uISnowWorker.pas
@@ -0,0 +1,13 @@
+unit uISnowWorker;
+
+interface
+
+type
+ ISnowWorker = interface
+ ['{AB5DCE35-5745-417F-9217-9094CA651A8C}']
+ function NextId(): Int64;
+ end;
+
+implementation
+
+end.
diff --git a/Delphi/source/Contract/uIdGeneratorOptions.pas b/Delphi/source/Contract/uIdGeneratorOptions.pas
new file mode 100644
index 0000000..901c04f
--- /dev/null
+++ b/Delphi/source/Contract/uIdGeneratorOptions.pas
@@ -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
+ ///
+ /// ѩ㷽
+ /// 1-Ư㷨|2-ͳ㷨Ĭ1
+ ///
+ property Method: SmallInt read FMethod write FMethod default 1;
+ ///
+ /// ʱ䣨UTCʽ
+ /// ܳǰϵͳʱ
+ ///
+ // property BaseTime: TDateTime read FBaseTime write FBaseTime;
+ property BaseTime: Int64 read FBaseTime write FBaseTime;
+ ///
+ ///
+ /// ⲿ趨ֵ 2^WorkerIdBitLength-1
+ ///
+ property WorkerId: Word read FWorkerId write FWorkerId default 0;
+ ///
+ /// λ
+ /// Ĭֵ6ȡֵΧ [1, 15]Ҫλ+λ22
+ ///
+ property WorkerIdBitLength: Byte read FWorkerIdBitLength write FWorkerIdBitLength default 6; // 10;
+ ///
+ /// λ
+ /// Ĭֵ6ȡֵΧ [3, 21]Ҫλ+λ22
+ ///
+ property SeqBitLength: Byte read FSeqBitLength write FSeqBitLength default 6; // 10;
+ ///
+ ///
+ /// ÷Χ [MinSeqNumber, 2^SeqBitLength-1]Ĭֵ0ʾȡֵ2^SeqBitLength-1]
+ ///
+ property MaxSeqNumber: Integer read FMaxSeqNumber write FMaxSeqNumber default 0;
+ ///
+ /// С
+ /// Ĭֵ5ȡֵΧ [5, MaxSeqNumber]ÿǰ5Ӧ0-4DZλ1-4ʱزӦԤλ0ֵֹԤλ
+ ///
+ property MinSeqNumber: Word read FMinSeqNumber write FMinSeqNumber default 5;
+ ///
+ /// Ưƴ
+ /// Ĭ2000ƼΧ500-10000йأ
+ ///
+ property TopOverCostCount: Integer read FTopOverCostCount write FTopOverCostCount default 2000;
+ ///
+ /// IDĬ0
+ ///
+ property DataCenterId: Cardinal read FDataCenterId write FDataCenterId default 0;
+ ///
+ /// IDȣĬ0
+ ///
+ property DataCenterIdBitLength: Byte read FDataCenterIdBitLength write FDataCenterIdBitLength default 0;
+ ///
+ /// ʱͣ0-룬1-룩Ĭ0
+ ///
+ 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.
diff --git a/Delphi/source/Contract/uTOverCostActionArg.pas b/Delphi/source/Contract/uTOverCostActionArg.pas
new file mode 100644
index 0000000..d21ba2c
--- /dev/null
+++ b/Delphi/source/Contract/uTOverCostActionArg.pas
@@ -0,0 +1,61 @@
+unit uTOverCostActionArg;
+
+interface
+
+type
+ TOverCostActionArg = class
+ private
+ FActionType: Integer;
+ FTimeTick: Int64;
+ FWorkerId: Word;
+ FOverCostCountInOneTerm: Integer;
+ FGenCountInOneTerm: Integer;
+ FTermIndex: Integer;
+ public
+ ///
+ /// ¼
+ /// 1-ʼ2-8-Ư
+ ///
+ property ActionType: Integer read FActionType write FActionType default 0;
+ ///
+ /// ʱ
+ ///
+ property TimeTick: Int64 read FTimeTick write FTimeTick;
+ ///
+ ///
+ ///
+ property WorkerId: Word read FWorkerId write FWorkerId;
+ ///
+ /// ƯƼ
+ ///
+ property OverCostCountInOneTerm: Integer read FOverCostCountInOneTerm write FOverCostCountInOneTerm default 0;
+ ///
+ /// ƯڼID
+ ///
+ property GenCountInOneTerm: Integer read FGenCountInOneTerm write FGenCountInOneTerm default 0;
+ ///
+ /// Ư
+ ///
+ 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.
diff --git a/Delphi/source/Core/uSnowWorkerM1.pas b/Delphi/source/Core/uSnowWorkerM1.pas
new file mode 100644
index 0000000..d2b9ba0
--- /dev/null
+++ b/Delphi/source/Core/uSnowWorkerM1.pas
@@ -0,0 +1,404 @@
+unit uSnowWorkerM1;
+
+interface
+
+uses
+ uISnowWorker, uIdGeneratorOptions, System.SyncObjs, uTOverCostActionArg, System.DateUtils, System.SysUtils;
+
+///
+/// ѩƯ㷨
+///
+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
+ ///
+ /// ʱ
+ ///
+ // property BaseTime: TDateTime read FBaseTime write FBaseTime;
+ property BaseTime: Int64 read FBaseTime;
+ ///
+ ///
+ ///
+ property WorkerId: Word read FWorkerId default 0;
+ ///
+ /// λ
+ ///
+ property WorkerIdBitLength: Byte read FWorkerIdBitLength default 0;
+ ///
+ /// λ
+ ///
+ property SeqBitLength: Byte read FSeqBitLength default 0;
+ ///
+ ///
+ ///
+ property MaxSeqNumber: Integer read FMaxSeqNumber default 0;
+ ///
+ /// С
+ ///
+ property MinSeqNumber: Word read FMinSeqNumber default 0;
+ ///
+ /// Ưƴ
+ ///
+ 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 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.
diff --git a/Delphi/source/Core/uSnowWorkerM2.pas b/Delphi/source/Core/uSnowWorkerM2.pas
new file mode 100644
index 0000000..6e902eb
--- /dev/null
+++ b/Delphi/source/Core/uSnowWorkerM2.pas
@@ -0,0 +1,75 @@
+unit uSnowWorkerM2;
+
+interface
+
+uses System.SysUtils, uSnowWorkerM1, uIdGeneratorOptions, System.SyncObjs;
+
+///
+/// ѩ㷨
+///
+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.
diff --git a/Delphi/source/Core/uSnowWorkerM3.pas b/Delphi/source/Core/uSnowWorkerM3.pas
new file mode 100644
index 0000000..e90d59e
--- /dev/null
+++ b/Delphi/source/Core/uSnowWorkerM3.pas
@@ -0,0 +1,91 @@
+unit uSnowWorkerM3;
+
+interface
+
+uses System.SysUtils, System.DateUtils, uSnowWorkerM1, uIdGeneratorOptions, System.SyncObjs;
+
+///
+/// ѩƯ㷨֧ID뼶ʱ
+///
+type
+ TSnowWorkerM3 = class(TSnowWorkerM1)
+ protected
+ FDataCenterId: Cardinal;
+ FDataCenterIdBitLength: Byte;
+ FTimestampType: Byte;
+ protected
+ ///
+ /// IDĬ0
+ ///
+ property DataCenterId: Cardinal read FDataCenterId default 0;
+ ///
+ /// IDȣĬ0
+ ///
+ property DataCenterIdBitLength: Byte read FDataCenterIdBitLength default 0;
+ ///
+ /// ʱͣ0-룬1-룩Ĭ0
+ ///
+ 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.
diff --git a/Delphi/source/IdGenTest.dpr b/Delphi/source/IdGenTest.dpr
new file mode 100644
index 0000000..8205adf
--- /dev/null
+++ b/Delphi/source/IdGenTest.dpr
@@ -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.
diff --git a/Delphi/source/IdGenTest.dproj b/Delphi/source/IdGenTest.dproj
new file mode 100644
index 0000000..97237f5
--- /dev/null
+++ b/Delphi/source/IdGenTest.dproj
@@ -0,0 +1,987 @@
+
+
+ {9237743A-F2B2-49BE-941B-C151799790AF}
+ 18.8
+ VCL
+ IdGenTest.dpr
+ True
+ Release
+ Win32
+ 1
+ Application
+
+
+ true
+
+
+ true
+ Base
+ true
+
+
+ true
+ Base
+ true
+
+
+ true
+ Base
+ true
+
+
+ true
+ Cfg_1
+ true
+ true
+
+
+ true
+ Base
+ true
+
+
+ true
+ Cfg_2
+ true
+ true
+
+
+ .\$(Platform)\$(Config)
+ .\$(Platform)\$(Config)
+ false
+ false
+ false
+ false
+ false
+ System;Xml;Data;Datasnap;Web;Soap;Vcl;Vcl.Imaging;Vcl.Touch;Vcl.Samples;Vcl.Shell;$(DCC_Namespace)
+ $(BDS)\bin\delphi_PROJECTICON.ico
+ $(BDS)\bin\Artwork\Windows\UWP\delphi_UwpDefault_44.png
+ $(BDS)\bin\Artwork\Windows\UWP\delphi_UwpDefault_150.png
+ IdGenTest
+
+
+ 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)
+ Winapi;System.Win;Data.Win;Datasnap.Win;Web.Win;Soap.Win;Xml.Win;Bde;$(DCC_Namespace)
+ Debug
+ true
+ CompanyName=;FileDescription=$(MSBuildProjectName);FileVersion=1.0.0.0;InternalName=;LegalCopyright=;LegalTrademarks=;OriginalFilename=;ProgramID=com.embarcadero.$(MSBuildProjectName);ProductName=$(MSBuildProjectName);ProductVersion=1.0.0.0;Comments=
+ 1033
+ $(BDS)\bin\default_app.manifest
+ .\
+
+
+ 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)
+
+
+ DEBUG;$(DCC_Define)
+ true
+ false
+ true
+ true
+ true
+
+
+ false
+ true
+ PerMonitorV2
+
+
+ false
+ RELEASE;$(DCC_Define)
+ 0
+ 0
+
+
+ true
+ PerMonitorV2
+ true
+ 1033
+
+
+
+ MainSource
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Cfg_2
+ Base
+
+
+ Base
+
+
+ Cfg_1
+ Base
+
+
+
+ Delphi.Personality.12
+ Application
+
+
+
+
+ Microsoft Office 2000 Sample Automation Server Wrapper Components
+ Microsoft Office XP Sample Automation Server Wrapper Components
+
+
+
+
+
+ IdGenTest.exe
+ true
+
+
+
+
+ 1
+
+
+ Contents\MacOS
+ 1
+
+
+ 0
+
+
+
+
+ classes
+ 1
+
+
+ classes
+ 1
+
+
+
+
+ res\xml
+ 1
+
+
+ res\xml
+ 1
+
+
+
+
+ library\lib\armeabi-v7a
+ 1
+
+
+
+
+ library\lib\armeabi
+ 1
+
+
+ library\lib\armeabi
+ 1
+
+
+
+
+ library\lib\armeabi-v7a
+ 1
+
+
+
+
+ library\lib\mips
+ 1
+
+
+ library\lib\mips
+ 1
+
+
+
+
+ library\lib\armeabi-v7a
+ 1
+
+
+ library\lib\arm64-v8a
+ 1
+
+
+
+
+ library\lib\armeabi-v7a
+ 1
+
+
+
+
+ res\drawable
+ 1
+
+
+ res\drawable
+ 1
+
+
+
+
+ res\values
+ 1
+
+
+ res\values
+ 1
+
+
+
+
+ res\values-v21
+ 1
+
+
+ res\values-v21
+ 1
+
+
+
+
+ res\values
+ 1
+
+
+ res\values
+ 1
+
+
+
+
+ res\drawable
+ 1
+
+
+ res\drawable
+ 1
+
+
+
+
+ res\drawable-xxhdpi
+ 1
+
+
+ res\drawable-xxhdpi
+ 1
+
+
+
+
+ res\drawable-ldpi
+ 1
+
+
+ res\drawable-ldpi
+ 1
+
+
+
+
+ res\drawable-mdpi
+ 1
+
+
+ res\drawable-mdpi
+ 1
+
+
+
+
+ res\drawable-hdpi
+ 1
+
+
+ res\drawable-hdpi
+ 1
+
+
+
+
+ res\drawable-xhdpi
+ 1
+
+
+ res\drawable-xhdpi
+ 1
+
+
+
+
+ res\drawable-mdpi
+ 1
+
+
+ res\drawable-mdpi
+ 1
+
+
+
+
+ res\drawable-hdpi
+ 1
+
+
+ res\drawable-hdpi
+ 1
+
+
+
+
+ res\drawable-xhdpi
+ 1
+
+
+ res\drawable-xhdpi
+ 1
+
+
+
+
+ res\drawable-xxhdpi
+ 1
+
+
+ res\drawable-xxhdpi
+ 1
+
+
+
+
+ res\drawable-xxxhdpi
+ 1
+
+
+ res\drawable-xxxhdpi
+ 1
+
+
+
+
+ res\drawable-small
+ 1
+
+
+ res\drawable-small
+ 1
+
+
+
+
+ res\drawable-normal
+ 1
+
+
+ res\drawable-normal
+ 1
+
+
+
+
+ res\drawable-large
+ 1
+
+
+ res\drawable-large
+ 1
+
+
+
+
+ res\drawable-xlarge
+ 1
+
+
+ res\drawable-xlarge
+ 1
+
+
+
+
+ res\values
+ 1
+
+
+ res\values
+ 1
+
+
+
+
+ 1
+
+
+ Contents\MacOS
+ 1
+
+
+ 0
+
+
+
+
+ Contents\MacOS
+ 1
+ .framework
+
+
+ Contents\MacOS
+ 1
+ .framework
+
+
+ 0
+
+
+
+
+ 1
+ .dylib
+
+
+ 1
+ .dylib
+
+
+ 1
+ .dylib
+
+
+ Contents\MacOS
+ 1
+ .dylib
+
+
+ Contents\MacOS
+ 1
+ .dylib
+
+
+ 0
+ .dll;.bpl
+
+
+
+
+ 1
+ .dylib
+
+
+ 1
+ .dylib
+
+
+ 1
+ .dylib
+
+
+ Contents\MacOS
+ 1
+ .dylib
+
+
+ Contents\MacOS
+ 1
+ .dylib
+
+
+ 0
+ .bpl
+
+
+
+
+ 0
+
+
+ 0
+
+
+ 0
+
+
+ 0
+
+
+ 0
+
+
+ Contents\Resources\StartUp\
+ 0
+
+
+ Contents\Resources\StartUp\
+ 0
+
+
+ 0
+
+
+
+
+ 1
+
+
+ 1
+
+
+ 1
+
+
+
+
+ 1
+
+
+ 1
+
+
+ 1
+
+
+
+
+ 1
+
+
+ 1
+
+
+ 1
+
+
+
+
+ 1
+
+
+ 1
+
+
+ 1
+
+
+
+
+ 1
+
+
+ 1
+
+
+ 1
+
+
+
+
+ 1
+
+
+ 1
+
+
+ 1
+
+
+
+
+ 1
+
+
+ 1
+
+
+ 1
+
+
+
+
+ 1
+
+
+ 1
+
+
+ 1
+
+
+
+
+ 1
+
+
+ 1
+
+
+ 1
+
+
+
+
+ 1
+
+
+ 1
+
+
+ 1
+
+
+
+
+ 1
+
+
+ 1
+
+
+ 1
+
+
+
+
+ 1
+
+
+ 1
+
+
+ 1
+
+
+
+
+ 1
+
+
+ 1
+
+
+ 1
+
+
+
+
+ 1
+
+
+ 1
+
+
+ 1
+
+
+
+
+ 1
+
+
+ 1
+
+
+ 1
+
+
+
+
+ 1
+
+
+ 1
+
+
+ 1
+
+
+
+
+ 1
+
+
+ 1
+
+
+ 1
+
+
+
+
+ 1
+
+
+ 1
+
+
+ 1
+
+
+
+
+ 1
+
+
+ 1
+
+
+ 1
+
+
+
+
+ 1
+
+
+ 1
+
+
+ 1
+
+
+
+
+ 1
+
+
+ 1
+
+
+ 1
+
+
+
+
+ 1
+
+
+ 1
+
+
+ 1
+
+
+
+
+ 1
+
+
+ 1
+
+
+ 1
+
+
+
+
+ 1
+
+
+ 1
+
+
+ 1
+
+
+
+
+ 1
+
+
+ 1
+
+
+
+
+ ..\$(PROJECTNAME).app.dSYM\Contents\Resources\DWARF
+ 1
+
+
+ ..\$(PROJECTNAME).app.dSYM\Contents\Resources\DWARF
+ 1
+
+
+
+
+ 1
+
+
+ 1
+
+
+
+
+ ..\
+ 1
+
+
+ ..\
+ 1
+
+
+
+
+ 1
+
+
+ 1
+
+
+ 1
+
+
+
+
+ 1
+
+
+ 1
+
+
+ 1
+
+
+
+
+ ..\$(PROJECTNAME).app.dSYM\Contents\Resources\DWARF
+ 1
+
+
+
+
+ ..\
+ 1
+
+
+ ..\
+ 1
+
+
+
+
+ Contents
+ 1
+
+
+ Contents
+ 1
+
+
+
+
+ Contents\Resources
+ 1
+
+
+ Contents\Resources
+ 1
+
+
+
+
+ library\lib\armeabi-v7a
+ 1
+
+
+ library\lib\arm64-v8a
+ 1
+
+
+ 1
+
+
+ 1
+
+
+ 1
+
+
+ 1
+
+
+ Contents\MacOS
+ 1
+
+
+ Contents\MacOS
+ 1
+
+
+ 0
+
+
+
+
+ library\lib\armeabi-v7a
+ 1
+
+
+
+
+ 1
+
+
+ 1
+
+
+
+
+ Assets
+ 1
+
+
+ Assets
+ 1
+
+
+
+
+ Assets
+ 1
+
+
+ Assets
+ 1
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ True
+ False
+
+
+ 12
+
+
+
+
+
diff --git a/Delphi/source/IdGenTest.res b/Delphi/source/IdGenTest.res
new file mode 100644
index 0000000..f06d283
Binary files /dev/null and b/Delphi/source/IdGenTest.res differ
diff --git a/Delphi/source/uDefaultIdGenerator.pas b/Delphi/source/uDefaultIdGenerator.pas
new file mode 100644
index 0000000..80453b7
--- /dev/null
+++ b/Delphi/source/uDefaultIdGenerator.pas
@@ -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('errorDataCenterIdBitLength + 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.
diff --git a/Delphi/source/uTest.dfm b/Delphi/source/uTest.dfm
new file mode 100644
index 0000000..e17d456
--- /dev/null
+++ b/Delphi/source/uTest.dfm
@@ -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
diff --git a/Delphi/source/uTest.pas b/Delphi/source/uTest.pas
new file mode 100644
index 0000000..2dd5282
--- /dev/null
+++ b/Delphi/source/uTest.pas
@@ -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.
diff --git a/Delphi/source/uYitIdHelper.pas b/Delphi/source/uYitIdHelper.pas
new file mode 100644
index 0000000..fe2f185
--- /dev/null
+++ b/Delphi/source/uYitIdHelper.pas
@@ -0,0 +1,51 @@
+unit uYitIdHelper;
+
+interface
+
+uses System.SysUtils, uIIdGenerator, uIdGeneratorOptions;
+
+type
+ TYitIdHelper = class
+ private
+ IdGenInstance: IIdGenerator;
+ public
+ function GetIdGenInstance(): IIdGenerator;
+ ///
+ /// òʼʱִһ
+ ///
+ ///
+ procedure SetIdGenerator(options: TIdGeneratorOptions);
+ ///
+ /// µId
+ /// ñǰȷ SetIdGenerator ʼ
+ ///
+ ///
+ 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.
diff --git a/README.md b/README.md
index ef342dd..6426dab 100644
--- a/README.md
+++ b/README.md
@@ -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