use 5.12.0; use strict; use warnings; use Data::Dump qw/pp dd/; use Benchmark qw/cmpthese/; # --------- fetch all defined generators my %generators; for my $generator ( grep {/^gen_/} keys %Generators::) { my $g_generator = $Generators::{$generator}; $generators{$generator} = $g_generator; } #warn pp \%generators; # --------- init test data my %hash; my @entries = 0..1e3; @hash{@entries} = reverse @entries; my %copy = %hash; # --------- run tests while( my ($gen,$glob) = each %generators ) { say "\n*** Testing $gen"; Tests::all( "$gen", $glob->(\%hash), \%copy ); } Test::More::done_testing(); # --------- run benchmarks # --- expand test data @entries = 0..1e6; @hash{@entries} = reverse @entries; # --- init iterators my %iterators; while ( my ($gen,$glob) = each %generators ) { (my $name = $gen) =~ s/^gen_//; $iterators{$name} = $glob->(\%hash); } #warn pp \%iterators; # --- benchmark cmpthese(-1, \%iterators ); package Generators; sub gen_copy_keys { my ($h_hash) = @_; my $idx = 0; my @keys = keys %$h_hash; return sub { # --- reset? if ($idx >= @keys) { $idx = 0; return; } # --- return key, value my $key = $keys[$idx++]; return $key, $h_hash->{$key}; } } sub gen_copy_hash_and_each { my ($h_hash) = @_; my %copy = %$h_hash; return sub { # --- return key, value return each %copy } } sub gen_each { my ($h_hash) = @_; return sub { # --- return key, value return each %$h_hash; } } sub gen_idx_keys { my ($h_hash) = @_; my $idx = 0; return sub { if ($idx >= keys %$h_hash) { $idx = 0; return; } # --- return key, value my $key = (keys %$h_hash)[$idx++]; return $key, $h_hash->{$key}; } } package Tests; use Test::More; sub all { my ( $name, $c_iter, $h_expected ) = @_; # --- gathers all entries my %got = (); while ( my ($k,$v) = &$c_iter ) { $got{$k} = $v; } is_deeply(\%got, $h_expected, "'$name' iterates over all entries"); # --- cycles to restart %got = (); while ( my ($k,$v) = &$c_iter ) { $got{$k} = $v; } is_deeply(\%got, $h_expected, "'$name' cycles and iterates again"); }