1
0
mirror of synced 2024-12-22 09:13:07 +01:00

Added: optimized Split function

This commit is contained in:
Mark van Renswoude 2004-09-02 14:24:30 +00:00
parent bc366730a2
commit 72f1763ea1
4 changed files with 474 additions and 0 deletions

35
Test/X2UtStringsTest.cfg Normal file
View 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
View 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
View 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.

View File

@ -8,6 +8,9 @@
unit X2UtStrings;
interface
type
TSplitArray = array of String;
//:$ Formats the specified size
//:: If KeepBytes is true, the size will be formatted for decimal separators
//:: 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.
function SameTextS(const AMatch, AAgainst: String): Boolean;
//:$ Splits a string on the specified delimiter
procedure Split(const ASource, ADelimiter: String; out ADest: TSplitArray);
implementation
uses
SysUtils;
@ -101,5 +107,127 @@ begin
Result := SameTextL(AMatch, AAgainst, Length(AAgainst));
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.