Data-Path-XS
view release on metacpan or search on metacpan
bench/benchmark.pl view on Meta::CPAN
#!/usr/bin/env perl
use strict;
use warnings;
use Benchmark qw(cmpthese timethese);
use FindBin;
use lib "$FindBin::Bin/../blib/lib", "$FindBin::Bin/../blib/arch";
use Data::Path::XS qw(path_get path_set path_exists path_delete
patha_get patha_set patha_exists patha_delete
path_compile pathc_get pathc_set pathc_exists pathc_delete);
use Data::Path::XS ':keywords';
use autovivification;
# Pure Perl implementation for comparison
sub pp_path_get {
my ($data, $path) = @_;
return $data if $path eq '';
die "Invalid path" unless $path =~ s{^/}{};
for my $p (split m{/}, $path, -1) {
return undef unless ref $data;
if (ref $data eq 'HASH') {
return undef unless exists $data->{$p};
$data = $data->{$p};
} elsif (ref $data eq 'ARRAY') {
return undef unless $p =~ /^\d+$/ && exists $data->[$p];
$data = $data->[$p];
} else {
return undef;
}
}
$data;
}
sub pp_path_exists {
my ($data, $path) = @_;
return 1 if $path eq '';
die "Invalid path" unless $path =~ s{^/}{};
for my $p (split m{/}, $path, -1) {
return 0 unless ref $data;
if (ref $data eq 'HASH') {
return 0 unless exists $data->{$p};
$data = $data->{$p};
} elsif (ref $data eq 'ARRAY') {
return 0 unless $p =~ /^\d+$/ && exists $data->[$p];
$data = $data->[$p];
} else {
return 0;
}
}
1;
}
sub pp_path_set {
my ($data, $path, $value) = @_;
die "Cannot set root" if $path eq '';
die "Invalid path" unless $path =~ s{^/}{};
my @parts = split m{/}, $path, -1;
my $last = pop @parts;
for my $p (@parts) {
if (ref $data eq 'HASH') {
$data->{$p} //= {};
$data = $data->{$p};
} elsif (ref $data eq 'ARRAY') {
$data->[$p] //= {};
$data = $data->[$p];
}
}
if (ref $data eq 'HASH') {
$data->{$last} = $value;
} elsif (ref $data eq 'ARRAY') {
$data->[$last] = $value;
}
$value;
}
# Test data
my $deep = {
level1 => {
level2 => {
level3 => {
level4 => {
level5 => { value => 'deep' }
}
}
}
},
arr => [0, [1, [2, [3, [4, 'nested']]]]],
};
my $shallow = { foo => 'bar', num => 42 };
print "=" x 70, "\n";
print "Data::Path::XS Benchmark (XS vs Pure Perl vs Native expressions)\n";
print "=" x 70, "\n\n";
print "--- Shallow get: /foo ---\n";
cmpthese(-2, {
'XS' => sub { path_get($shallow, '/foo') },
'Perl' => sub { pp_path_get($shallow, '/foo') },
'Native' => sub { no autovivification; $shallow->{foo} },
});
print "\n--- Deep get: /level1/level2/level3/level4/level5/value ---\n";
cmpthese(-2, {
'XS' => sub { path_get($deep, '/level1/level2/level3/level4/level5/value') },
'Perl' => sub { pp_path_get($deep, '/level1/level2/level3/level4/level5/value') },
'Native' => sub { no autovivification; $deep->{level1}{level2}{level3}{level4}{level5}{value} },
});
print "\n--- Array get: /arr/1/1/1/1/1 ---\n";
cmpthese(-2, {
'XS' => sub { path_get($deep, '/arr/1/1/1/1/1') },
'Perl' => sub { pp_path_get($deep, '/arr/1/1/1/1/1') },
'Native' => sub { no autovivification; $deep->{arr}[1][1][1][1][1] },
});
print "\n--- Deep get (missing key): /level1/level2/nope/x ---\n";
( run in 2.286 seconds using v1.01-cache-2.11-cpan-71847e10f99 )