use blib; use Hash::Bidirectional; use Benchmark qw(cmpthese); use Devel::Size qw(total_size); use strict; use warnings; my $hn = {}; my $hb = bless {}, 'Hash::Bidirectional'; my $i = 0; for ( 'aaaaz' .. 'zzzzz') { $i++; $hn->{$_} = $i; # - normal hash $hn->{$i} = $_; # / $hb->pair($_,$i); # - bidirectional hash } print "size normal hash: ", total_size($hn),"\n"; print "size bi_dir hash: ", total_size($hb),"\n"; cmpthese( 10000000, { normal => sub { $hn->{$hn->{shmem}} }, bi_dir => sub { $hb->get($hb->get('shmem')) }, }); __END__ size normal hash: 3025679168 size bi_dir hash: 2360323536 Rate bi_dir normal bi_dir 2801120/s -- -62% normal 7407407/s 164% -- #### #include "EXTERN.h" #include "perl.h" #include "XSUB.h" #include "perlapi.h" #include "ppport.h" HE * get_entry(HE * he, U32 hash) { HE *entry = he; for(; entry; entry = HeNEXT(entry)) { if (HeHASH(entry) != hash){ continue; } } if (!entry) entry = he; return entry; } MODULE = Hash::Bidirectional PACKAGE = Hash::Bidirectional char * pair(HV *hv, char *key, SV *value) CODE: SV **key_ptr; SV **value_ptr; char *v = SvPVbyte_nolen(value); U32 hash = 0; HE *ventry; HE *kentry; SV *ksv; SV *vsv; /* store key as key */ PERL_HASH(hash, key, strlen(key)); ksv = newSViv((IV) &key); key_ptr = hv_store(hv, key, strlen(key), ksv, hash); kentry = get_entry((HvARRAY(hv))[hash & (I32) HvMAX(hv)],hash); /* store value as key */ hash = 0; PERL_HASH(hash, v, strlen(v)); vsv = newSViv((IV) &v); value_ptr = hv_store(hv, v, strlen(v), vsv, hash); ventry = get_entry((HvARRAY(hv))[hash & (I32) HvMAX(hv)],hash); /* set pointers of each */ sv_setiv(ksv,(IV)HeKEY(ventry)); sv_setiv(vsv,(IV)HeKEY(kentry)); RETVAL = v; OUTPUT: RETVAL char * get(HV *hv, char *key) CODE: HE *entry; U32 hash; PERL_HASH(hash, key, strlen(key)); entry = get_entry((HvARRAY(hv))[hash & (I32) HvMAX(hv)],hash); RETVAL= (char*) SvIVX(HeVAL(entry)); OUTPUT: RETVAL