* Speed improvements, iteration 1

git-svn-id: trunk@42882 -
This commit is contained in:
michael 2019-08-31 10:38:49 +00:00
parent 869fc5c7b3
commit 9d969a5fb1
4 changed files with 122 additions and 57 deletions

View File

@ -723,6 +723,7 @@ Type
{$ifdef fpc} {$ifdef fpc}
TJSONParserHandler = Procedure(AStream : TStream; Const AUseUTF8 : Boolean; Out Data : TJSONData); TJSONParserHandler = Procedure(AStream : TStream; Const AUseUTF8 : Boolean; Out Data : TJSONData);
TJSONStringParserHandler = Procedure(Const aJSON : TJSONStringType; Const AUseUTF8 : Boolean; Out Data : TJSONData);
{$endif} {$endif}
Function SetJSONInstanceType(AType : TJSONInstanceType; AClass : TJSONDataClass) : TJSONDataClass; Function SetJSONInstanceType(AType : TJSONInstanceType; AClass : TJSONDataClass) : TJSONDataClass;
@ -754,7 +755,9 @@ Function CreateJSONObject(const Data : Array of {$ifdef pas2js}jsvalue{$else}Con
Function GetJSON(Const JSON : TJSONStringType; Const UseUTF8 : Boolean = True) : TJSONData; Function GetJSON(Const JSON : TJSONStringType; Const UseUTF8 : Boolean = True) : TJSONData;
Function GetJSON(Const JSON : TStream; Const UseUTF8 : Boolean = True) : TJSONData; Function GetJSON(Const JSON : TStream; Const UseUTF8 : Boolean = True) : TJSONData;
Function SetJSONParserHandler(AHandler : TJSONParserHandler) : TJSONParserHandler; Function SetJSONParserHandler(AHandler : TJSONParserHandler) : TJSONParserHandler;
Function SetJSONStringParserHandler(AHandler : TJSONStringParserHandler) : TJSONStringParserHandler;
Function GetJSONParserHandler : TJSONParserHandler; Function GetJSONParserHandler : TJSONParserHandler;
Function GetJSONStringParserHandler: TJSONStringParserHandler;
{$endif} {$endif}
implementation implementation
@ -1003,31 +1006,57 @@ begin
end; end;
{$ifdef fpc} {$ifdef fpc}
Var
JPH : TJSONParserHandler;
JPSH : TJSONStringParserHandler;
function GetJSON(const JSON: TJSONStringType; const UseUTF8: Boolean): TJSONData; function GetJSON(const JSON: TJSONStringType; const UseUTF8: Boolean): TJSONData;
Var Var
SS : TStringStream; SS : TStringStream;
begin begin
SS:=TStringStream.Create(JSON); if Assigned(JPSH) then
try JPSH(JSON,useUTF8,Result)
Result:=GetJSON(SS,UseUTF8); else
finally begin
SS.Free; if UseUTF8 then
end; SS:=TStringStream.Create(JSON,TEncoding.UTF8)
else
SS:=TStringStream.Create(JSON);
try
Result:=GetJSON(SS,UseUTF8);
finally
SS.Free;
end;
end;
end; end;
{$endif} {$endif}
{$ifdef fpc} {$ifdef fpc}
Var
JPH : TJSONParserHandler;
function GetJSON(const JSON: TStream; const UseUTF8: Boolean): TJSONData; function GetJSON(const JSON: TStream; const UseUTF8: Boolean): TJSONData;
Var
S : TJSONStringType;
begin begin
Result:=Nil; Result:=Nil;
If (JPH=Nil) then If (JPH<>Nil) then
TJSONData.DoError(SErrNoParserHandler); JPH(JSON,UseUTF8,Result)
JPH(JSON,UseUTF8,Result); else if JPSH=Nil then
TJSONData.DoError(SErrNoParserHandler)
else
begin
Setlength(S,JSON.Size);
if Length(S)>0 then
JSON.ReadBuffer(S[1],Length(S));
end;
end;
Function SetJSONStringParserHandler(AHandler : TJSONStringParserHandler) : TJSONStringParserHandler;
begin
Result:=JPSH;
JPSH:=AHandler;
end; end;
function SetJSONParserHandler(AHandler: TJSONParserHandler): TJSONParserHandler; function SetJSONParserHandler(AHandler: TJSONParserHandler): TJSONParserHandler;
@ -1040,6 +1069,11 @@ function GetJSONParserHandler: TJSONParserHandler;
begin begin
Result:=JPH; Result:=JPH;
end; end;
function GetJSONStringParserHandler: TJSONStringParserHandler;
begin
Result:=JPSH;
end;
{$endif} {$endif}
Type Type

View File

@ -82,6 +82,26 @@ begin
end; end;
end; end;
procedure DefJSONStringParserHandler(Const S : TJSONStringType; const AUseUTF8: Boolean; out
Data: TJSONData);
Var
P : TJSONParser;
AOptions: TJSONOptions;
begin
Data:=Nil;
AOptions:=[];
if AUseUTF8 then
Include(AOptions,joUTF8);
P:=TJSONParser.Create(S,AOptions);
try
Data:=P.Parse;
finally
P.Free;
end;
end;
procedure TJSONParser.Pop(aType: TJSONType); procedure TJSONParser.Pop(aType: TJSONType);
begin begin
@ -224,6 +244,8 @@ Procedure InitJSONHandler;
begin begin
if GetJSONParserHandler=Nil then if GetJSONParserHandler=Nil then
SetJSONParserHandler(@DefJSONParserHandler); SetJSONParserHandler(@DefJSONParserHandler);
if GetJSONStringParserHandler=Nil then
SetJSONStringParserHandler(@DefJSONStringParserHandler);
end; end;
Procedure DoneJSONHandler; Procedure DoneJSONHandler;
@ -231,6 +253,8 @@ Procedure DoneJSONHandler;
begin begin
if GetJSONParserHandler=@DefJSONParserHandler then if GetJSONParserHandler=@DefJSONParserHandler then
SetJSONParserHandler(Nil); SetJSONParserHandler(Nil);
if GetJSONStringParserHandler=@DefJSONStringParserHandler then
SetJSONStringParserHandler(Nil);
end; end;
initialization initialization

View File

@ -60,9 +60,9 @@ Type
Property Scanner : TJSONScanner read FScanner; Property Scanner : TJSONScanner read FScanner;
Public Public
Constructor Create(Source : TStream; AUseUTF8 : Boolean = True); overload;deprecated 'use options form instead'; Constructor Create(Source : TStream; AUseUTF8 : Boolean = True); overload;deprecated 'use options form instead';
Constructor Create(Source : TJSONStringType; AUseUTF8 : Boolean = True); overload;deprecated 'use options form instead'; Constructor Create(Const Source : RawByteString; AUseUTF8 : Boolean = True); overload;deprecated 'use options form instead';
constructor Create(Source: TStream; AOptions: TJSONOptions); overload; constructor Create(Source: TStream; AOptions: TJSONOptions); overload;
constructor Create(const Source: String; AOptions: TJSONOptions); overload; constructor Create(const Source: RawByteString; AOptions: TJSONOptions); overload;
destructor Destroy();override; destructor Destroy();override;
// Parsing options // Parsing options
Property Options : TJSONOptions Read GetOptions Write SetOptions; Property Options : TJSONOptions Read GetOptions Write SetOptions;
@ -415,7 +415,7 @@ begin
Options:=Options + [joUTF8]; Options:=Options + [joUTF8];
end; end;
constructor TBaseJSONReader.Create(Source: TJSONStringType; AUseUTF8 : Boolean = True); constructor TBaseJSONReader.Create(const Source: RawByteString; AUseUTF8 : Boolean = True);
begin begin
Inherited Create; Inherited Create;
FScanner:=TJSONScanner.Create(Source,[joUTF8]); FScanner:=TJSONScanner.Create(Source,[joUTF8]);
@ -428,7 +428,7 @@ begin
FScanner:=TJSONScanner.Create(Source,AOptions); FScanner:=TJSONScanner.Create(Source,AOptions);
end; end;
constructor TBaseJSONReader.Create(const Source: String; AOptions: TJSONOptions); constructor TBaseJSONReader.Create(const Source: RawByteString; AOptions: TJSONOptions);
begin begin
FScanner:=TJSONScanner.Create(Source,AOptions); FScanner:=TJSONScanner.Create(Source,AOptions);
end; end;

View File

@ -15,10 +15,6 @@
{$mode objfpc} {$mode objfpc}
{$h+} {$h+}
{$ifdef fpc}
{$define UsePChar}
{$endif}
unit jsonscanner; unit jsonscanner;
interface interface
@ -66,29 +62,26 @@ Type
TJSONScanner = class TJSONScanner = class
private private
FSource: TStringList; FSource: RawByteString;
FCurPos : PAnsiChar; // Position inside total string
FCurRow: Integer; FCurRow: Integer;
FCurToken: TJSONToken; FCurToken: TJSONToken;
FCurTokenString: string; FCurTokenString: string;
FCurLine: string; FCurLine: string;
FTokenStr: {$ifdef UsePChar}PChar{$else}integer{$endif}; // position inside FCurLine FTokenStr: PAnsiChar; // position inside FCurLine
FOptions : TJSONOptions; FOptions : TJSONOptions;
function GetCurColumn: Integer; inline; function GetCurColumn: Integer; inline;
function GetO(AIndex: TJSONOption): Boolean; function GetO(AIndex: TJSONOption): Boolean;
procedure SetO(AIndex: TJSONOption; AValue: Boolean); procedure SetO(AIndex: TJSONOption; AValue: Boolean);
protected protected
procedure Error(const Msg: string);overload; procedure Error(const Msg: string);overload;
procedure Error(const Msg: string; procedure Error(const Msg: string; Const Args: array of const);overload;
Const Args: array of {$ifdef pas2js}jsvalue{$else}const{$endif});overload;
function DoFetchToken: TJSONToken; inline; function DoFetchToken: TJSONToken; inline;
public public
{$ifdef fpc}
constructor Create(Source : TStream; AUseUTF8 : Boolean = True); overload; deprecated 'use options form instead'; constructor Create(Source : TStream; AUseUTF8 : Boolean = True); overload; deprecated 'use options form instead';
constructor Create(const Source : String; AUseUTF8 : Boolean = True); overload; deprecated 'use options form instead';
constructor Create(Source: TStream; AOptions: TJSONOptions); overload; constructor Create(Source: TStream; AOptions: TJSONOptions); overload;
{$endif} constructor Create(const aSource : RawByteString; AUseUTF8 : Boolean = True); overload; deprecated 'use options form instead';
constructor Create(const Source: String; AOptions: TJSONOptions); overload; constructor Create(const aSource: RawByteString; AOptions: TJSONOptions); overload;
destructor Destroy; override;
function FetchToken: TJSONToken; function FetchToken: TJSONToken;
@ -129,7 +122,6 @@ const
implementation implementation
{$ifdef fpc}
constructor TJSONScanner.Create(Source : TStream; AUseUTF8 : Boolean = True); constructor TJSONScanner.Create(Source : TStream; AUseUTF8 : Boolean = True);
Var Var
@ -144,7 +136,20 @@ begin
Create(Source,O); Create(Source,O);
end; end;
constructor TJSONScanner.Create(const Source : String; AUseUTF8 : Boolean = True); constructor TJSONScanner.Create(Source: TStream; AOptions: TJSONOptions);
Var
S : RawByteString;
begin
S:='';
SetLength(S,Source.Size);
if Length(S)>0 then
Source.ReadBuffer(S[1],Length(S));
Create(S,AOptions)
end;
constructor TJSONScanner.Create(const aSource : RawByteString; AUseUTF8 : Boolean = True);
Var Var
O : TJSONOptions; O : TJSONOptions;
@ -154,30 +159,15 @@ begin
Include(O,joUTF8) Include(O,joUTF8)
else else
Exclude(O,joUTF8); Exclude(O,joUTF8);
Create(Source,O); Create(aSource,O);
end; end;
constructor TJSONScanner.Create(Source: TStream; AOptions: TJSONOptions); constructor TJSONScanner.Create(const aSource: RawByteString; AOptions: TJSONOptions);
begin begin
FSource:=TStringList.Create; FSource:=aSource;
FSource.LoadFromStream(Source); FCurPos:=PAnsiChar(FSource);
FOptions:=AOptions; FOptions:=AOptions;
end; end;
{$endif}
constructor TJSONScanner.Create(const Source: String; AOptions: TJSONOptions);
begin
FSource:=TStringList.Create;
FSource.Text:=Source;
FOptions:=AOptions;
end;
destructor TJSONScanner.Destroy;
begin
FreeAndNil(FSource);
Inherited;
end;
function TJSONScanner.FetchToken: TJSONToken; function TJSONScanner.FetchToken: TJSONToken;
@ -190,8 +180,7 @@ begin
raise EScannerError.Create(Msg); raise EScannerError.Create(Msg);
end; end;
procedure TJSONScanner.Error(const Msg: string; procedure TJSONScanner.Error(const Msg: string; const Args: array of const);
const Args: array of {$ifdef pas2js}jsvalue{$else}const{$endif});
begin begin
raise EScannerError.CreateFmt(Msg, Args); raise EScannerError.CreateFmt(Msg, Args);
end; end;
@ -199,13 +188,31 @@ end;
function TJSONScanner.DoFetchToken: TJSONToken; function TJSONScanner.DoFetchToken: TJSONToken;
function FetchLine: Boolean; function FetchLine: Boolean;
var
PEOL : PAnsiChar;
Len : integer;
begin begin
Result:=FCurRow<FSource.Count; Result:=(FCurPos<>Nil) and (FCurPos^<>#0);
if Result then if Result then
begin begin
FCurLine:=FSource[FCurRow]; FTokenStr:=FCurPos;
FTokenStr:=PChar(FCurLine); While Not (FCurPos^ in [#0,#10,#13]) do
Inc(FCurRow); Inc(FCurPos);
PEOL:=FCurPos;
if (FCurPos^<>#0) then
begin
if (FCurPos^=#13) and (FCurPos[1]=#10) then
Inc(FCurPos); // Skip CR-LF
Inc(FCurPos); // To start of next line
Inc(FCurRow); // Increase line index
end;
Len:=PEOL-FTokenStr;
SetLength(FCurLine,Len);
if Len>0 then
Move(FTokenStr^,FCurLine[1],Len);
FTokenStr:=PAnsiChar(FCurLine);
end end
else else
begin begin
@ -226,7 +233,7 @@ var
Procedure MaybeAppendUnicode; Procedure MaybeAppendUnicode;
Var Var
u : String; u : UTF8String;
begin begin
// if there is a leftover \u, append // if there is a leftover \u, append