mirror of
https://gitlab.com/freepascal.org/fpc/source.git
synced 2025-04-22 00:09:25 +02:00
XPath: reducing memory load:
* Store predicates of TStep and TXPathFilterNode in dynarrays instead of TList, this way we allocate only as much memory as needed, and allocate anything only when predicates are actually present (that's minority of all cases). * Eliminated intermediate TList in filtering step results. * Remaining TList's replaced by TFPList's. * Fixed ordering of nodes on preceding-sibling axis. git-svn-id: trunk@13230 -
This commit is contained in:
parent
3327371e24
commit
e66e35ac2c
@ -107,6 +107,7 @@ type
|
||||
AEnvironment: TXPathEnvironment): TXPathVariable; virtual; abstract;
|
||||
end;
|
||||
|
||||
TXPathNodeArray = array of TXPathExprNode;
|
||||
|
||||
TXPathConstantNode = class(TXPathExprNode)
|
||||
private
|
||||
@ -132,7 +133,7 @@ type
|
||||
TXPathFunctionNode = class(TXPathExprNode)
|
||||
private
|
||||
FName: DOMString;
|
||||
FArgs: TList;
|
||||
FArgs: TFPList;
|
||||
public
|
||||
constructor Create(const AName: DOMString);
|
||||
destructor Destroy; override;
|
||||
@ -220,7 +221,7 @@ type
|
||||
TXPathFilterNode = class(TXPathExprNode)
|
||||
private
|
||||
FExpr: TXPathExprNode;
|
||||
FPredicates: TList;
|
||||
FPredicates: TXPathNodeArray;
|
||||
public
|
||||
constructor Create(AExpr: TXPathExprNode);
|
||||
destructor Destroy; override;
|
||||
@ -245,7 +246,7 @@ type
|
||||
Axis: TAxis;
|
||||
NodeTestType: TNodeTestType;
|
||||
NodeTestString: DOMString;
|
||||
Predicates: TList;
|
||||
Predicates: TXPathNodeArray;
|
||||
constructor Create(aAxis: TAxis; aTest: TNodeTestType);
|
||||
destructor Destroy; override;
|
||||
end;
|
||||
@ -263,7 +264,7 @@ type
|
||||
end;
|
||||
|
||||
|
||||
TNodeSet = TList;
|
||||
TNodeSet = TFPList;
|
||||
|
||||
{ Exceptions }
|
||||
|
||||
@ -351,6 +352,7 @@ type
|
||||
FTokenStart: DOMPChar;
|
||||
FTokenLength: Integer;
|
||||
procedure Error(const Msg: String);
|
||||
procedure ParsePredicates(var Dest: TXPathNodeArray);
|
||||
procedure ParseStep(Dest: TStep); // [4]
|
||||
function ParsePrimaryExpr: TXPathExprNode; // [15]
|
||||
function ParseUnionExpr: TXPathExprNode; // [18]
|
||||
@ -389,15 +391,15 @@ type
|
||||
the variables and functions, which are part of the context in the official
|
||||
standard). }
|
||||
|
||||
TXPathVarList = TList;
|
||||
TXPathVarList = TFPList;
|
||||
|
||||
TXPathFunction = function(Context: TXPathContext; Args: TXPathVarList):
|
||||
TXPathVariable of object;
|
||||
|
||||
TXPathEnvironment = class
|
||||
private
|
||||
FFunctions: TList;
|
||||
FVariables: TList;
|
||||
FFunctions: TFPList;
|
||||
FVariables: TFPList;
|
||||
function GetFunctionCount: Integer;
|
||||
function GetVariableCount: Integer;
|
||||
function GetFunction(Index: Integer): TXPathFunction;
|
||||
@ -583,6 +585,15 @@ begin
|
||||
end;
|
||||
end;
|
||||
|
||||
procedure AddNodes(var Dst: TXPathNodeArray; const Src: array of TXPathExprNode);
|
||||
var
|
||||
L: Integer;
|
||||
begin
|
||||
L := Length(Dst);
|
||||
SetLength(Dst, L + High(Src)+1);
|
||||
Move(Src[0], Dst[L], (High(Src)+1)*sizeof(TObject));
|
||||
end;
|
||||
|
||||
{ XPath parse tree classes }
|
||||
|
||||
function TXPathExprNode.EvalPredicate(AContext: TXPathContext;
|
||||
@ -640,7 +651,7 @@ constructor TXPathFunctionNode.Create(const AName: DOMString);
|
||||
begin
|
||||
inherited Create;
|
||||
FName := AName;
|
||||
FArgs := TList.Create;
|
||||
FArgs := TFPList.Create;
|
||||
end;
|
||||
|
||||
destructor TXPathFunctionNode.Destroy;
|
||||
@ -984,16 +995,14 @@ constructor TXPathFilterNode.Create(AExpr: TXPathExprNode);
|
||||
begin
|
||||
inherited Create;
|
||||
FExpr := AExpr;
|
||||
FPredicates := TList.Create;
|
||||
end;
|
||||
|
||||
destructor TXPathFilterNode.Destroy;
|
||||
var
|
||||
i: Integer;
|
||||
begin
|
||||
for i := 0 to FPredicates.Count - 1 do
|
||||
TXPathExprNode(FPredicates[i]).Free;
|
||||
FPredicates.Free;
|
||||
for i := 0 to High(FPredicates) do
|
||||
FPredicates[i].Free;
|
||||
inherited Destroy;
|
||||
end;
|
||||
|
||||
@ -1020,9 +1029,9 @@ begin
|
||||
NewContext.ContextNode := CurContextNode;
|
||||
Inc(NewContext.ContextPosition);
|
||||
DoAdd := True;
|
||||
for j := 0 to FPredicates.Count - 1 do
|
||||
for j := 0 to High(FPredicates) do
|
||||
begin
|
||||
DoAdd := TXPathExprNode(FPredicates[j]).EvalPredicate(NewContext,
|
||||
DoAdd := FPredicates[j].EvalPredicate(NewContext,
|
||||
AEnvironment);
|
||||
if not DoAdd then
|
||||
Break;
|
||||
@ -1047,16 +1056,14 @@ begin
|
||||
inherited Create;
|
||||
Axis := aAxis;
|
||||
NodeTestType := aTest;
|
||||
Predicates := TList.Create;
|
||||
end;
|
||||
|
||||
destructor TStep.Destroy;
|
||||
var
|
||||
i: Integer;
|
||||
begin
|
||||
for i := 0 to Predicates.Count - 1 do
|
||||
TXPathExprNode(Predicates[i]).Free;
|
||||
Predicates.Free;
|
||||
for i := 0 to High(Predicates) do
|
||||
Predicates[i].Free;
|
||||
inherited destroy;
|
||||
end;
|
||||
|
||||
@ -1074,7 +1081,7 @@ var
|
||||
|
||||
procedure EvaluateStep(AStep: TStep; AContext: TXPathContext);
|
||||
var
|
||||
StepNodes: TList;
|
||||
StepNodes: TFPList;
|
||||
|
||||
procedure DoNodeTest(Node: TDOMNode);
|
||||
begin
|
||||
@ -1120,12 +1127,11 @@ var
|
||||
i, j: Integer;
|
||||
|
||||
NewContext: TXPathContext;
|
||||
NewStepNodes: TNodeSet;
|
||||
Predicate: TXPathExprNode;
|
||||
TempList: TList;
|
||||
TempList: TFPList;
|
||||
|
||||
begin
|
||||
StepNodes := TList.Create;
|
||||
StepNodes := TFPList.Create;
|
||||
// !!!: Protect this with an try/finally block
|
||||
case AStep.Axis of
|
||||
axisAncestor:
|
||||
@ -1197,7 +1203,7 @@ var
|
||||
DoNodeTest(AContext.ContextNode);
|
||||
axisPreceding:
|
||||
begin
|
||||
TempList := TList.Create;
|
||||
TempList := TFPList.Create;
|
||||
try
|
||||
Node := AContext.ContextNode;
|
||||
// build list of ancestors
|
||||
@ -1224,11 +1230,14 @@ var
|
||||
end;
|
||||
axisPrecedingSibling:
|
||||
begin
|
||||
Node := AContext.ContextNode.PreviousSibling;
|
||||
while Assigned(Node) do
|
||||
if Assigned(AContext.ContextNode.ParentNode) then
|
||||
begin
|
||||
DoNodeTest(Node);
|
||||
Node := Node.PreviousSibling;
|
||||
Node := AContext.ContextNode.ParentNode.FirstChild;
|
||||
while Assigned(Node) and (Node <> AContext.ContextNode) do
|
||||
begin
|
||||
DoNodeTest(Node);
|
||||
Node := Node.NextSibling;
|
||||
end;
|
||||
end;
|
||||
end;
|
||||
axisSelf:
|
||||
@ -1236,19 +1245,17 @@ var
|
||||
end;
|
||||
|
||||
{ Filter the nodes of this step using the predicates: The current
|
||||
node set (StepNodes) is filtered, all passed nodes will be added
|
||||
to NewStepNodes. After one filter has been applied, NewStepNodes
|
||||
gets copied to StepNodes, and the next filter will be processed.
|
||||
node set (StepNodes) is filtered, nodes not passing the filter
|
||||
are replaced by nil. After one filter has been applied, StepNodes
|
||||
is packed, and the next filter will be processed.
|
||||
The final result will then be passed to the next step, or added
|
||||
to the result of the LocationPath if this is the last step. }
|
||||
|
||||
for i := 0 to AStep.Predicates.Count - 1 do
|
||||
for i := 0 to High(AStep.Predicates) do
|
||||
begin
|
||||
NewContext := TXPathContext.Create(nil, 0, StepNodes.Count);
|
||||
NewStepNodes := nil;
|
||||
try
|
||||
NewStepNodes := TNodeSet.Create;
|
||||
Predicate := TXPathExprNode(AStep.Predicates[i]);
|
||||
Predicate := AStep.Predicates[i];
|
||||
for j := 0 to StepNodes.Count - 1 do
|
||||
begin
|
||||
// ContextPosition must honor the axis direction
|
||||
@ -1260,13 +1267,12 @@ var
|
||||
|
||||
Node := TDOMNode(StepNodes[j]);
|
||||
NewContext.ContextNode := Node;
|
||||
if Predicate.EvalPredicate(NewContext, AEnvironment) then
|
||||
NewStepNodes.Add(Node);
|
||||
if not Predicate.EvalPredicate(NewContext, AEnvironment) then
|
||||
StepNodes[j] := nil;
|
||||
end;
|
||||
StepNodes.Pack;
|
||||
finally
|
||||
NewContext.Free;
|
||||
StepNodes.Free;
|
||||
StepNodes := NewStepNodes;
|
||||
end;
|
||||
end;
|
||||
|
||||
@ -1706,6 +1712,32 @@ begin
|
||||
raise Exception.Create(Msg) at get_caller_addr(get_frame);
|
||||
end;
|
||||
|
||||
procedure TXPathScanner.ParsePredicates(var Dest: TXPathNodeArray);
|
||||
var
|
||||
Buffer: array[0..15] of TXPathExprNode;
|
||||
I: Integer;
|
||||
begin
|
||||
I := 0;
|
||||
// accumulate nodes in local buffer, then add all at once
|
||||
// this reduces amount of ReallocMem's
|
||||
while CurToken = tkLeftSquareBracket do
|
||||
begin
|
||||
NextToken;
|
||||
Buffer[I] := ParseOrExpr;
|
||||
Inc(I);
|
||||
if I > High(Buffer) then
|
||||
begin
|
||||
AddNodes(Dest, Buffer);
|
||||
I := 0;
|
||||
end;
|
||||
if CurToken <> tkRightSquareBracket then
|
||||
Error(SParserExpectedRightSquareBracket);
|
||||
NextToken;
|
||||
end;
|
||||
if I > 0 then
|
||||
AddNodes(Dest, Slice(Buffer, I));
|
||||
end;
|
||||
|
||||
procedure TXPathScanner.ParseStep(Dest: TStep); // [4]
|
||||
|
||||
procedure NeedBrackets;
|
||||
@ -1837,16 +1869,7 @@ begin
|
||||
end
|
||||
else
|
||||
Exit;
|
||||
|
||||
// Parse predicates
|
||||
while CurToken = tkLeftSquareBracket do
|
||||
begin
|
||||
NextToken;
|
||||
Dest.Predicates.Add(ParseOrExpr);
|
||||
if CurToken <> tkRightSquareBracket then
|
||||
Error(SParserExpectedRightSquareBracket);
|
||||
NextToken;
|
||||
end;
|
||||
ParsePredicates(Dest.Predicates);
|
||||
end;
|
||||
end;
|
||||
|
||||
@ -1986,24 +2009,13 @@ begin
|
||||
end;
|
||||
|
||||
function TXPathScanner.ParseFilterExpr: TXPathExprNode; // [20]
|
||||
var
|
||||
IsFirst: Boolean;
|
||||
begin
|
||||
Result := ParsePrimaryExpr;
|
||||
// Parse predicates
|
||||
IsFirst := True;
|
||||
while CurToken = tkLeftSquareBracket do
|
||||
if CurToken = tkLeftSquareBracket then
|
||||
begin
|
||||
NextToken;
|
||||
if IsFirst then
|
||||
begin
|
||||
Result := TXPathFilterNode.Create(Result);
|
||||
IsFirst := False;
|
||||
end;
|
||||
TXPathFilterNode(Result).FPredicates.Add(ParseOrExpr);
|
||||
if CurToken <> tkRightSquareBracket then
|
||||
Error(SParserExpectedRightSquareBracket);
|
||||
NextToken;
|
||||
Result := TXPathFilterNode.Create(Result);
|
||||
ParsePredicates(TXPathFilterNode(Result).FPredicates);
|
||||
end;
|
||||
end;
|
||||
|
||||
@ -2151,8 +2163,8 @@ type
|
||||
constructor TXPathEnvironment.Create;
|
||||
begin
|
||||
inherited Create;
|
||||
FFunctions := TList.Create;
|
||||
FVariables := TList.Create;
|
||||
FFunctions := TFPList.Create;
|
||||
FVariables := TFPList.Create;
|
||||
|
||||
// Add the functions of the XPath Core Function Library
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user