#!/usr/bin/env perl package MyArray; use Tie::Array; use strict; use warnings; our @ISA = qw(Tie::StdArray); my %inside_out; sub FETCH { my ($self, $index) = @_; if (!defined($inside_out{"$self"}->{'cache'}->[$index])) { my $count = ++$inside_out{"$self"}->{'cache_miss_count'}; warn "FETCH (miss) $count: $index\n"; sleep 1; $inside_out{"$self"}->{'cache'}->[$index] = $self->[$index]; } else { my $count = ++$inside_out{"$self"}->{'cache_hit_count'}; warn "FETCH (hit) $count: $index\n"; } return $inside_out{"$self"}->{'cache'}->[$index]; } 1; package main; use strict; use warnings; use List::BinarySearch qw(binsearch); my ($min_sample_index, $max_sample_index) = sort {$a <=> $b} map {int(rand(100))} (0,1); # Generate two random indices in low to high order. my ($min_find_value, $max_find_value); tie my @array, 'MyArray'; my $curr_value = 0; foreach (1 .. 100) { $curr_value += int(rand(10)); push @array, $curr_value; $min_find_value = $curr_value if $_ == $min_sample_index; $max_find_value = $curr_value if $_ == $max_sample_index; } print "Looking for the range $min_find_value, $max_find_value in an array with ", scalar(@array), " elements\n"; my ($min_found_ix, $max_found_ix) = binsearch_range($min_find_value, $max_find_value, @array); print "Found indexes of $min_found_ix, $max_found_ix\n"; # This algorithm was taken from Mastering Algorithms with Perl, OReilly. sub binsearch_range { my $min = shift; my $max = shift; my $min_found_ix = binsearch {$a <=> $b} $min, @_; my $max_found_ix = binsearch {$a <=> $b} $max, @_; if ($max_found_ix == scalar(@array) || ($array[$max_found_ix] <=> $max_find_value) > 0) { $max_found_ix--; } return($min_found_ix, $max_found_ix); } #### Looking for the range 232, 339 in an array with 100 elements FETCH (miss) 1: 49 FETCH (miss) 2: 74 FETCH (miss) 3: 62 FETCH (miss) 4: 56 FETCH (miss) 5: 53 FETCH (miss) 6: 55 FETCH (miss) 7: 87 FETCH (miss) 8: 81 FETCH (miss) 9: 84 FETCH (miss) 10: 86 FETCH (miss) 11: 85 FETCH (hit) 1: 86 Found indexes of 56, 86 #### use List::BinarySearch qw(binsearch_range); foreach my $ix (0..99) { my @params = params($ix); push @array, MyClass->new(@params); } my ($low_ix, $high_ix) = binsearch_range { $a <=> $b->fetch } $min_wanted, $max_wanted, @array; #### package MyClass; sub new { my ($class, @parameters) = @_; return bless {params => \@parameters}, $class; } sub fetch { my $self = return $self->{'cache'} //= do { sleep 1; warn "cache miss. Generating value...\n"; _gen_value($self->{'params'}) #; Generate the expensive value and store it in the cache. }; }