Using magic hash key transformation

Since version 5.10, perl has the ability to magically transform keys on a hash. This feature was added to make fieldhashes possible, but has more uses. Here I'll show you how to do in using Class::Private as an example.

Loading the XS

package Class::Private;

use 5.010;
use strict;
use warnings;
use XSLoader;

our $VERSION = '0.05';

XSLoader::load('Class::Private', $VERSION);

1;

As you can see, there's not much to the Perl part of this module, it loads some pragma's (the 5.010 is important because this feature will not work on older versions) and then loads the XS.

Casting the magic

SV* new(class) SV* class; CODE: HV* hash = newHV(); sv_magic((SV*)hash, NULL, PERL_MAGIC_uvar, (const char*)&hash_filter, sizeof hash_filter); RETVAL = sv_bless(newRV_noinc((SV*)hash), gv_stashsv(class, GV_ADD)); OUTPUT: RETVAL

The new is slightly more complicated. It creates a hash, adds the magic to id, and then returns a blessed reference to it. hash_filter is an argument in the magic casting describes how the transformation should happen. It specifies the function to call on hash access, it's defined like this:

static const struct ufuncs hash_filter = { hash_name_filter, NULL, 0 };

Implementing the magic

hash_name_filter is the real meat of the module. It defines the transformation.

I32 hash_name_filter(pTHX_ IV action, SV* val) {
MAGIC* magic = mg_find(val, PERL_MAGIC_uvar);
if (strstr(SvPV_nolen(magic->mg_obj), "::") == NULL)
magic->mg_obj = sv_2mortal(newSVpvf("%s::%s", CopSTASHPV(PL_curcop), SvPV_nolen(magic->mg_obj)));
return 0;
}

On the first line it retrieves the magic handle. Its member mg_obj is where the key is stored. If you want to modify it, you will have to create a new SV with a different value and assign it to mg_obj. Note that there is no easy way to transmit arguments to the functions (though you could use the IV member in struct ufuncs), I consider this an unfortunate design flaw.

3 Comments

So...what does this actually do?

Looks really interesting if I could understand it ;)

Leave a comment

About Leon Timmermans

user-pic