Subject: | [patch] add indices to speed up find_input on large forms |
The attached patch implements a set of indices (on input name, id, and
class) to significantly speed up the find_input call for large forms.
It also adds a test for a previously-untested case: that when changing
the name of an input, the input is findable through the new name.
Subject: | html-form-indexed.patch |
diff --git a/lib/HTML/Form.pm b/lib/HTML/Form.pm
index bbbd777..38330fe 100644
--- a/lib/HTML/Form.pm
+++ b/lib/HTML/Form.pm
@@ -482,11 +482,19 @@ input with the given name and/or type.
sub find_input
{
my($self, $name, $type, $no) = @_;
+ my $inputs;
+ if (defined $name) {
+ $name="^$name" unless $name=~m{^[#.^]};
+ $inputs=$self->{'inputs-by-key'}{$name};
+ }
+ else {
+ $inputs=$self->{inputs};
+ }
if (wantarray) {
my @res;
my $c;
- for (@{$self->{'inputs'}}) {
- next if defined($name) && !$_->selected($name);
+ for (@$inputs) {
+ #next if defined($name) && !$_->selected($name);
next if $type && $type ne $_->{type};
$c++;
next if $no && $no != $c;
@@ -497,8 +505,8 @@ sub find_input
}
else {
$no ||= 1;
- for (@{$self->{'inputs'}}) {
- next if defined($name) && !$_->selected($name);
+ for (@$inputs) {
+ #next if defined($name) && !$_->selected($name);
next if $type && $type ne $_->{type};
next if --$no;
return $_;
@@ -862,9 +870,27 @@ sub add_to_form
{
my($self, $form) = @_;
push(@{$form->{'inputs'}}, $self);
+ $self->{form}=$form;
+ $self->_add_to_form_by_key($form,'^',$self->name);
+ $self->_add_to_form_by_key($form,'#',$self->id);
+ $self->_add_to_form_by_key($form,'.',$self->class);
$self;
}
+sub _add_to_form_by_key {
+ my ($self,$form,$prefix,$key)=@_;
+ return unless defined $key;
+ push(@{$form->{'inputs-by-key'}{$prefix.$key}},$self);
+}
+
+sub _del_from_form_by_key {
+ my ($self,$form,$prefix,$key)=@_;
+ return unless defined $key;
+
+ @{$form->{'inputs-by-key'}{$prefix.$key}}=
+ grep {$_ ne $self} @{$form->{'inputs-by-key'}{$prefix.$key}};
+}
+
sub strict {
my $self = shift;
my $old = $self->{strict};
@@ -927,7 +953,11 @@ sub name
{
my $self = shift;
my $old = $self->{name};
- $self->{name} = shift if @_;
+ if (@_) {
+ $self->_del_from_form_by_key($self->{form},'^',$old);
+ $self->{name}=shift;
+ $self->_add_to_form_by_key($self->{form},'^',$self->{name});
+ }
$old;
}
@@ -935,7 +965,11 @@ sub id
{
my $self = shift;
my $old = $self->{id};
- $self->{id} = shift if @_;
+ if (@_) {
+ $self->_del_from_form_by_key($self->{form},'#',$old);
+ $self->{id}=shift;
+ $self->_add_to_form_by_key($self->{form},'#',$self->{id});
+ }
$old;
}
@@ -943,7 +977,11 @@ sub class
{
my $self = shift;
my $old = $self->{class};
- $self->{class} = shift if @_;
+ if (@_) {
+ $self->_del_from_form_by_key($self->{form},'.',$old);
+ $self->{class}=shift;
+ $self->_add_to_form_by_key($self->{form},'.',$self->{class});
+ }
$old;
}
diff --git a/t/html/form-selector.t b/t/html/form-selector.t
index 9cba445..5cdcec4 100755
--- a/t/html/form-selector.t
+++ b/t/html/form-selector.t
@@ -3,7 +3,7 @@
use strict;
use Test qw(plan ok);
-plan tests => 12;
+plan tests => 13;
use HTML::Form;
@@ -35,6 +35,7 @@ ok(j(map $_->value, $form->find_input(".A")), "1:2");
$form->find_input("#id2")->name("n2");
$form->value("#id2", 22);
ok($form->click->uri->query, "n1=1&n2=22");
+ok($form->value('n2'),22);
# try some odd names
ok($form->find_input("##foo")->name, "#bar");