Skip to content

Commit

Permalink
improved Mojo::DOM::CSS performance significantly
Browse files Browse the repository at this point in the history
  • Loading branch information
kraih committed Dec 2, 2014
1 parent 6e9228a commit 818bae8
Show file tree
Hide file tree
Showing 2 changed files with 25 additions and 32 deletions.
1 change: 1 addition & 0 deletions Changes
@@ -1,5 +1,6 @@

5.68 2014-12-02
- Improved Mojo::DOM::CSS performance significantly.
- Fixed deprecation warnings in get command.

5.67 2014-11-27
Expand Down
56 changes: 24 additions & 32 deletions lib/Mojo/DOM/CSS.pm
Expand Up @@ -32,10 +32,10 @@ sub select { _select(0, shift->tree, _compile(@_)) }
sub select_one { _select(1, shift->tree, _compile(@_)) }

sub _ancestor {
my ($selectors, $current, $tree) = @_;
my ($selectors, $current, $tree, $pos) = @_;
while ($current = $current->[3]) {
return undef if $current->[0] eq 'root' || $current eq $tree;
return 1 if _combinator($selectors, $current, $tree);
return 1 if _combinator($selectors, $current, $tree, $pos);
}
return undef;
}
Expand All @@ -55,28 +55,26 @@ sub _attr {
}

sub _combinator {
my ($selectors, $current, $tree) = @_;
my ($selectors, $current, $tree, $pos) = @_;

# Selector
my @s = @$selectors;
return undef unless my $combinator = shift @s;
if ($combinator->[0] ne 'combinator') {
return undef unless _selector($combinator, $current);
return 1 unless $combinator = shift @s;
return undef unless my $c = $selectors->[$pos];
if (ref $c) {
return undef unless _selector($c, $current);
return 1 unless $c = $selectors->[++$pos];
}

# ">" (parent only)
my $c = $combinator->[1];
return _parent(\@s, $current, $tree) ? 1 : undef if $c eq '>';
return _parent($selectors, $current, $tree, ++$pos) if $c eq '>';

# "~" (preceding siblings)
return _sibling(\@s, $current, $tree, 0) ? 1 : undef if $c eq '~';
return _sibling($selectors, $current, $tree, 0, ++$pos) if $c eq '~';

# "+" (immediately preceding siblings)
return _sibling(\@s, $current, $tree, 1) ? 1 : undef if $c eq '+';
return _sibling($selectors, $current, $tree, 1, ++$pos) if $c eq '+';

# " " (ancestor)
return _ancestor(\@s, $current, $tree) ? 1 : undef;
return _ancestor($selectors, $current, $tree, ++$pos);
}

sub _compile {
Expand All @@ -94,15 +92,12 @@ sub _compile {
my $part = $pattern->[-1];

# Empty combinator
push @$part, [combinator => ' ']
if $part->[-1] && $part->[-1][0] ne 'combinator';
push @$part, ' ' if $part->[-1] && ref $part->[-1];

# Tag
push @$part, ['element'];
my $selector = $part->[-1];
my $tag = '*';
$element =~ s/^((?:\\\.|\\\#|[^.#])+)// and $tag = _unescape($1);
push @$selector, ['tag', $tag];
push @$part, my $selector = [];
push @$selector, ['tag', qr/(?:^|:)\Q@{[_unescape($1)]}\E$/]
if $element =~ s/^((?:\\\.|\\\#|[^.#])+)// && $1 ne '*';

# Class or ID
while ($element =~ /(?:([.#])((?:\\[.\#]|[^\#.])+))/g) {
Expand All @@ -119,7 +114,7 @@ sub _compile {
while $attrs =~ /$ATTR_RE/go;

# Combinator
push @$part, [combinator => $combinator] if $combinator;
push @$part, $combinator if $combinator;
}

return $pattern;
Expand Down Expand Up @@ -148,15 +143,15 @@ sub _equation {

sub _match {
my ($pattern, $current, $tree) = @_;
_combinator([reverse @$_], $current, $tree) and return 1 for @$pattern;
_combinator([reverse @$_], $current, $tree, 0) and return 1 for @$pattern;
return undef;
}

sub _parent {
my ($selectors, $current, $tree) = @_;
my ($selectors, $current, $tree, $pos) = @_;
return undef unless my $parent = $current->[3];
return undef if $parent->[0] eq 'root';
return _combinator($selectors, $parent, $tree);
return _combinator($selectors, $parent, $tree, $pos);
}

sub _pc {
Expand Down Expand Up @@ -245,14 +240,11 @@ sub _select {
sub _selector {
my ($selector, $current) = @_;

for my $s (@$selector[1 .. $#$selector]) {
for my $s (@$selector) {
my $type = $s->[0];

# Tag (ignore namespace prefix)
if ($type eq 'tag') {
my $tag = $s->[1];
return undef unless $tag eq '*' || $current->[1] =~ /(?:^|:)\Q$tag\E$/;
}
if ($type eq 'tag') { return undef unless $current->[1] =~ $s->[1] }

# Attribute
elsif ($type eq 'attr') { return undef unless _attr(@$s[1, 2], $current) }
Expand All @@ -267,17 +259,17 @@ sub _selector {
}

sub _sibling {
my ($selectors, $current, $tree, $immediate) = @_;
my ($selectors, $current, $tree, $immediate, $pos) = @_;

my $found;
for my $sibling (@{_siblings($current)}) {
return $found if $sibling eq $current;

# "+" (immediately preceding sibling)
if ($immediate) { $found = _combinator($selectors, $sibling, $tree) }
if ($immediate) { $found = _combinator($selectors, $sibling, $tree, $pos) }

# "~" (preceding sibling)
else { return 1 if _combinator($selectors, $sibling, $tree) }
else { return 1 if _combinator($selectors, $sibling, $tree, $pos) }
}

return undef;
Expand Down

0 comments on commit 818bae8

Please sign in to comment.