Added: optimized Split function
This commit is contained in:
parent
bc366730a2
commit
72f1763ea1
35
Test/X2UtStringsTest.cfg
Normal file
35
Test/X2UtStringsTest.cfg
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
-$A8
|
||||||
|
-$B-
|
||||||
|
-$C+
|
||||||
|
-$D+
|
||||||
|
-$E-
|
||||||
|
-$F-
|
||||||
|
-$G+
|
||||||
|
-$H+
|
||||||
|
-$I+
|
||||||
|
-$J+
|
||||||
|
-$K-
|
||||||
|
-$L+
|
||||||
|
-$M-
|
||||||
|
-$N+
|
||||||
|
-$O+
|
||||||
|
-$P+
|
||||||
|
-$Q-
|
||||||
|
-$R+
|
||||||
|
-$S-
|
||||||
|
-$T-
|
||||||
|
-$U-
|
||||||
|
-$V+
|
||||||
|
-$W-
|
||||||
|
-$X+
|
||||||
|
-$YD
|
||||||
|
-$Z1
|
||||||
|
-cg
|
||||||
|
-AWinTypes=Windows;WinProcs=Windows;DbiTypes=BDE;DbiProcs=BDE;DbiErrs=BDE;
|
||||||
|
-H+
|
||||||
|
-W+
|
||||||
|
-M
|
||||||
|
-$M16384,1048576
|
||||||
|
-K$00400000
|
||||||
|
-LE"c:\delphi6\Projects\Bpl"
|
||||||
|
-LN"c:\delphi6\Projects\Bpl"
|
167
Test/X2UtStringsTest.dof
Normal file
167
Test/X2UtStringsTest.dof
Normal file
@ -0,0 +1,167 @@
|
|||||||
|
[FileVersion]
|
||||||
|
Version=6.0
|
||||||
|
[Compiler]
|
||||||
|
A=8
|
||||||
|
B=0
|
||||||
|
C=1
|
||||||
|
D=1
|
||||||
|
E=0
|
||||||
|
F=0
|
||||||
|
G=1
|
||||||
|
H=1
|
||||||
|
I=1
|
||||||
|
J=1
|
||||||
|
K=0
|
||||||
|
L=1
|
||||||
|
M=0
|
||||||
|
N=1
|
||||||
|
O=1
|
||||||
|
P=1
|
||||||
|
Q=0
|
||||||
|
R=1
|
||||||
|
S=0
|
||||||
|
T=0
|
||||||
|
U=0
|
||||||
|
V=1
|
||||||
|
W=0
|
||||||
|
X=1
|
||||||
|
Y=1
|
||||||
|
Z=1
|
||||||
|
ShowHints=1
|
||||||
|
ShowWarnings=1
|
||||||
|
UnitAliases=WinTypes=Windows;WinProcs=Windows;DbiTypes=BDE;DbiProcs=BDE;DbiErrs=BDE;
|
||||||
|
[Linker]
|
||||||
|
MapFile=0
|
||||||
|
OutputObjs=0
|
||||||
|
ConsoleApp=1
|
||||||
|
DebugInfo=0
|
||||||
|
RemoteSymbols=0
|
||||||
|
MinStackSize=16384
|
||||||
|
MaxStackSize=1048576
|
||||||
|
ImageBase=4194304
|
||||||
|
ExeDescription=
|
||||||
|
[Directories]
|
||||||
|
OutputDir=
|
||||||
|
UnitOutputDir=
|
||||||
|
PackageDLLOutputDir=
|
||||||
|
PackageDCPOutputDir=
|
||||||
|
SearchPath=
|
||||||
|
Packages=vcl;rtl;dbrtl;vcldb;vclx;dss;dsnapcrba;dsnapcon;inetdb;webdsnap;websnap;dbxcds;Irc;parsdpk;hotspotter
|
||||||
|
Conditionals=
|
||||||
|
DebugSourceDirs=
|
||||||
|
UsePackages=0
|
||||||
|
[Parameters]
|
||||||
|
RunParams=ip-to-country.csv countries.csv geo.db
|
||||||
|
HostApplication=
|
||||||
|
Launcher=
|
||||||
|
UseLauncher=0
|
||||||
|
DebugCWD=
|
||||||
|
[Version Info]
|
||||||
|
IncludeVerInfo=1
|
||||||
|
AutoIncBuild=0
|
||||||
|
MajorVer=1
|
||||||
|
MinorVer=0
|
||||||
|
Release=0
|
||||||
|
Build=0
|
||||||
|
Debug=0
|
||||||
|
PreRelease=0
|
||||||
|
Special=0
|
||||||
|
Private=0
|
||||||
|
DLL=0
|
||||||
|
Locale=1043
|
||||||
|
CodePage=1252
|
||||||
|
[Version Info Keys]
|
||||||
|
CompanyName=
|
||||||
|
FileDescription=
|
||||||
|
FileVersion=1.0.0.0
|
||||||
|
InternalName=
|
||||||
|
LegalCopyright=
|
||||||
|
LegalTrademarks=
|
||||||
|
OriginalFilename=
|
||||||
|
ProductName=
|
||||||
|
ProductVersion=1.0.0.0
|
||||||
|
Comments=
|
||||||
|
[Excluded Packages]
|
||||||
|
c:\delphi6\Bin\dcl31w60.bpl=Delphi 1.0 Compatibility Components
|
||||||
|
C:\Delphi6\Bin\dcldb60.bpl=Borland Database Components
|
||||||
|
c:\delphi6\Bin\dclact60.bpl=Borland ActionBar Components
|
||||||
|
C:\Program Files\madCollection\madBasic\Delphi 6\madHelp_.bpl=madHelp 1.1 · www.madshi.net
|
||||||
|
c:\delphi6\Bin\applet60.bpl=Borland Control Panel Applet Package
|
||||||
|
c:\delphi6\Projects\Bpl\X2CompsD6.bpl=X²Software Components - Designtime
|
||||||
|
C:\Delphi6\Bin\dbx60.bpl=Borland SQL Explorer UI Package
|
||||||
|
C:\Delphi6\Projects\Bpl\tb2k_d6.bpl=Toolbar2000 Components (Jordan Russell)
|
||||||
|
c:\delphi6\Projects\Bpl\tb2kdsgn_d6.bpl=Toolbar2000 Design Package (Jordan Russell)
|
||||||
|
c:\delphi6\Projects\Bpl\VirtualTreesD6D.bpl=Virtual Treeview
|
||||||
|
c:\delphi6\Bin\DCLNMF60.bpl=NetMasters Fastnet Tools
|
||||||
|
c:\delphi6\Bin\dclado60.bpl=Borland ADO DB Components
|
||||||
|
c:\delphi6\Bin\dclclxdb60.bpl=Borland CLX Database Components
|
||||||
|
C:\Delphi6\Bin\dclclxstd60.bpl=Borland CLX Standard Components
|
||||||
|
c:\delphi6\Bin\dclie60.bpl=Internet Explorer Components
|
||||||
|
C:\Delphi6\Projects\Bpl\aSQLitepkg.bpl=Aducom Software -- SQLite RunTime Components
|
||||||
|
c:\delphi6\Projects\Bpl\asqlite.bpl=Aducom Software -- SQLite Design Time Components
|
||||||
|
c:\delphi6\Projects\Bpl\PCtrlExd6.bpl=PageControlEx
|
||||||
|
c:\delphi6\Projects\Bpl\JvCoreD6D.bpl=JVCL Core Components
|
||||||
|
c:\delphi6\Projects\Bpl\JvSystemD6D.bpl=JVCL System Components
|
||||||
|
c:\delphi6\Projects\Bpl\JvStdCtrlsD6D.bpl=JVCL Standard Controls
|
||||||
|
c:\delphi6\Projects\Bpl\JvCtrlsD6D.bpl=JVCL Visual Controls
|
||||||
|
c:\delphi6\Projects\Bpl\JvCmpD6D.bpl=JVCL Non-Visual Components
|
||||||
|
c:\delphi6\Projects\Bpl\JvCustomD6D.bpl=JVCL Custom Controls
|
||||||
|
c:\delphi6\Projects\Bpl\JvDlgsD6D.bpl=JVCL Dialog Components
|
||||||
|
c:\delphi6\Projects\Bpl\JvCryptD6D.bpl=JVCL Encryption and Compression Components
|
||||||
|
c:\delphi6\Projects\Bpl\JvMMD6D.bpl=JVCL Multimedia and Image Components
|
||||||
|
c:\delphi6\Projects\Bpl\JvNetD6D.bpl=JVCL Network Components
|
||||||
|
c:\delphi6\Projects\Bpl\JvAppFrmD6D.bpl=JVCL Application and Form Components
|
||||||
|
c:\delphi6\Projects\Bpl\JvDBD6D.bpl=JVCL Database Components
|
||||||
|
c:\delphi6\Projects\Bpl\JvBDED6D.bpl=JVCL BDE Components
|
||||||
|
c:\delphi6\Projects\Bpl\JvInterpreterD6D.bpl=JVCL Interpreter Components
|
||||||
|
c:\delphi6\Projects\Bpl\JvBandsD6D.bpl=JVCL Band Objects
|
||||||
|
c:\delphi6\Projects\Bpl\JvPluginD6D.bpl=JVCL Plugin Components
|
||||||
|
c:\delphi6\Projects\Bpl\JvJansD6D.bpl=JVCL Jans Components
|
||||||
|
c:\delphi6\Projects\Bpl\JvGlobusD6D.bpl=JVCL Globus Components
|
||||||
|
c:\delphi6\Projects\Bpl\JvPrintPreviewD6D.bpl=JVCL Print Preview Components
|
||||||
|
c:\delphi6\Projects\Bpl\JvPageCompsD6D.bpl=JVCL Page Style Components
|
||||||
|
c:\delphi6\Projects\Bpl\JvValidatorsD6D.bpl=JVCL Validators and Error Provider Components
|
||||||
|
c:\delphi6\Projects\Bpl\JvUIBD6D.bpl=JVCL Unified Interbase Components
|
||||||
|
c:\delphi6\Projects\Bpl\JvWizardD6D.bpl=JVCL Wizard Design Time Package
|
||||||
|
c:\delphi6\Projects\Bpl\JvTimeFrameworkD6D.bpl=JVCL Time Framework
|
||||||
|
c:\delphi6\Projects\Bpl\JvHMID6D.bpl=JVCL HMI Controls design time unit
|
||||||
|
c:\delphi6\Projects\Bpl\JvManagedThreadsD6D.bpl=JVCL Managed Threads
|
||||||
|
c:\delphi6\Projects\Bpl\JvXPCtrlsD6D.bpl=JVCL XP Controls
|
||||||
|
c:\delphi6\Projects\Bpl\JvDockingD6D.bpl=JVCL Docking Components
|
||||||
|
c:\delphi6\Projects\Bpl\JvDotNetCtrlsD6D.bpl=JVCL DotNet Controls
|
||||||
|
c:\delphi6\Projects\Bpl\dclIndyCore60.bpl=Indy 10 Core Design Time
|
||||||
|
c:\delphi6\Projects\Bpl\dclIndyProtocols60.bpl=Indy 10 Protocols Design Time
|
||||||
|
c:\delphi6\Projects\Bpl\SysILS.bpl=System ImageList
|
||||||
|
c:\delphi6\Projects\Bpl\DragDropD6.bpl=Drag and Drop Component Suite
|
||||||
|
C:\Projects\Components\DevExpress\OrgChart Suite\Lib\dcldxOrgCD6.bpl=ExpressOrgChart by Developer Express Inc.
|
||||||
|
C:\Projects\Components\DevExpress\OrgChart Suite\Lib\dcldxDBOrD6.bpl=ExpressDBOrgChart by Developer Express Inc.
|
||||||
|
c:\delphi6\Projects\Bpl\BalloonD6.bpl=Balloon 2.0
|
||||||
|
c:\delphi6\Projects\Bpl\DIPasDocD6.bpl=DiPasDoc - Designtime
|
||||||
|
C:\Delphi6\Projects\Bpl\DIContainers_D6.bpl=The Delphi Inspiration -- DIContainers
|
||||||
|
c:\delphi6\Bin\dclshlctrls60.bpl=Shell Control Property and Component Editors
|
||||||
|
c:\delphi6\Bin\dclsmp60.bpl=Borland Sample Components
|
||||||
|
c:\delphi6\Bin\dclbde60.bpl=Borland BDE DB Components
|
||||||
|
c:\delphi6\Bin\dclcds60.bpl=Borland Base Cached ClientDataset Component
|
||||||
|
C:\Delphi6\Bin\dclmid60.bpl=Borland MyBase DataAccess Components
|
||||||
|
c:\delphi6\Bin\dclbdecds60.bpl=Borland Local BDE ClientDataset Components
|
||||||
|
c:\delphi6\Bin\dclib60.bpl=InterBase Data Access Components
|
||||||
|
c:\delphi6\Bin\DBWEBXPRT.BPL=Borland Web Wizard Package
|
||||||
|
c:\delphi6\Bin\dcloffice2k60.bpl=Microsoft Office 2000 Sample Automation Server Wrapper Components
|
||||||
|
c:\delphi6\Bin\dcltee60.bpl=TeeChart Components
|
||||||
|
c:\delphi6\Bin\dcltqr60.bpl=TeeChart for QuickReport Components
|
||||||
|
c:\delphi6\Bin\dclnet60.bpl=Borland Internet Components
|
||||||
|
c:\delphi6\Bin\dclite60.bpl=Borland Integrated Translation Environment
|
||||||
|
c:\delphi6\Bin\dcldbx60.bpl=Borland dbExpress Components
|
||||||
|
c:\delphi6\Bin\dclsoap60.bpl=Borland SOAP Components
|
||||||
|
c:\delphi6\Bin\dclocx60.bpl=Borland Sample Imported ActiveX Controls
|
||||||
|
c:\delphi6\Bin\dcldbxcds60.bpl=Borland Local DBX ClientDataset Components
|
||||||
|
C:\Program Files\madCollection\madRemote\Delphi 6\madRemote_.bpl=madRemote 1.1b · www.madshi.net
|
||||||
|
C:\Program Files\madCollection\madKernel\Delphi 6\madKernel_.bpl=madKernel 1.3 · www.madshi.net
|
||||||
|
C:\Program Files\madCollection\madCodeHook\Delphi 6\madCodeHook_.bpl=madCodeHook 2.1b · www.madshi.net
|
||||||
|
C:\Program Files\madCollection\madSecurity\Delphi 6\madSecurity_.bpl=madSecurity 1.1n · www.madshi.net
|
||||||
|
C:\Program Files\madCollection\madShell\Delphi 6\madShell_.bpl=madShell 1.3k · www.madshi.net
|
||||||
|
C:\WINDOWS\System32\ibevnt60.bpl=Borland Interbase Event Alerter Component
|
||||||
|
c:\delphi6\Projects\Bpl\PsychoTidyD6.bpl=PsychoTidy IDE Expert
|
||||||
|
[HistoryLists\hlUnitAliases]
|
||||||
|
Count=1
|
||||||
|
Item0=WinTypes=Windows;WinProcs=Windows;DbiTypes=BDE;DbiProcs=BDE;DbiErrs=BDE;
|
144
Test/X2UtStringsTest.dpr
Normal file
144
Test/X2UtStringsTest.dpr
Normal file
@ -0,0 +1,144 @@
|
|||||||
|
program X2UtStringsTest;
|
||||||
|
|
||||||
|
{$APPTYPE CONSOLE}
|
||||||
|
|
||||||
|
uses
|
||||||
|
SysUtils,
|
||||||
|
Windows,
|
||||||
|
|
||||||
|
FastStrings,
|
||||||
|
|
||||||
|
X2UtStrings;
|
||||||
|
|
||||||
|
var
|
||||||
|
GFreq: Int64;
|
||||||
|
GStart: Int64;
|
||||||
|
|
||||||
|
procedure TimeStart();
|
||||||
|
begin
|
||||||
|
QueryPerformanceFrequency(GFreq);
|
||||||
|
QueryPerformanceCounter(GStart);
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure TimeEnd();
|
||||||
|
var
|
||||||
|
iEnd: Int64;
|
||||||
|
|
||||||
|
begin
|
||||||
|
QueryPerformanceCounter(iEnd);
|
||||||
|
WriteLn(Format('%.6f seconds', [(iEnd - GStart) / GFreq]));
|
||||||
|
end;
|
||||||
|
|
||||||
|
|
||||||
|
procedure OldSplit(const ASource, ADelimiter: String; out ADest: TSplitArray);
|
||||||
|
var
|
||||||
|
iCount: Integer;
|
||||||
|
iPos: Integer;
|
||||||
|
iLength: Integer;
|
||||||
|
sTemp: String;
|
||||||
|
|
||||||
|
begin
|
||||||
|
sTemp := ASource;
|
||||||
|
iCount := 0;
|
||||||
|
iLength := Length(ADelimiter) - 1;
|
||||||
|
|
||||||
|
repeat
|
||||||
|
iPos := Pos(ADelimiter, sTemp);
|
||||||
|
|
||||||
|
if iPos = 0 then
|
||||||
|
break
|
||||||
|
else begin
|
||||||
|
Inc(iCount);
|
||||||
|
SetLength(ADest, iCount);
|
||||||
|
ADest[iCount - 1] := Copy(sTemp, 1, iPos - 1);
|
||||||
|
Delete(sTemp, 1, iPos + iLength);
|
||||||
|
end;
|
||||||
|
until False;
|
||||||
|
|
||||||
|
if Length(sTemp) > 0 then begin
|
||||||
|
Inc(iCount);
|
||||||
|
SetLength(ADest, iCount);
|
||||||
|
ADest[iCount - 1] := sTemp;
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure OldFastStringsSplit(const ASource, ADelimiter: String; out ADest: TSplitArray);
|
||||||
|
const
|
||||||
|
BufferSize = 50;
|
||||||
|
|
||||||
|
var
|
||||||
|
iCount: Integer;
|
||||||
|
iSize: Integer;
|
||||||
|
iPos: Integer;
|
||||||
|
iDelimLength: Integer;
|
||||||
|
iLength: Integer;
|
||||||
|
iLastPos: Integer;
|
||||||
|
|
||||||
|
begin
|
||||||
|
iCount := 0;
|
||||||
|
iDelimLength := Length(ADelimiter);
|
||||||
|
iLength := Length(ASource);
|
||||||
|
iPos := 1;
|
||||||
|
iLastPos := 1;
|
||||||
|
iSize := BufferSize;
|
||||||
|
SetLength(ADest, iSize);
|
||||||
|
|
||||||
|
repeat
|
||||||
|
iPos := FastPos(ASource, ADelimiter, iLength, iDelimLength, iPos);
|
||||||
|
|
||||||
|
if iPos = 0 then
|
||||||
|
break
|
||||||
|
else begin
|
||||||
|
ADest[iCount] := Copy(ASource, iLastPos, iPos - iLastPos);
|
||||||
|
Inc(iPos, iDelimLength);
|
||||||
|
iLastPos := iPos;
|
||||||
|
|
||||||
|
Inc(iCount);
|
||||||
|
if iCount >= iSize then begin
|
||||||
|
Inc(iSize, BufferSize);
|
||||||
|
SetLength(ADest, iSize);
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
until False;
|
||||||
|
|
||||||
|
|
||||||
|
if iLastPos <= iLength then begin
|
||||||
|
ADest[iCount] := Copy(ASource, iLastPos, iLength - iLastPos + 1);
|
||||||
|
Inc(iCount);
|
||||||
|
end;
|
||||||
|
|
||||||
|
if iSize <> iCount then
|
||||||
|
SetLength(ADest, iCount);
|
||||||
|
end;
|
||||||
|
|
||||||
|
|
||||||
|
var
|
||||||
|
sTest: String;
|
||||||
|
iCount: Integer;
|
||||||
|
aSplit: TSplitArray;
|
||||||
|
|
||||||
|
begin
|
||||||
|
sTest := 'this|isateststring||';
|
||||||
|
for iCount := 0 to 7 do
|
||||||
|
sTest := sTest + sTest;
|
||||||
|
|
||||||
|
TimeStart();
|
||||||
|
Write('10.000 iterations of OldSplit: ');
|
||||||
|
for iCount := 0 to 9999 do
|
||||||
|
OldSplit(sTest, '|', aSplit);
|
||||||
|
TimeEnd();
|
||||||
|
|
||||||
|
TimeStart();
|
||||||
|
Write('10.000 iterations of OldFastStringsSplit: ');
|
||||||
|
for iCount := 0 to 9999 do
|
||||||
|
OldFastStringsSplit(sTest, '|', aSplit);
|
||||||
|
TimeEnd();
|
||||||
|
|
||||||
|
TimeStart();
|
||||||
|
Write('10.000 iterations of Split: ');
|
||||||
|
for iCount := 0 to 9999 do
|
||||||
|
Split(sTest, '||', aSplit);
|
||||||
|
TimeEnd();
|
||||||
|
|
||||||
|
ReadLn;
|
||||||
|
end.
|
128
X2UtStrings.pas
128
X2UtStrings.pas
@ -8,6 +8,9 @@
|
|||||||
unit X2UtStrings;
|
unit X2UtStrings;
|
||||||
|
|
||||||
interface
|
interface
|
||||||
|
type
|
||||||
|
TSplitArray = array of String;
|
||||||
|
|
||||||
//:$ Formats the specified size
|
//:$ Formats the specified size
|
||||||
//:: If KeepBytes is true, the size will be formatted for decimal separators
|
//:: If KeepBytes is true, the size will be formatted for decimal separators
|
||||||
//:: and 'bytes' will be appended. If KeepBytes is false the best suitable
|
//:: and 'bytes' will be appended. If KeepBytes is false the best suitable
|
||||||
@ -30,6 +33,9 @@ interface
|
|||||||
//:$ Compares AMatch against AAgainst using AAgainst's length.
|
//:$ Compares AMatch against AAgainst using AAgainst's length.
|
||||||
function SameTextS(const AMatch, AAgainst: String): Boolean;
|
function SameTextS(const AMatch, AAgainst: String): Boolean;
|
||||||
|
|
||||||
|
//:$ Splits a string on the specified delimiter
|
||||||
|
procedure Split(const ASource, ADelimiter: String; out ADest: TSplitArray);
|
||||||
|
|
||||||
implementation
|
implementation
|
||||||
uses
|
uses
|
||||||
SysUtils;
|
SysUtils;
|
||||||
@ -101,5 +107,127 @@ begin
|
|||||||
Result := SameTextL(AMatch, AAgainst, Length(AAgainst));
|
Result := SameTextL(AMatch, AAgainst, Length(AAgainst));
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
|
||||||
|
procedure Split;
|
||||||
|
// StrPos is slow. Sloooooow slow. This function may not be advanced or
|
||||||
|
// the fastest one around, but it sure kicks StrPos' ass.
|
||||||
|
// 11.5 vs 1.7 seconds on a 2.4 Ghz for 10.000 iterations, baby!
|
||||||
|
function StrPosEx(const ASource, ASearch: PChar): PChar;
|
||||||
|
var
|
||||||
|
pPos: PChar;
|
||||||
|
pSub: PChar;
|
||||||
|
|
||||||
|
begin
|
||||||
|
Result := nil;
|
||||||
|
|
||||||
|
// Search for the first character
|
||||||
|
pPos := ASource;
|
||||||
|
|
||||||
|
while pPos^ <> #0 do
|
||||||
|
begin
|
||||||
|
if pPos^ = ASearch^ then
|
||||||
|
begin
|
||||||
|
// Found the first character, match the rest
|
||||||
|
pSub := ASearch;
|
||||||
|
Result := pPos;
|
||||||
|
Inc(pSub);
|
||||||
|
Inc(pPos);
|
||||||
|
|
||||||
|
|
||||||
|
while pSub^ <> #0 do
|
||||||
|
begin
|
||||||
|
if pPos^ <> pSub^ then
|
||||||
|
begin
|
||||||
|
// No match, resume as normal
|
||||||
|
Result := nil;
|
||||||
|
break;
|
||||||
|
end;
|
||||||
|
|
||||||
|
Inc(pSub);
|
||||||
|
Inc(pPos);
|
||||||
|
end;
|
||||||
|
|
||||||
|
// If still assigned, all characters matched
|
||||||
|
if Assigned(Result) then
|
||||||
|
exit;
|
||||||
|
end else
|
||||||
|
Inc(pPos);
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
|
const
|
||||||
|
GrowStart = 32;
|
||||||
|
GrowMax = 256;
|
||||||
|
|
||||||
|
var
|
||||||
|
iCapacity: Integer;
|
||||||
|
iCount: Integer;
|
||||||
|
iDelimLen: Integer;
|
||||||
|
iLength: Integer;
|
||||||
|
iPos: Integer;
|
||||||
|
iSize: Integer;
|
||||||
|
pDelimiter: PChar;
|
||||||
|
pLast: PChar;
|
||||||
|
pPos: PChar;
|
||||||
|
|
||||||
|
begin
|
||||||
|
// Reserve some space
|
||||||
|
iCapacity := GrowStart;
|
||||||
|
iCount := 0;
|
||||||
|
SetLength(ADest, iCapacity);
|
||||||
|
|
||||||
|
iDelimLen := Length(ADelimiter);
|
||||||
|
iLength := Length(ASource);
|
||||||
|
iPos := -1;
|
||||||
|
pDelimiter := PChar(ADelimiter);
|
||||||
|
pPos := PChar(ASource);
|
||||||
|
|
||||||
|
repeat
|
||||||
|
// Find delimiter
|
||||||
|
pLast := pPos;
|
||||||
|
pPos := StrPosEx(pPos, pDelimiter);
|
||||||
|
|
||||||
|
if pPos <> nil then
|
||||||
|
begin
|
||||||
|
// Make space
|
||||||
|
Inc(iCount);
|
||||||
|
if iCount > iCapacity then
|
||||||
|
begin
|
||||||
|
if iCapacity < GrowMax then
|
||||||
|
Inc(iCapacity, iCapacity)
|
||||||
|
else
|
||||||
|
Inc(iCapacity, GrowMax);
|
||||||
|
|
||||||
|
SetLength(ADest, iCapacity);
|
||||||
|
end;
|
||||||
|
|
||||||
|
// Copy substring
|
||||||
|
iSize := Integer(pPos) - Integer(pLast);
|
||||||
|
SetString(ADest[iCount - 1], pLast, iSize);
|
||||||
|
|
||||||
|
// Move pointer
|
||||||
|
Inc(pPos, iDelimLen);
|
||||||
|
Inc(iPos, iSize + iDelimLen);
|
||||||
|
end else
|
||||||
|
begin
|
||||||
|
if iPos < iLength then
|
||||||
|
begin
|
||||||
|
// Copy what's left
|
||||||
|
Inc(iCount);
|
||||||
|
if iCount > iCapacity then
|
||||||
|
SetLength(ADest, iCount);
|
||||||
|
|
||||||
|
ADest[iCount - 1] := pLast;
|
||||||
|
end;
|
||||||
|
|
||||||
|
if iCount <> iCapacity then
|
||||||
|
// Shrink array
|
||||||
|
SetLength(ADest, iCount);
|
||||||
|
|
||||||
|
break;
|
||||||
|
end;
|
||||||
|
until False;
|
||||||
|
end;
|
||||||
|
|
||||||
end.
|
end.
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user